blob: 5920cbc3a1b23c1a702426dee7e5aecaa9623695 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * Stacks and their uses (e.g. native --> interpreted method calls).
18 *
19 * See the majestic ASCII art in Stack.h.
20 */
21#include "Dalvik.h"
22#include "jni.h"
23
24#include <stdlib.h>
25#include <stdarg.h>
26
27/*
28 * Initialize the interpreter stack in a new thread.
29 *
30 * Currently this doesn't do much, since we don't need to zero out the
31 * stack (and we really don't want to if it was created with mmap).
32 */
33bool dvmInitInterpStack(Thread* thread, int stackSize)
34{
35 assert(thread->interpStackStart != NULL);
36
37 assert(thread->curFrame == NULL);
38
39 return true;
40}
41
42/*
43 * We're calling an interpreted method from an internal VM function or
44 * via reflection.
45 *
46 * Push a frame for an interpreted method onto the stack. This is only
47 * used when calling into interpreted code from native code. (The
48 * interpreter does its own stack frame manipulation for interp-->interp
49 * calls.)
50 *
51 * The size we need to reserve is the sum of parameters, local variables,
52 * saved goodies, and outbound parameters.
53 *
54 * We start by inserting a "break" frame, which ensures that the interpreter
55 * hands control back to us after the function we call returns or an
56 * uncaught exception is thrown.
57 */
58static bool dvmPushInterpFrame(Thread* self, const Method* method)
59{
60 StackSaveArea* saveBlock;
61 StackSaveArea* breakSaveBlock;
62 int stackReq;
63 u1* stackPtr;
64
65 assert(!dvmIsNativeMethod(method));
66 assert(!dvmIsAbstractMethod(method));
67
68 stackReq = method->registersSize * 4 // params + locals
69 + sizeof(StackSaveArea) * 2 // break frame + regular frame
70 + method->outsSize * 4; // args to other methods
71
72 if (self->curFrame != NULL)
73 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
74 else
75 stackPtr = self->interpStackStart;
76
77 if (stackPtr - stackReq < self->interpStackEnd) {
78 /* not enough space */
The Android Open Source Project99409882009-03-18 22:20:24 -070079 LOGW("Stack overflow on call to interp "
80 "(req=%d top=%p cur=%p size=%d %s.%s)\n",
81 stackReq, self->interpStackStart, self->curFrame,
82 self->interpStackSize, method->clazz->descriptor, method->name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080083 dvmHandleStackOverflow(self);
84 assert(dvmCheckException(self));
85 return false;
86 }
87
88 /*
89 * Shift the stack pointer down, leaving space for the function's
90 * args/registers and save area.
91 */
92 stackPtr -= sizeof(StackSaveArea);
93 breakSaveBlock = (StackSaveArea*)stackPtr;
94 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
95 saveBlock = (StackSaveArea*) stackPtr;
96
97#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
98 /* debug -- memset the new stack, unless we want valgrind's help */
99 memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
100#endif
101#ifdef EASY_GDB
102 breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
103 saveBlock->prevSave = breakSaveBlock;
104#endif
105
106 breakSaveBlock->prevFrame = self->curFrame;
107 breakSaveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700108 breakSaveBlock->xtra.localRefCookie = 0; // not required
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800109 breakSaveBlock->method = NULL;
110 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
111 saveBlock->savedPc = NULL; // not required
112 saveBlock->xtra.currentPc = NULL; // not required?
113 saveBlock->method = method;
114
115 LOGVV("PUSH frame: old=%p new=%p (size=%d)\n",
116 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
117 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
118
119 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
120
121 return true;
122}
123
124/*
125 * We're calling a JNI native method from an internal VM fuction or
126 * via reflection. This is also used to create the "fake" native-method
127 * frames at the top of the interpreted stack.
128 *
129 * This actually pushes two frames; the first is a "break" frame.
130 *
131 * The top frame has additional space for JNI local reference tracking.
132 */
133bool dvmPushJNIFrame(Thread* self, const Method* method)
134{
135 StackSaveArea* saveBlock;
136 StackSaveArea* breakSaveBlock;
137 int stackReq;
138 u1* stackPtr;
139
140 assert(dvmIsNativeMethod(method));
141
142 stackReq = method->registersSize * 4 // params only
143 + sizeof(StackSaveArea) * 2; // break frame + regular frame
144
145 if (self->curFrame != NULL)
146 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
147 else
148 stackPtr = self->interpStackStart;
149
150 if (stackPtr - stackReq < self->interpStackEnd) {
151 /* not enough space */
The Android Open Source Project99409882009-03-18 22:20:24 -0700152 LOGW("Stack overflow on call to native "
153 "(req=%d top=%p cur=%p size=%d '%s')\n",
154 stackReq, self->interpStackStart, self->curFrame,
155 self->interpStackSize, method->name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156 dvmHandleStackOverflow(self);
157 assert(dvmCheckException(self));
158 return false;
159 }
160
161 /*
162 * Shift the stack pointer down, leaving space for just the stack save
163 * area for the break frame, then shift down farther for the full frame.
164 * We leave space for the method args, which are copied in later.
165 */
166 stackPtr -= sizeof(StackSaveArea);
167 breakSaveBlock = (StackSaveArea*)stackPtr;
168 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
169 saveBlock = (StackSaveArea*) stackPtr;
170
171#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
172 /* debug -- memset the new stack */
173 memset(stackPtr, 0xaf, stackReq);
174#endif
175#ifdef EASY_GDB
176 if (self->curFrame == NULL)
177 breakSaveBlock->prevSave = NULL;
178 else
179 breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
180 saveBlock->prevSave = breakSaveBlock;
181#endif
182
183 breakSaveBlock->prevFrame = self->curFrame;
184 breakSaveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700185 breakSaveBlock->xtra.localRefCookie = 0; // not required
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800186 breakSaveBlock->method = NULL;
187 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
188 saveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700189#ifdef USE_INDIRECT_REF
190 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
191#else
192 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
193#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800194 saveBlock->method = method;
195
196 LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)\n",
197 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
198 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
199
200 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
201
202 return true;
203}
204
205/*
206 * This is used by the JNI PushLocalFrame call. We push a new frame onto
207 * the stack that has no ins, outs, or locals, and no break frame above it.
208 * It's strictly used for tracking JNI local refs, and will be popped off
209 * by dvmPopFrame if it's not removed explicitly.
210 */
211bool dvmPushLocalFrame(Thread* self, const Method* method)
212{
213 StackSaveArea* saveBlock;
214 int stackReq;
215 u1* stackPtr;
216
217 assert(dvmIsNativeMethod(method));
218
219 stackReq = sizeof(StackSaveArea); // regular frame
220
221 assert(self->curFrame != NULL);
222 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
223
224 if (stackPtr - stackReq < self->interpStackEnd) {
225 /* not enough space; let JNI throw the exception */
The Android Open Source Project99409882009-03-18 22:20:24 -0700226 LOGW("Stack overflow on PushLocal "
227 "(req=%d top=%p cur=%p size=%d '%s')\n",
228 stackReq, self->interpStackStart, self->curFrame,
229 self->interpStackSize, method->name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800230 dvmHandleStackOverflow(self);
231 assert(dvmCheckException(self));
232 return false;
233 }
234
235 /*
236 * Shift the stack pointer down, leaving space for just the stack save
237 * area for the break frame, then shift down farther for the full frame.
238 */
239 stackPtr -= sizeof(StackSaveArea);
240 saveBlock = (StackSaveArea*) stackPtr;
241
242#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
243 /* debug -- memset the new stack */
244 memset(stackPtr, 0xaf, stackReq);
245#endif
246#ifdef EASY_GDB
247 saveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
248#endif
249
250 saveBlock->prevFrame = self->curFrame;
251 saveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700252#ifdef USE_INDIRECT_REF
253 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
254#else
255 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
256#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800257 saveBlock->method = method;
258
259 LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n",
260 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
261 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
262
263 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
264
265 return true;
266}
267
268/*
269 * Pop one frame pushed on by JNI PushLocalFrame.
270 *
271 * If we've gone too far, the previous frame is either a break frame or
272 * an interpreted frame. Either way, the method pointer won't match.
273 */
274bool dvmPopLocalFrame(Thread* self)
275{
276 StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->curFrame);
277
278 assert(!dvmIsBreakFrame(self->curFrame));
279 if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
280 /*
281 * The previous frame doesn't have the same method pointer -- we've
282 * been asked to pop too much.
283 */
284 assert(dvmIsBreakFrame(saveBlock->prevFrame) ||
285 !dvmIsNativeMethod(
286 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
287 return false;
288 }
289
290 LOGVV("POP JNI local frame: removing %s, now %s\n",
291 saveBlock->method->name,
292 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
293 dvmPopJniLocals(self, saveBlock);
294 self->curFrame = saveBlock->prevFrame;
295
296 return true;
297}
298
299/*
300 * Pop a frame we added. There should be one method frame and one break
301 * frame.
302 *
303 * If JNI Push/PopLocalFrame calls were mismatched, we might end up
304 * popping multiple method frames before we find the break.
305 *
306 * Returns "false" if there was no frame to pop.
307 */
308static bool dvmPopFrame(Thread* self)
309{
310 StackSaveArea* saveBlock;
311
312 if (self->curFrame == NULL)
313 return false;
314
315 saveBlock = SAVEAREA_FROM_FP(self->curFrame);
316 assert(!dvmIsBreakFrame(self->curFrame));
317
318 /*
319 * Remove everything up to the break frame. If this was a call into
320 * native code, pop the JNI local references table.
321 */
322 while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
323 /* probably a native->native JNI call */
324
325 if (dvmIsNativeMethod(saveBlock->method)) {
326 LOGVV("Popping JNI stack frame for %s.%s%s\n",
327 saveBlock->method->clazz->descriptor,
328 saveBlock->method->name,
329 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
330 "" : " (JNI local)");
Andy McFaddend5ab7262009-08-25 07:19:34 -0700331 assert(saveBlock->xtra.localRefCookie != 0);
332 //assert(saveBlock->xtra.localRefCookie >= self->jniLocalRefTable.table &&
333 // saveBlock->xtra.localRefCookie <=self->jniLocalRefTable.nextEntry);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800334
335 dvmPopJniLocals(self, saveBlock);
336 }
337
338 saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
339 }
340 if (saveBlock->method != NULL) {
341 LOGE("PopFrame missed the break\n");
342 assert(false);
343 dvmAbort(); // stack trashed -- nowhere to go in this thread
344 }
345
346 LOGVV("POP frame: cur=%p new=%p\n",
347 self->curFrame, saveBlock->prevFrame);
348
349 self->curFrame = saveBlock->prevFrame;
350 return true;
351}
352
353/*
354 * Common code for dvmCallMethodV/A and dvmInvokeMethod.
355 *
356 * Pushes a call frame on, advancing self->curFrame.
357 */
358static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
359 bool checkAccess)
360{
361 ClassObject* clazz;
362
363#ifndef NDEBUG
364 if (self->status != THREAD_RUNNING) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700365 LOGW("threadid=%d: status=%d on call to %s.%s -\n",
366 self->threadId, self->status,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800367 method->clazz->descriptor, method->name);
368 }
369#endif
370
371 assert(self != NULL);
372 assert(method != NULL);
373
374 if (obj != NULL)
375 clazz = obj->clazz;
376 else
377 clazz = method->clazz;
378
379 IF_LOGVV() {
380 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
381 LOGVV("thread=%d native code calling %s.%s %s\n", self->threadId,
382 clazz->descriptor, method->name, desc);
383 free(desc);
384 }
385
386 if (checkAccess) {
387 /* needed for java.lang.reflect.Method.invoke */
388 if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->curFrame),
389 method))
390 {
391 /* note this throws IAException, not IAError */
392 dvmThrowException("Ljava/lang/IllegalAccessException;",
393 "access to method denied");
394 return NULL;
395 }
396 }
397
398 /*
399 * Push a call frame on. If there isn't enough room for ins, locals,
400 * outs, and the saved state, it will throw an exception.
401 *
402 * This updates self->curFrame.
403 */
404 if (dvmIsNativeMethod(method)) {
405 /* native code calling native code the hard way */
406 if (!dvmPushJNIFrame(self, method)) {
407 assert(dvmCheckException(self));
408 return NULL;
409 }
410 } else {
411 /* native code calling interpreted code */
412 if (!dvmPushInterpFrame(self, method)) {
413 assert(dvmCheckException(self));
414 return NULL;
415 }
416 }
417
418 return clazz;
419}
420
421/*
422 * Issue a method call.
423 *
424 * Pass in NULL for "obj" on calls to static methods.
425 *
426 * (Note this can't be inlined because it takes a variable number of args.)
427 */
428void dvmCallMethod(Thread* self, const Method* method, Object* obj,
429 JValue* pResult, ...)
430{
431 JValue result;
432
433 va_list args;
434 va_start(args, pResult);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700435 dvmCallMethodV(self, method, obj, false, pResult, args);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800436 va_end(args);
437}
438
439/*
440 * Issue a method call with a variable number of arguments. We process
441 * the contents of "args" by scanning the method signature.
442 *
443 * Pass in NULL for "obj" on calls to static methods.
444 *
445 * We don't need to take the class as an argument because, in Dalvik,
446 * we don't need to worry about static synchronized methods.
447 */
448void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
Andy McFaddend5ab7262009-08-25 07:19:34 -0700449 bool fromJni, JValue* pResult, va_list args)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800450{
451 const char* desc = &(method->shorty[1]); // [0] is the return type.
452 int verifyCount = 0;
453 ClassObject* clazz;
454 u4* ins;
455
456 clazz = callPrep(self, method, obj, false);
457 if (clazz == NULL)
458 return;
459
460 /* "ins" for new frame start at frame pointer plus locals */
461 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
462
463 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
464
465 /* put "this" pointer into in0 if appropriate */
466 if (!dvmIsStaticMethod(method)) {
467#ifdef WITH_EXTRA_OBJECT_VALIDATION
468 assert(obj != NULL && dvmIsValidObject(obj));
469#endif
470 *ins++ = (u4) obj;
471 verifyCount++;
472 }
473
Andy McFadden0083d372009-08-21 14:44:04 -0700474 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800475 while (*desc != '\0') {
476 switch (*(desc++)) {
477 case 'D': case 'J': {
478 u8 val = va_arg(args, u8);
479 memcpy(ins, &val, 8); // EABI prevents direct store
480 ins += 2;
481 verifyCount += 2;
482 break;
483 }
484 case 'F': {
485 /* floats were normalized to doubles; convert back */
486 float f = (float) va_arg(args, double);
487 *ins++ = dvmFloatToU4(f);
488 verifyCount++;
489 break;
490 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800491 case 'L': { /* 'shorty' descr uses L for all refs, incl array */
Andy McFadden0083d372009-08-21 14:44:04 -0700492 void* argObj = va_arg(args, void*);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800493 assert(obj == NULL || dvmIsValidObject(obj));
Andy McFaddend5ab7262009-08-25 07:19:34 -0700494 if (fromJni)
495 *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
496 else
497 *ins++ = (u4) argObj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800498 verifyCount++;
499 break;
500 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800501 default: {
Andy McFadden0083d372009-08-21 14:44:04 -0700502 /* Z B C S I -- all passed as 32-bit integers */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503 *ins++ = va_arg(args, u4);
504 verifyCount++;
505 break;
506 }
507 }
508 }
509
510#ifndef NDEBUG
511 if (verifyCount != method->insSize) {
512 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
513 method->insSize, clazz->descriptor, method->name);
514 assert(false);
515 goto bail;
516 }
517#endif
518
519 //dvmDumpThreadStack(dvmThreadSelf());
520
521 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700522#ifdef WITH_PROFILER
523 TRACE_METHOD_ENTER(self, method);
524#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800525 /*
526 * Because we leave no space for local variables, "curFrame" points
527 * directly at the method arguments.
528 */
529 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700530#ifdef WITH_PROFILER
531 TRACE_METHOD_EXIT(self, method);
532#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800533 } else {
534 dvmInterpret(self, method, pResult);
535 }
536
537bail:
538 dvmPopFrame(self);
539}
540
541/*
542 * Issue a method call with arguments provided in an array. We process
543 * the contents of "args" by scanning the method signature.
544 *
545 * The values were likely placed into an uninitialized jvalue array using
546 * the field specifiers, which means that sub-32-bit fields (e.g. short,
547 * boolean) may not have 32 or 64 bits of valid data. This is different
548 * from the varargs invocation where the C compiler does a widening
549 * conversion when calling a function. As a result, we have to be a
550 * little more precise when pulling stuff out.
Andy McFadden8e5c7842009-07-23 17:47:18 -0700551 *
552 * "args" may be NULL if the method has no arguments.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800553 */
554void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
Andy McFaddend5ab7262009-08-25 07:19:34 -0700555 bool fromJni, JValue* pResult, const jvalue* args)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556{
557 const char* desc = &(method->shorty[1]); // [0] is the return type.
558 int verifyCount = 0;
559 ClassObject* clazz;
560 u4* ins;
561
562 clazz = callPrep(self, method, obj, false);
563 if (clazz == NULL)
564 return;
565
566 /* "ins" for new frame start at frame pointer plus locals */
567 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
568
569 /* put "this" pointer into in0 if appropriate */
570 if (!dvmIsStaticMethod(method)) {
571 assert(obj != NULL);
Andy McFadden0083d372009-08-21 14:44:04 -0700572 *ins++ = (u4) obj; /* obj is a "real" ref */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800573 verifyCount++;
574 }
575
Andy McFadden0083d372009-08-21 14:44:04 -0700576 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800577 while (*desc != '\0') {
Andy McFadden0083d372009-08-21 14:44:04 -0700578 switch (*desc++) {
579 case 'D': /* 64-bit quantity; have to use */
580 case 'J': /* memcpy() in case of mis-alignment */
581 memcpy(ins, &args->j, 8);
582 ins += 2;
583 verifyCount++; /* this needs an extra push */
584 break;
585 case 'L': /* includes array refs */
Andy McFaddend5ab7262009-08-25 07:19:34 -0700586 if (fromJni)
587 *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
588 else
589 *ins++ = (u4) args->l;
Andy McFadden0083d372009-08-21 14:44:04 -0700590 break;
591 case 'F':
592 case 'I':
593 *ins++ = args->i; /* full 32 bits */
594 break;
595 case 'S':
596 *ins++ = args->s; /* 16 bits, sign-extended */
597 break;
598 case 'C':
599 *ins++ = args->c; /* 16 bits, unsigned */
600 break;
601 case 'B':
602 *ins++ = args->b; /* 8 bits, sign-extended */
603 break;
604 case 'Z':
605 *ins++ = args->z; /* 8 bits, zero or non-zero */
606 break;
607 default:
608 LOGE("Invalid char %c in short signature of %s.%s\n",
609 *(desc-1), clazz->descriptor, method->name);
610 assert(false);
611 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800612 }
Andy McFadden0083d372009-08-21 14:44:04 -0700613
614 verifyCount++;
615 args++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800616 }
617
618#ifndef NDEBUG
619 if (verifyCount != method->insSize) {
620 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
621 method->insSize, clazz->descriptor, method->name);
622 assert(false);
623 goto bail;
624 }
625#endif
626
627 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700628#ifdef WITH_PROFILER
629 TRACE_METHOD_ENTER(self, method);
630#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800631 /*
632 * Because we leave no space for local variables, "curFrame" points
633 * directly at the method arguments.
634 */
635 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700636#ifdef WITH_PROFILER
637 TRACE_METHOD_EXIT(self, method);
638#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800639 } else {
640 dvmInterpret(self, method, pResult);
641 }
642
643bail:
644 dvmPopFrame(self);
645}
646
647/*
648 * Invoke a method, using the specified arguments and return type, through
649 * one of the reflection interfaces. Could be a virtual or direct method
650 * (including constructors). Used for reflection.
651 *
652 * Deals with boxing/unboxing primitives and performs widening conversions.
653 *
654 * "invokeObj" will be null for a static method.
655 *
656 * If the invocation returns with an exception raised, we have to wrap it.
657 */
658Object* dvmInvokeMethod(Object* obj, const Method* method,
659 ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
660 bool noAccessCheck)
661{
662 ClassObject* clazz;
663 Object* retObj = NULL;
664 Thread* self = dvmThreadSelf();
665 s4* ins;
666 int verifyCount, argListLength;
667 JValue retval;
668
669 /* verify arg count */
670 if (argList != NULL)
671 argListLength = argList->length;
672 else
673 argListLength = 0;
674 if (argListLength != (int) params->length) {
675 LOGI("invoke: expected %d args, received %d args\n",
676 params->length, argListLength);
677 dvmThrowException("Ljava/lang/IllegalArgumentException;",
678 "wrong number of arguments");
679 return NULL;
680 }
681
682 clazz = callPrep(self, method, obj, !noAccessCheck);
683 if (clazz == NULL)
684 return NULL;
685
686 /* "ins" for new frame start at frame pointer plus locals */
687 ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
688 verifyCount = 0;
689
690 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
691
692 /* put "this" pointer into in0 if appropriate */
693 if (!dvmIsStaticMethod(method)) {
694 assert(obj != NULL);
695 *ins++ = (s4) obj;
696 verifyCount++;
697 }
698
699 /*
700 * Copy the args onto the stack. Primitive types are converted when
701 * necessary, and object types are verified.
702 */
703 DataObject** args;
704 ClassObject** types;
705 int i;
706
707 args = (DataObject**) argList->contents;
708 types = (ClassObject**) params->contents;
709 for (i = 0; i < argListLength; i++) {
710 int width;
711
712 width = dvmConvertArgument(*args++, *types++, ins);
713 if (width < 0) {
714 if (*(args-1) != NULL) {
715 LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
716 i, (*(args-1))->obj.clazz->descriptor,
717 (*(types-1))->descriptor);
718 }
719 dvmPopFrame(self); // throw wants to pull PC out of stack
720 dvmThrowException("Ljava/lang/IllegalArgumentException;",
721 "argument type mismatch");
722 goto bail_popped;
723 }
724
725 ins += width;
726 verifyCount += width;
727 }
728
729 if (verifyCount != method->insSize) {
730 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
731 method->insSize, clazz->descriptor, method->name);
732 assert(false);
733 goto bail;
734 }
735 //dvmDumpThreadStack(dvmThreadSelf());
736
737 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700738#ifdef WITH_PROFILER
739 TRACE_METHOD_ENTER(self, method);
740#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800741 /*
742 * Because we leave no space for local variables, "curFrame" points
743 * directly at the method arguments.
744 */
745 (*method->nativeFunc)(self->curFrame, &retval, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700746#ifdef WITH_PROFILER
747 TRACE_METHOD_EXIT(self, method);
748#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800749 } else {
750 dvmInterpret(self, method, &retval);
751 }
752
753 /*
754 * If an exception is raised, wrap and replace. This is necessary
755 * because the invoked method could have thrown a checked exception
756 * that the caller wasn't prepared for.
757 *
758 * We might be able to do this up in the interpreted code, but that will
759 * leave us with a shortened stack trace in the top-level exception.
760 */
761 if (dvmCheckException(self)) {
762 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
763 } else {
764 /*
765 * If this isn't a void method or constructor, convert the return type
766 * to an appropriate object.
767 *
768 * We don't do this when an exception is raised because the value
769 * in "retval" is undefined.
770 */
771 if (returnType != NULL) {
772 retObj = (Object*)dvmWrapPrimitive(retval, returnType);
773 dvmReleaseTrackedAlloc(retObj, NULL);
774 }
775 }
776
777bail:
778 dvmPopFrame(self);
779bail_popped:
780 return retObj;
781}
782
783typedef struct LineNumFromPcContext {
784 u4 address;
785 u4 lineNum;
786} LineNumFromPcContext;
787
788static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
789{
790 LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
791
792 // We know that this callback will be called in
793 // ascending address order, so keep going until we find
794 // a match or we've just gone past it.
795
796 if (address > pContext->address) {
797 // The line number from the previous positions callback
798 // wil be the final result.
799 return 1;
800 }
801
802 pContext->lineNum = lineNum;
803
804 return (address == pContext->address) ? 1 : 0;
805}
806
807/*
808 * Determine the source file line number based on the program counter.
809 * "pc" is an offset, in 16-bit units, from the start of the method's code.
810 *
811 * Returns -1 if no match was found (possibly because the source files were
812 * compiled without "-g", so no line number information is present).
813 * Returns -2 for native methods (as expected in exception traces).
814 */
815int dvmLineNumFromPC(const Method* method, u4 relPc)
816{
817 const DexCode* pDexCode = dvmGetMethodCode(method);
818
819 if (pDexCode == NULL) {
820 if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
821 return -2;
822 return -1; /* can happen for abstract method stub */
823 }
824
825 LineNumFromPcContext context;
826 memset(&context, 0, sizeof(context));
827 context.address = relPc;
828 // A method with no line number info should return -1
829 context.lineNum = -1;
830
831 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
832 method->clazz->descriptor,
833 method->prototype.protoIdx,
834 method->accessFlags,
835 lineNumForPcCb, NULL, &context);
836
837 return context.lineNum;
838}
839
840/*
841 * Compute the frame depth.
842 *
843 * Excludes "break" frames.
844 */
845int dvmComputeExactFrameDepth(const void* fp)
846{
847 int count = 0;
848
849 for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
850 if (!dvmIsBreakFrame(fp))
851 count++;
852 }
853
854 return count;
855}
856
857/*
858 * Compute the "vague" frame depth, which is just a pointer subtraction.
859 * The result is NOT an overly generous assessment of the number of
860 * frames; the only meaningful use is to compare against the result of
861 * an earlier invocation.
862 *
863 * Useful for implementing single-step debugger modes, which may need to
864 * call this for every instruction.
865 */
866int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
867{
868 const u1* interpStackStart = thread->interpStackStart;
869 const u1* interpStackBottom = interpStackStart - thread->interpStackSize;
870
871 assert((u1*) fp >= interpStackBottom && (u1*) fp < interpStackStart);
872 return interpStackStart - (u1*) fp;
873}
874
875/*
876 * Get the calling frame. Pass in the current fp.
877 *
878 * Skip "break" frames and reflection invoke frames.
879 */
880void* dvmGetCallerFP(const void* curFrame)
881{
882 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
883 StackSaveArea* saveArea;
884
885retry:
886 if (dvmIsBreakFrame(caller)) {
887 /* pop up one more */
888 caller = SAVEAREA_FROM_FP(caller)->prevFrame;
889 if (caller == NULL)
890 return NULL; /* hit the top */
891
892 /*
893 * If we got here by java.lang.reflect.Method.invoke(), we don't
894 * want to return Method's class loader. Shift up one and try
895 * again.
896 */
897 saveArea = SAVEAREA_FROM_FP(caller);
898 if (dvmIsReflectionMethod(saveArea->method)) {
899 caller = saveArea->prevFrame;
900 assert(caller != NULL);
901 goto retry;
902 }
903 }
904
905 return caller;
906}
907
908/*
909 * Get the caller's class. Pass in the current fp.
910 *
911 * This is used by e.g. java.lang.Class.
912 */
913ClassObject* dvmGetCallerClass(const void* curFrame)
914{
915 void* caller;
916
917 caller = dvmGetCallerFP(curFrame);
918 if (caller == NULL)
919 return NULL;
920
921 return SAVEAREA_FROM_FP(caller)->method->clazz;
922}
923
924/*
925 * Get the caller's caller's class. Pass in the current fp.
926 *
927 * This is used by e.g. java.lang.Class, which wants to know about the
928 * class loader of the method that called it.
929 */
930ClassObject* dvmGetCaller2Class(const void* curFrame)
931{
932 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
933 void* callerCaller;
934
935 /* at the top? */
936 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
937 return NULL;
938
939 /* go one more */
940 callerCaller = dvmGetCallerFP(caller);
941 if (callerCaller == NULL)
942 return NULL;
943
944 return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
945}
946
947/*
948 * Get the caller's caller's caller's class. Pass in the current fp.
949 *
950 * This is used by e.g. java.lang.Class, which wants to know about the
951 * class loader of the method that called it.
952 */
953ClassObject* dvmGetCaller3Class(const void* curFrame)
954{
955 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
956 int i;
957
958 /* at the top? */
959 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
960 return NULL;
961
962 /* Walk up two frames if possible. */
963 for (i = 0; i < 2; i++) {
964 caller = dvmGetCallerFP(caller);
965 if (caller == NULL)
966 return NULL;
967 }
968
969 return SAVEAREA_FROM_FP(caller)->method->clazz;
970}
971
972/*
973 * Create a flat array of methods that comprise the current interpreter
974 * stack trace. Pass in the current frame ptr.
975 *
976 * Allocates a new array and fills it with method pointers. Break frames
977 * are skipped, but reflection invocations are not. The caller must free
978 * "*pArray".
979 *
980 * The current frame will be in element 0.
981 *
982 * Returns "true" on success, "false" on failure (e.g. malloc failed).
983 */
984bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray,
985 int* pLength)
986{
987 const Method** array;
988 int idx, depth;
989
990 depth = dvmComputeExactFrameDepth(fp);
991 array = (const Method**) malloc(depth * sizeof(Method*));
992 if (array == NULL)
993 return false;
994
995 for (idx = 0; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
996 if (!dvmIsBreakFrame(fp))
997 array[idx++] = SAVEAREA_FROM_FP(fp)->method;
998 }
999 assert(idx == depth);
1000
1001 *pArray = array;
1002 *pLength = depth;
1003 return true;
1004}
1005
1006/*
1007 * Open up the reserved area and throw an exception. The reserved area
1008 * should only be needed to create and initialize the exception itself.
1009 *
1010 * If we already opened it and we're continuing to overflow, abort the VM.
1011 *
1012 * We have to leave the "reserved" area open until the "catch" handler has
1013 * finished doing its processing. This is because the catch handler may
1014 * need to resolve classes, which requires calling into the class loader if
1015 * the classes aren't already in the "initiating loader" list.
1016 */
1017void dvmHandleStackOverflow(Thread* self)
1018{
1019 /*
1020 * Can we make the reserved area available?
1021 */
1022 if (self->stackOverflowed) {
1023 /*
1024 * Already did, nothing to do but bail.
1025 */
1026 LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting\n",
1027 self->threadId);
1028 dvmDumpThread(self, false);
1029 dvmAbort();
1030 }
1031
1032 /* open it up to the full range */
1033 LOGI("Stack overflow, expanding (%p to %p)\n", self->interpStackEnd,
1034 self->interpStackStart - self->interpStackSize);
1035 //dvmDumpThread(self, false);
1036 self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1037 self->stackOverflowed = true;
1038
1039 /*
1040 * If we were trying to throw an exception when the stack overflowed,
1041 * we will blow up when doing the class lookup on StackOverflowError
1042 * because of the pending exception. So, we clear it and make it
1043 * the cause of the SOE.
1044 */
1045 Object* excep = dvmGetException(self);
1046 if (excep != NULL) {
1047 LOGW("Stack overflow while throwing exception\n");
1048 dvmClearException(self);
1049 }
1050 dvmThrowChainedException("Ljava/lang/StackOverflowError;", NULL, excep);
1051}
1052
1053/*
1054 * Reduce the available stack size. By this point we should have finished
1055 * our overflow processing.
1056 */
1057void dvmCleanupStackOverflow(Thread* self)
1058{
1059 const u1* newStackEnd;
1060
1061 assert(self->stackOverflowed);
1062
1063 newStackEnd = (self->interpStackStart - self->interpStackSize)
1064 + STACK_OVERFLOW_RESERVE;
1065 if ((u1*)self->curFrame <= newStackEnd) {
1066 LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)\n",
1067 self->interpStackEnd, self->curFrame);
1068 dvmDumpThread(self, false);
1069 dvmAbort();
1070 }
1071
1072 self->interpStackEnd = newStackEnd;
1073 self->stackOverflowed = false;
1074
1075 LOGI("Shrank stack (to %p, curFrame is %p)\n", self->interpStackEnd,
1076 self->curFrame);
1077}
1078
1079
1080/*
1081 * Dump stack frames, starting from the specified frame and moving down.
1082 *
1083 * Each frame holds a pointer to the currently executing method, and the
1084 * saved program counter from the caller ("previous" frame). This means
1085 * we don't have the PC for the current method on the stack, which is
1086 * pretty reasonable since it's in the "PC register" for the VM. Because
1087 * exceptions need to show the correct line number we actually *do* have
1088 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1089 *
1090 * Note "framePtr" could be NULL in rare circumstances.
1091 */
1092static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1093 Thread* thread)
1094{
1095 const StackSaveArea* saveArea;
1096 const Method* method;
1097 int checkCount = 0;
1098 const u2* currentPc = NULL;
1099 bool first = true;
1100
1101 /*
1102 * The "currentPc" is updated whenever we execute an instruction that
1103 * might throw an exception. Show it here.
1104 */
1105 if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) {
1106 saveArea = SAVEAREA_FROM_FP(framePtr);
1107
1108 if (saveArea->xtra.currentPc != NULL)
1109 currentPc = saveArea->xtra.currentPc;
1110 }
1111
1112 while (framePtr != NULL) {
1113 saveArea = SAVEAREA_FROM_FP(framePtr);
1114 method = saveArea->method;
1115
1116 if (dvmIsBreakFrame(framePtr)) {
1117 //dvmPrintDebugMessage(target, " (break frame)\n");
1118 } else {
1119 int relPc;
1120
1121 if (currentPc != NULL)
1122 relPc = currentPc - saveArea->method->insns;
1123 else
1124 relPc = -1;
1125
1126 char* className = dvmDescriptorToDot(method->clazz->descriptor);
1127 if (dvmIsNativeMethod(method))
1128 dvmPrintDebugMessage(target,
1129 " at %s.%s(Native Method)\n", className, method->name);
1130 else {
1131 dvmPrintDebugMessage(target,
1132 " at %s.%s(%s:%s%d)\n",
1133 className, method->name, dvmGetMethodSourceFile(method),
1134 (relPc >= 0 && first) ? "~" : "",
1135 relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1136 }
1137 free(className);
1138
1139 if (first &&
1140 (thread->status == THREAD_WAIT ||
1141 thread->status == THREAD_TIMED_WAIT))
1142 {
1143 /* warning: wait status not stable, even in suspend */
1144 Monitor* mon = thread->waitMonitor;
1145 Object* obj = dvmGetMonitorObject(mon);
1146 if (obj != NULL) {
1147 className = dvmDescriptorToDot(obj->clazz->descriptor);
1148 dvmPrintDebugMessage(target,
1149 " - waiting on <%p> (a %s)\n", mon, className);
1150 free(className);
1151 }
1152 }
1153
1154 }
1155
1156 /*
1157 * Get saved PC for previous frame. There's no savedPc in a "break"
1158 * frame, because that represents native or interpreted code
1159 * invoked by the VM. The saved PC is sitting in the "PC register",
1160 * a local variable on the native stack.
1161 */
1162 currentPc = saveArea->savedPc;
1163
1164 first = false;
1165
Andy McFadden0083d372009-08-21 14:44:04 -07001166 if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1167 LOGW("Warning: loop in stack trace at frame %d (%p -> %p)\n",
1168 checkCount, framePtr, saveArea->prevFrame);
1169 break;
1170 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001171 framePtr = saveArea->prevFrame;
1172
1173 checkCount++;
Andy McFadden0083d372009-08-21 14:44:04 -07001174 if (checkCount > 300) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001175 dvmPrintDebugMessage(target,
1176 " ***** printed %d frames, not showing any more\n",
1177 checkCount);
1178 break;
1179 }
1180 }
1181 dvmPrintDebugMessage(target, "\n");
1182}
1183
1184
1185/*
1186 * Dump the stack for the specified thread.
1187 */
1188void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1189{
1190 dumpFrames(target, thread->curFrame, thread);
1191}
1192
1193/*
1194 * Dump the stack for the specified thread, which is still running.
1195 *
1196 * This is very dangerous, because stack frames are being pushed on and
1197 * popped off, and if the thread exits we'll be looking at freed memory.
1198 * The plan here is to take a snapshot of the stack and then dump that
1199 * to try to minimize the chances of catching it mid-update. This should
1200 * work reasonably well on a single-CPU system.
1201 *
1202 * There is a small chance that calling here will crash the VM.
1203 */
1204void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1205{
1206 StackSaveArea* saveArea;
1207 const u1* origStack;
1208 u1* stackCopy = NULL;
1209 int origSize, fpOffset;
1210 void* fp;
1211 int depthLimit = 200;
1212
1213 if (thread == NULL || thread->curFrame == NULL) {
1214 dvmPrintDebugMessage(target,
1215 "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1216 thread, (thread != NULL) ? thread->threadId : 0);
1217 return;
1218 }
1219
1220 /* wait for a full quantum */
1221 sched_yield();
1222
1223 /* copy the info we need, then the stack itself */
1224 origSize = thread->interpStackSize;
1225 origStack = (const u1*) thread->interpStackStart - origSize;
1226 stackCopy = (u1*) malloc(origSize);
1227 fpOffset = (u1*) thread->curFrame - origStack;
1228 memcpy(stackCopy, origStack, origSize);
1229
1230 /*
1231 * Run through the stack and rewrite the "prev" pointers.
1232 */
1233 //LOGI("DR: fpOff=%d (from %p %p)\n",fpOffset, origStack, thread->curFrame);
1234 fp = stackCopy + fpOffset;
1235 while (true) {
1236 int prevOffset;
1237
1238 if (depthLimit-- < 0) {
1239 /* we're probably screwed */
1240 dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1241 dvmAbort();
1242 }
1243 saveArea = SAVEAREA_FROM_FP(fp);
1244 if (saveArea->prevFrame == NULL)
1245 break;
1246
1247 prevOffset = (u1*) saveArea->prevFrame - origStack;
1248 if (prevOffset < 0 || prevOffset > origSize) {
1249 dvmPrintDebugMessage(target,
1250 "DumpRunning: bad offset found: %d (from %p %p)\n",
1251 prevOffset, origStack, saveArea->prevFrame);
1252 saveArea->prevFrame = NULL;
1253 break;
1254 }
1255
1256 saveArea->prevFrame = stackCopy + prevOffset;
1257 fp = saveArea->prevFrame;
1258 }
1259
1260 /*
1261 * We still need to pass the Thread for some monitor wait stuff.
1262 */
1263 dumpFrames(target, stackCopy + fpOffset, thread);
1264 free(stackCopy);
1265}
1266