summaryrefslogtreecommitdiffstats
path: root/vm/interp/Stack.h
blob: 99bef1acdc6bad58f58fd2c7b74ae2ad2cefda5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Stack frames, and uses thereof.
 */
#ifndef _DALVIK_INTERP_STACK
#define _DALVIK_INTERP_STACK

#include "jni.h"
#include <stdarg.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
Stack layout

In what follows, the "top" of the stack is at a low position in memory,
and the "bottom" of the stack is in a high position (put more simply,
they grow downward).  They may be merged with the native stack at a
later date.  The interpreter assumes that they have a fixed size,
determined when the thread is created.

Dalvik's registers (of which there can be up to 64K) map to the "ins"
(method arguments) and "locals" (local variables).  The "outs" (arguments
to called methods) are specified by the "invoke" operand.  The return
value, which is passed through the interpreter rather than on the stack,
is retrieved with a "move-result" instruction.

    Low addresses (0x00000000)

                     +- - - - - - - - -+
                     -  out0           -
                     +-----------------+  <-- stack ptr (top of stack)
                     +  VM-specific    +
                     +  internal goop  +
                     +-----------------+  <-- curFrame: FP for cur function
                     +  v0 == local0   +
+-----------------+  +-----------------+
+  out0           +  +  v1 == in0      +
+-----------------+  +-----------------+
+  out1           +  +  v2 == in1      +
+-----------------+  +-----------------+
+  VM-specific    +
+  internal goop  +
+-----------------+  <-- frame ptr (FP) for previous function
+  v0 == local0   +
+-----------------+
+  v1 == local1   +
+-----------------+
+  v2 == in0      +
+-----------------+
+  v3 == in1      +
+-----------------+
+  v4 == in2      +
+-----------------+
-                 -
-                 -
-                 -
+-----------------+  <-- interpStackStart

    High addresses (0xffffffff)

Note the "ins" and "outs" overlap -- values pushed into the "outs" area
become the parameters to the called method.  The VM guarantees that there
will be enough room for all possible "outs" on the stack before calling
into a method.

All "V registers" are 32 bits, and all stack entries are 32-bit aligned.
Registers are accessed as a positive offset from the frame pointer,
e.g. register v2 is fp[2].  64-bit quantities are stored in two adjacent
registers, addressed by the lower-numbered register, and are in host order.
64-bit quantities do not need to start in an even-numbered register.

We push two stack frames on when calling an interpreted or native method
directly from the VM (e.g. invoking <clinit> or via reflection "invoke()").
The first is a "break" frame, which allows us to tell when a call return or
exception unroll has reached the VM call site.  Without the break frame the
stack might look like an uninterrupted series of interpreted method calls.
The second frame is for the method itself.

The "break" frame is used as an alternative to adding additional fields
to the StackSaveArea struct itself.  They are recognized by having a
NULL method pointer.

When calling a native method from interpreted code, the stack setup is
essentially identical to calling an interpreted method.  Because it's a
native method, though, there are never any "locals" or "outs".

For native calls into JNI, we want to store a table of local references
on the stack.  The GC needs to scan them while the native code is running,
and we want to trivially discard them when the method returns.  See JNI.c
for a discussion of how this is managed.  In particular note that it is
possible to push additional call frames on without calling a method.
*/


struct StackSaveArea;
typedef struct StackSaveArea StackSaveArea;

//#define PAD_SAVE_AREA       /* help debug stack trampling */

/*
 * The VM-specific internal goop.
 *
 * The idea is to mimic a typical native stack frame, with copies of the
 * saved PC and FP.  At some point we'd like to have interpreted and
 * native code share the same stack, though this makes portability harder.
 */
struct StackSaveArea {
#ifdef PAD_SAVE_AREA
    u4          pad0, pad1, pad2;
#endif

#ifdef EASY_GDB
    /* make it easier to trek through stack frames in GDB */
    StackSaveArea* prevSave;
#endif

    /* saved frame pointer for previous frame, or NULL if this is at bottom */
    void*       prevFrame;

    /* saved program counter (from method in caller's frame) */
    const u2*   savedPc;

    /* pointer to method we're *currently* executing; handy for exceptions */
    const Method* method;

    union {
        /* for JNI native methods: bottom of local reference segment */
        u4          localRefCookie;

        /* for interpreted methods: saved current PC, for exception stack
         * traces and debugger traces */
        const u2*   currentPc;
    } xtra;

    /* Native return pointer for JIT, or 0 if interpreted */
    const u2* returnAddr;
#ifdef PAD_SAVE_AREA
    u4          pad3, pad4, pad5;
#endif
};

/* move between the stack save area and the frame pointer */
#define SAVEAREA_FROM_FP(_fp)   ((StackSaveArea*)(_fp) -1)
#define FP_FROM_SAVEAREA(_save) ((void*) ((StackSaveArea*)(_save) +1))

/* when calling a function, get a pointer to outs[0] */
#define OUTS_FROM_FP(_fp, _argCount) \
    ((u4*) ((u1*)SAVEAREA_FROM_FP(_fp) - sizeof(u4) * (_argCount)))

/* reserve this many bytes for handling StackOverflowError */
#define STACK_OVERFLOW_RESERVE  768

/*
 * Determine if the frame pointer points to a "break frame".
 */
INLINE bool dvmIsBreakFrame(const u4* fp)
{
    return SAVEAREA_FROM_FP(fp)->method == NULL;
}

/*
 * Initialize the interp stack (call this after allocating storage and
 * setting thread->interpStackStart).
 */
bool dvmInitInterpStack(Thread* thread, int stackSize);

/*
 * Push a native method frame directly onto the stack.  Used to push the
 * "fake" native frames at the top of each thread stack.
 */
bool dvmPushJNIFrame(Thread* thread, const Method* method);

/*
 * JNI local frame management.
 */
bool dvmPushLocalFrame(Thread* thread, const Method* method);
bool dvmPopLocalFrame(Thread* thread);

/*
 * Call an interpreted method from native code.  If this is being called
 * from a JNI function, references in the argument list will be converted
 * back to pointers.
 *
 * "obj" should be NULL for "direct" methods.
 */
void dvmCallMethod(Thread* self, const Method* method, Object* obj,
    JValue* pResult, ...);
void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, va_list args);
void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
    bool fromJni, JValue* pResult, const jvalue* args);

/*
 * Invoke a method, using the specified arguments and return type, through
 * a reflection interface.
 *
 * Deals with boxing/unboxing primitives and performs widening conversions.
 *
 * "obj" should be null for a static method.
 *
 * "params" and "returnType" come from the Method object, so we don't have
 * to re-generate them from the method signature.  "returnType" should be
 * NULL if we're invoking a constructor.
 */
Object* dvmInvokeMethod(Object* invokeObj, const Method* meth,
    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    bool noAccessCheck);

/*
 * Determine the source file line number, given the program counter offset
 * into the specified method.  Returns -2 for native methods, -1 if no
 * match was found.
 */
int dvmLineNumFromPC(const Method* method, u4 relPc);

/*
 * Given a frame pointer, compute the current call depth.  The value can be
 * "exact" (a count of non-break frames) or "vague" (just subtracting
 * pointers to give relative values).
 */
int dvmComputeExactFrameDepth(const void* fp);
int dvmComputeVagueFrameDepth(Thread* thread, const void* fp);

/*
 * Get the frame pointer for the caller's stack frame.
 */
void* dvmGetCallerFP(const void* curFrame);

/*
 * Get the class of the method that called us.
 */
ClassObject* dvmGetCallerClass(const void* curFrame);

/*
 * Get the caller's caller's class.  Pass in the current fp.
 *
 * This is used by e.g. java.lang.Class, which wants to know about the
 * class loader of the method that called it.
 */
ClassObject* dvmGetCaller2Class(const void* curFrame);

/*
 * Get the caller's caller's caller's class.  Pass in the current fp.
 *
 * This is used by e.g. java.lang.Class, which wants to know about the
 * class loader of the method that called it.
 */
ClassObject* dvmGetCaller3Class(const void* curFrame);

/*
 * Fill an array of method pointers representing the current stack
 * trace (element 0 is current frame).
 */
void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length);

/*
 * Common handling for stack overflow.
 */
void dvmHandleStackOverflow(Thread* self, const Method* method);
void dvmCleanupStackOverflow(Thread* self, const Object* exception);

/* debugging; dvmDumpThread() is probably a better starting point */
void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread);
void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread);

#ifdef __cplusplus
}
#endif

#endif /*_DALVIK_INTERP_STACK*/