blob: 838147fe180680c3936b957d7e14e8e7057ed54f [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
108 breakSaveBlock->xtra.localRefTop = NULL; // not required
109 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
185 breakSaveBlock->xtra.localRefTop = NULL; // not required
186 breakSaveBlock->method = NULL;
187 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
188 saveBlock->savedPc = NULL; // not required
189 saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
190 saveBlock->method = method;
191
192 LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)\n",
193 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
194 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
195
196 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
197
198 return true;
199}
200
201/*
202 * This is used by the JNI PushLocalFrame call. We push a new frame onto
203 * the stack that has no ins, outs, or locals, and no break frame above it.
204 * It's strictly used for tracking JNI local refs, and will be popped off
205 * by dvmPopFrame if it's not removed explicitly.
206 */
207bool dvmPushLocalFrame(Thread* self, const Method* method)
208{
209 StackSaveArea* saveBlock;
210 int stackReq;
211 u1* stackPtr;
212
213 assert(dvmIsNativeMethod(method));
214
215 stackReq = sizeof(StackSaveArea); // regular frame
216
217 assert(self->curFrame != NULL);
218 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
219
220 if (stackPtr - stackReq < self->interpStackEnd) {
221 /* not enough space; let JNI throw the exception */
The Android Open Source Project99409882009-03-18 22:20:24 -0700222 LOGW("Stack overflow on PushLocal "
223 "(req=%d top=%p cur=%p size=%d '%s')\n",
224 stackReq, self->interpStackStart, self->curFrame,
225 self->interpStackSize, method->name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 dvmHandleStackOverflow(self);
227 assert(dvmCheckException(self));
228 return false;
229 }
230
231 /*
232 * Shift the stack pointer down, leaving space for just the stack save
233 * area for the break frame, then shift down farther for the full frame.
234 */
235 stackPtr -= sizeof(StackSaveArea);
236 saveBlock = (StackSaveArea*) stackPtr;
237
238#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
239 /* debug -- memset the new stack */
240 memset(stackPtr, 0xaf, stackReq);
241#endif
242#ifdef EASY_GDB
243 saveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
244#endif
245
246 saveBlock->prevFrame = self->curFrame;
247 saveBlock->savedPc = NULL; // not required
248 saveBlock->xtra.localRefTop = self->jniLocalRefTable.nextEntry;
249 saveBlock->method = method;
250
251 LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n",
252 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
253 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
254
255 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
256
257 return true;
258}
259
260/*
261 * Pop one frame pushed on by JNI PushLocalFrame.
262 *
263 * If we've gone too far, the previous frame is either a break frame or
264 * an interpreted frame. Either way, the method pointer won't match.
265 */
266bool dvmPopLocalFrame(Thread* self)
267{
268 StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->curFrame);
269
270 assert(!dvmIsBreakFrame(self->curFrame));
271 if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
272 /*
273 * The previous frame doesn't have the same method pointer -- we've
274 * been asked to pop too much.
275 */
276 assert(dvmIsBreakFrame(saveBlock->prevFrame) ||
277 !dvmIsNativeMethod(
278 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
279 return false;
280 }
281
282 LOGVV("POP JNI local frame: removing %s, now %s\n",
283 saveBlock->method->name,
284 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
285 dvmPopJniLocals(self, saveBlock);
286 self->curFrame = saveBlock->prevFrame;
287
288 return true;
289}
290
291/*
292 * Pop a frame we added. There should be one method frame and one break
293 * frame.
294 *
295 * If JNI Push/PopLocalFrame calls were mismatched, we might end up
296 * popping multiple method frames before we find the break.
297 *
298 * Returns "false" if there was no frame to pop.
299 */
300static bool dvmPopFrame(Thread* self)
301{
302 StackSaveArea* saveBlock;
303
304 if (self->curFrame == NULL)
305 return false;
306
307 saveBlock = SAVEAREA_FROM_FP(self->curFrame);
308 assert(!dvmIsBreakFrame(self->curFrame));
309
310 /*
311 * Remove everything up to the break frame. If this was a call into
312 * native code, pop the JNI local references table.
313 */
314 while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
315 /* probably a native->native JNI call */
316
317 if (dvmIsNativeMethod(saveBlock->method)) {
318 LOGVV("Popping JNI stack frame for %s.%s%s\n",
319 saveBlock->method->clazz->descriptor,
320 saveBlock->method->name,
321 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
322 "" : " (JNI local)");
323 assert(saveBlock->xtra.localRefTop != NULL);
324 assert(saveBlock->xtra.localRefTop >=self->jniLocalRefTable.table &&
325 saveBlock->xtra.localRefTop <=self->jniLocalRefTable.nextEntry);
326
327 dvmPopJniLocals(self, saveBlock);
328 }
329
330 saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
331 }
332 if (saveBlock->method != NULL) {
333 LOGE("PopFrame missed the break\n");
334 assert(false);
335 dvmAbort(); // stack trashed -- nowhere to go in this thread
336 }
337
338 LOGVV("POP frame: cur=%p new=%p\n",
339 self->curFrame, saveBlock->prevFrame);
340
341 self->curFrame = saveBlock->prevFrame;
342 return true;
343}
344
345/*
346 * Common code for dvmCallMethodV/A and dvmInvokeMethod.
347 *
348 * Pushes a call frame on, advancing self->curFrame.
349 */
350static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
351 bool checkAccess)
352{
353 ClassObject* clazz;
354
355#ifndef NDEBUG
356 if (self->status != THREAD_RUNNING) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700357 LOGW("threadid=%d: status=%d on call to %s.%s -\n",
358 self->threadId, self->status,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800359 method->clazz->descriptor, method->name);
360 }
361#endif
362
363 assert(self != NULL);
364 assert(method != NULL);
365
366 if (obj != NULL)
367 clazz = obj->clazz;
368 else
369 clazz = method->clazz;
370
371 IF_LOGVV() {
372 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
373 LOGVV("thread=%d native code calling %s.%s %s\n", self->threadId,
374 clazz->descriptor, method->name, desc);
375 free(desc);
376 }
377
378 if (checkAccess) {
379 /* needed for java.lang.reflect.Method.invoke */
380 if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->curFrame),
381 method))
382 {
383 /* note this throws IAException, not IAError */
384 dvmThrowException("Ljava/lang/IllegalAccessException;",
385 "access to method denied");
386 return NULL;
387 }
388 }
389
390 /*
391 * Push a call frame on. If there isn't enough room for ins, locals,
392 * outs, and the saved state, it will throw an exception.
393 *
394 * This updates self->curFrame.
395 */
396 if (dvmIsNativeMethod(method)) {
397 /* native code calling native code the hard way */
398 if (!dvmPushJNIFrame(self, method)) {
399 assert(dvmCheckException(self));
400 return NULL;
401 }
402 } else {
403 /* native code calling interpreted code */
404 if (!dvmPushInterpFrame(self, method)) {
405 assert(dvmCheckException(self));
406 return NULL;
407 }
408 }
409
410 return clazz;
411}
412
413/*
414 * Issue a method call.
415 *
416 * Pass in NULL for "obj" on calls to static methods.
417 *
418 * (Note this can't be inlined because it takes a variable number of args.)
419 */
420void dvmCallMethod(Thread* self, const Method* method, Object* obj,
421 JValue* pResult, ...)
422{
423 JValue result;
424
425 va_list args;
426 va_start(args, pResult);
427 dvmCallMethodV(self, method, obj, pResult, args);
428 va_end(args);
429}
430
431/*
432 * Issue a method call with a variable number of arguments. We process
433 * the contents of "args" by scanning the method signature.
434 *
435 * Pass in NULL for "obj" on calls to static methods.
436 *
437 * We don't need to take the class as an argument because, in Dalvik,
438 * we don't need to worry about static synchronized methods.
439 */
440void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
441 JValue* pResult, va_list args)
442{
443 const char* desc = &(method->shorty[1]); // [0] is the return type.
444 int verifyCount = 0;
445 ClassObject* clazz;
446 u4* ins;
447
448 clazz = callPrep(self, method, obj, false);
449 if (clazz == NULL)
450 return;
451
452 /* "ins" for new frame start at frame pointer plus locals */
453 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
454
455 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
456
457 /* put "this" pointer into in0 if appropriate */
458 if (!dvmIsStaticMethod(method)) {
459#ifdef WITH_EXTRA_OBJECT_VALIDATION
460 assert(obj != NULL && dvmIsValidObject(obj));
461#endif
462 *ins++ = (u4) obj;
463 verifyCount++;
464 }
465
Andy McFadden0083d372009-08-21 14:44:04 -0700466 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800467 while (*desc != '\0') {
468 switch (*(desc++)) {
469 case 'D': case 'J': {
470 u8 val = va_arg(args, u8);
471 memcpy(ins, &val, 8); // EABI prevents direct store
472 ins += 2;
473 verifyCount += 2;
474 break;
475 }
476 case 'F': {
477 /* floats were normalized to doubles; convert back */
478 float f = (float) va_arg(args, double);
479 *ins++ = dvmFloatToU4(f);
480 verifyCount++;
481 break;
482 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800483 case 'L': { /* 'shorty' descr uses L for all refs, incl array */
Andy McFadden0083d372009-08-21 14:44:04 -0700484 void* argObj = va_arg(args, void*);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800485 assert(obj == NULL || dvmIsValidObject(obj));
Andy McFadden0083d372009-08-21 14:44:04 -0700486 *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800487 verifyCount++;
488 break;
489 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800490 default: {
Andy McFadden0083d372009-08-21 14:44:04 -0700491 /* Z B C S I -- all passed as 32-bit integers */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800492 *ins++ = va_arg(args, u4);
493 verifyCount++;
494 break;
495 }
496 }
497 }
498
499#ifndef NDEBUG
500 if (verifyCount != method->insSize) {
501 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
502 method->insSize, clazz->descriptor, method->name);
503 assert(false);
504 goto bail;
505 }
506#endif
507
508 //dvmDumpThreadStack(dvmThreadSelf());
509
510 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700511#ifdef WITH_PROFILER
512 TRACE_METHOD_ENTER(self, method);
513#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800514 /*
515 * Because we leave no space for local variables, "curFrame" points
516 * directly at the method arguments.
517 */
518 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700519#ifdef WITH_PROFILER
520 TRACE_METHOD_EXIT(self, method);
521#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522 } else {
523 dvmInterpret(self, method, pResult);
524 }
525
526bail:
527 dvmPopFrame(self);
528}
529
530/*
531 * Issue a method call with arguments provided in an array. We process
532 * the contents of "args" by scanning the method signature.
533 *
534 * The values were likely placed into an uninitialized jvalue array using
535 * the field specifiers, which means that sub-32-bit fields (e.g. short,
536 * boolean) may not have 32 or 64 bits of valid data. This is different
537 * from the varargs invocation where the C compiler does a widening
538 * conversion when calling a function. As a result, we have to be a
539 * little more precise when pulling stuff out.
Andy McFadden8e5c7842009-07-23 17:47:18 -0700540 *
541 * "args" may be NULL if the method has no arguments.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800542 */
543void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
544 JValue* pResult, const jvalue* args)
545{
546 const char* desc = &(method->shorty[1]); // [0] is the return type.
547 int verifyCount = 0;
548 ClassObject* clazz;
549 u4* ins;
550
551 clazz = callPrep(self, method, obj, false);
552 if (clazz == NULL)
553 return;
554
555 /* "ins" for new frame start at frame pointer plus locals */
556 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
557
558 /* put "this" pointer into in0 if appropriate */
559 if (!dvmIsStaticMethod(method)) {
560 assert(obj != NULL);
Andy McFadden0083d372009-08-21 14:44:04 -0700561 *ins++ = (u4) obj; /* obj is a "real" ref */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800562 verifyCount++;
563 }
564
Andy McFadden0083d372009-08-21 14:44:04 -0700565 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800566 while (*desc != '\0') {
Andy McFadden0083d372009-08-21 14:44:04 -0700567 switch (*desc++) {
568 case 'D': /* 64-bit quantity; have to use */
569 case 'J': /* memcpy() in case of mis-alignment */
570 memcpy(ins, &args->j, 8);
571 ins += 2;
572 verifyCount++; /* this needs an extra push */
573 break;
574 case 'L': /* includes array refs */
575 *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
576 break;
577 case 'F':
578 case 'I':
579 *ins++ = args->i; /* full 32 bits */
580 break;
581 case 'S':
582 *ins++ = args->s; /* 16 bits, sign-extended */
583 break;
584 case 'C':
585 *ins++ = args->c; /* 16 bits, unsigned */
586 break;
587 case 'B':
588 *ins++ = args->b; /* 8 bits, sign-extended */
589 break;
590 case 'Z':
591 *ins++ = args->z; /* 8 bits, zero or non-zero */
592 break;
593 default:
594 LOGE("Invalid char %c in short signature of %s.%s\n",
595 *(desc-1), clazz->descriptor, method->name);
596 assert(false);
597 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800598 }
Andy McFadden0083d372009-08-21 14:44:04 -0700599
600 verifyCount++;
601 args++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800602 }
603
604#ifndef NDEBUG
605 if (verifyCount != method->insSize) {
606 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
607 method->insSize, clazz->descriptor, method->name);
608 assert(false);
609 goto bail;
610 }
611#endif
612
613 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700614#ifdef WITH_PROFILER
615 TRACE_METHOD_ENTER(self, method);
616#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800617 /*
618 * Because we leave no space for local variables, "curFrame" points
619 * directly at the method arguments.
620 */
621 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700622#ifdef WITH_PROFILER
623 TRACE_METHOD_EXIT(self, method);
624#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800625 } else {
626 dvmInterpret(self, method, pResult);
627 }
628
629bail:
630 dvmPopFrame(self);
631}
632
633/*
634 * Invoke a method, using the specified arguments and return type, through
635 * one of the reflection interfaces. Could be a virtual or direct method
636 * (including constructors). Used for reflection.
637 *
638 * Deals with boxing/unboxing primitives and performs widening conversions.
639 *
640 * "invokeObj" will be null for a static method.
641 *
642 * If the invocation returns with an exception raised, we have to wrap it.
643 */
644Object* dvmInvokeMethod(Object* obj, const Method* method,
645 ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
646 bool noAccessCheck)
647{
648 ClassObject* clazz;
649 Object* retObj = NULL;
650 Thread* self = dvmThreadSelf();
651 s4* ins;
652 int verifyCount, argListLength;
653 JValue retval;
654
655 /* verify arg count */
656 if (argList != NULL)
657 argListLength = argList->length;
658 else
659 argListLength = 0;
660 if (argListLength != (int) params->length) {
661 LOGI("invoke: expected %d args, received %d args\n",
662 params->length, argListLength);
663 dvmThrowException("Ljava/lang/IllegalArgumentException;",
664 "wrong number of arguments");
665 return NULL;
666 }
667
668 clazz = callPrep(self, method, obj, !noAccessCheck);
669 if (clazz == NULL)
670 return NULL;
671
672 /* "ins" for new frame start at frame pointer plus locals */
673 ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
674 verifyCount = 0;
675
676 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
677
678 /* put "this" pointer into in0 if appropriate */
679 if (!dvmIsStaticMethod(method)) {
680 assert(obj != NULL);
681 *ins++ = (s4) obj;
682 verifyCount++;
683 }
684
685 /*
686 * Copy the args onto the stack. Primitive types are converted when
687 * necessary, and object types are verified.
688 */
689 DataObject** args;
690 ClassObject** types;
691 int i;
692
693 args = (DataObject**) argList->contents;
694 types = (ClassObject**) params->contents;
695 for (i = 0; i < argListLength; i++) {
696 int width;
697
698 width = dvmConvertArgument(*args++, *types++, ins);
699 if (width < 0) {
700 if (*(args-1) != NULL) {
701 LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
702 i, (*(args-1))->obj.clazz->descriptor,
703 (*(types-1))->descriptor);
704 }
705 dvmPopFrame(self); // throw wants to pull PC out of stack
706 dvmThrowException("Ljava/lang/IllegalArgumentException;",
707 "argument type mismatch");
708 goto bail_popped;
709 }
710
711 ins += width;
712 verifyCount += width;
713 }
714
715 if (verifyCount != method->insSize) {
716 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
717 method->insSize, clazz->descriptor, method->name);
718 assert(false);
719 goto bail;
720 }
721 //dvmDumpThreadStack(dvmThreadSelf());
722
723 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700724#ifdef WITH_PROFILER
725 TRACE_METHOD_ENTER(self, method);
726#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800727 /*
728 * Because we leave no space for local variables, "curFrame" points
729 * directly at the method arguments.
730 */
731 (*method->nativeFunc)(self->curFrame, &retval, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700732#ifdef WITH_PROFILER
733 TRACE_METHOD_EXIT(self, method);
734#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800735 } else {
736 dvmInterpret(self, method, &retval);
737 }
738
739 /*
740 * If an exception is raised, wrap and replace. This is necessary
741 * because the invoked method could have thrown a checked exception
742 * that the caller wasn't prepared for.
743 *
744 * We might be able to do this up in the interpreted code, but that will
745 * leave us with a shortened stack trace in the top-level exception.
746 */
747 if (dvmCheckException(self)) {
748 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
749 } else {
750 /*
751 * If this isn't a void method or constructor, convert the return type
752 * to an appropriate object.
753 *
754 * We don't do this when an exception is raised because the value
755 * in "retval" is undefined.
756 */
757 if (returnType != NULL) {
758 retObj = (Object*)dvmWrapPrimitive(retval, returnType);
759 dvmReleaseTrackedAlloc(retObj, NULL);
760 }
761 }
762
763bail:
764 dvmPopFrame(self);
765bail_popped:
766 return retObj;
767}
768
769typedef struct LineNumFromPcContext {
770 u4 address;
771 u4 lineNum;
772} LineNumFromPcContext;
773
774static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
775{
776 LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
777
778 // We know that this callback will be called in
779 // ascending address order, so keep going until we find
780 // a match or we've just gone past it.
781
782 if (address > pContext->address) {
783 // The line number from the previous positions callback
784 // wil be the final result.
785 return 1;
786 }
787
788 pContext->lineNum = lineNum;
789
790 return (address == pContext->address) ? 1 : 0;
791}
792
793/*
794 * Determine the source file line number based on the program counter.
795 * "pc" is an offset, in 16-bit units, from the start of the method's code.
796 *
797 * Returns -1 if no match was found (possibly because the source files were
798 * compiled without "-g", so no line number information is present).
799 * Returns -2 for native methods (as expected in exception traces).
800 */
801int dvmLineNumFromPC(const Method* method, u4 relPc)
802{
803 const DexCode* pDexCode = dvmGetMethodCode(method);
804
805 if (pDexCode == NULL) {
806 if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
807 return -2;
808 return -1; /* can happen for abstract method stub */
809 }
810
811 LineNumFromPcContext context;
812 memset(&context, 0, sizeof(context));
813 context.address = relPc;
814 // A method with no line number info should return -1
815 context.lineNum = -1;
816
817 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
818 method->clazz->descriptor,
819 method->prototype.protoIdx,
820 method->accessFlags,
821 lineNumForPcCb, NULL, &context);
822
823 return context.lineNum;
824}
825
826/*
827 * Compute the frame depth.
828 *
829 * Excludes "break" frames.
830 */
831int dvmComputeExactFrameDepth(const void* fp)
832{
833 int count = 0;
834
835 for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
836 if (!dvmIsBreakFrame(fp))
837 count++;
838 }
839
840 return count;
841}
842
843/*
844 * Compute the "vague" frame depth, which is just a pointer subtraction.
845 * The result is NOT an overly generous assessment of the number of
846 * frames; the only meaningful use is to compare against the result of
847 * an earlier invocation.
848 *
849 * Useful for implementing single-step debugger modes, which may need to
850 * call this for every instruction.
851 */
852int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
853{
854 const u1* interpStackStart = thread->interpStackStart;
855 const u1* interpStackBottom = interpStackStart - thread->interpStackSize;
856
857 assert((u1*) fp >= interpStackBottom && (u1*) fp < interpStackStart);
858 return interpStackStart - (u1*) fp;
859}
860
861/*
862 * Get the calling frame. Pass in the current fp.
863 *
864 * Skip "break" frames and reflection invoke frames.
865 */
866void* dvmGetCallerFP(const void* curFrame)
867{
868 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
869 StackSaveArea* saveArea;
870
871retry:
872 if (dvmIsBreakFrame(caller)) {
873 /* pop up one more */
874 caller = SAVEAREA_FROM_FP(caller)->prevFrame;
875 if (caller == NULL)
876 return NULL; /* hit the top */
877
878 /*
879 * If we got here by java.lang.reflect.Method.invoke(), we don't
880 * want to return Method's class loader. Shift up one and try
881 * again.
882 */
883 saveArea = SAVEAREA_FROM_FP(caller);
884 if (dvmIsReflectionMethod(saveArea->method)) {
885 caller = saveArea->prevFrame;
886 assert(caller != NULL);
887 goto retry;
888 }
889 }
890
891 return caller;
892}
893
894/*
895 * Get the caller's class. Pass in the current fp.
896 *
897 * This is used by e.g. java.lang.Class.
898 */
899ClassObject* dvmGetCallerClass(const void* curFrame)
900{
901 void* caller;
902
903 caller = dvmGetCallerFP(curFrame);
904 if (caller == NULL)
905 return NULL;
906
907 return SAVEAREA_FROM_FP(caller)->method->clazz;
908}
909
910/*
911 * Get the caller's caller's class. Pass in the current fp.
912 *
913 * This is used by e.g. java.lang.Class, which wants to know about the
914 * class loader of the method that called it.
915 */
916ClassObject* dvmGetCaller2Class(const void* curFrame)
917{
918 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
919 void* callerCaller;
920
921 /* at the top? */
922 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
923 return NULL;
924
925 /* go one more */
926 callerCaller = dvmGetCallerFP(caller);
927 if (callerCaller == NULL)
928 return NULL;
929
930 return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
931}
932
933/*
934 * Get the caller's caller's caller's class. Pass in the current fp.
935 *
936 * This is used by e.g. java.lang.Class, which wants to know about the
937 * class loader of the method that called it.
938 */
939ClassObject* dvmGetCaller3Class(const void* curFrame)
940{
941 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
942 int i;
943
944 /* at the top? */
945 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
946 return NULL;
947
948 /* Walk up two frames if possible. */
949 for (i = 0; i < 2; i++) {
950 caller = dvmGetCallerFP(caller);
951 if (caller == NULL)
952 return NULL;
953 }
954
955 return SAVEAREA_FROM_FP(caller)->method->clazz;
956}
957
958/*
959 * Create a flat array of methods that comprise the current interpreter
960 * stack trace. Pass in the current frame ptr.
961 *
962 * Allocates a new array and fills it with method pointers. Break frames
963 * are skipped, but reflection invocations are not. The caller must free
964 * "*pArray".
965 *
966 * The current frame will be in element 0.
967 *
968 * Returns "true" on success, "false" on failure (e.g. malloc failed).
969 */
970bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray,
971 int* pLength)
972{
973 const Method** array;
974 int idx, depth;
975
976 depth = dvmComputeExactFrameDepth(fp);
977 array = (const Method**) malloc(depth * sizeof(Method*));
978 if (array == NULL)
979 return false;
980
981 for (idx = 0; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
982 if (!dvmIsBreakFrame(fp))
983 array[idx++] = SAVEAREA_FROM_FP(fp)->method;
984 }
985 assert(idx == depth);
986
987 *pArray = array;
988 *pLength = depth;
989 return true;
990}
991
992/*
993 * Open up the reserved area and throw an exception. The reserved area
994 * should only be needed to create and initialize the exception itself.
995 *
996 * If we already opened it and we're continuing to overflow, abort the VM.
997 *
998 * We have to leave the "reserved" area open until the "catch" handler has
999 * finished doing its processing. This is because the catch handler may
1000 * need to resolve classes, which requires calling into the class loader if
1001 * the classes aren't already in the "initiating loader" list.
1002 */
1003void dvmHandleStackOverflow(Thread* self)
1004{
1005 /*
1006 * Can we make the reserved area available?
1007 */
1008 if (self->stackOverflowed) {
1009 /*
1010 * Already did, nothing to do but bail.
1011 */
1012 LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting\n",
1013 self->threadId);
1014 dvmDumpThread(self, false);
1015 dvmAbort();
1016 }
1017
1018 /* open it up to the full range */
1019 LOGI("Stack overflow, expanding (%p to %p)\n", self->interpStackEnd,
1020 self->interpStackStart - self->interpStackSize);
1021 //dvmDumpThread(self, false);
1022 self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1023 self->stackOverflowed = true;
1024
1025 /*
1026 * If we were trying to throw an exception when the stack overflowed,
1027 * we will blow up when doing the class lookup on StackOverflowError
1028 * because of the pending exception. So, we clear it and make it
1029 * the cause of the SOE.
1030 */
1031 Object* excep = dvmGetException(self);
1032 if (excep != NULL) {
1033 LOGW("Stack overflow while throwing exception\n");
1034 dvmClearException(self);
1035 }
1036 dvmThrowChainedException("Ljava/lang/StackOverflowError;", NULL, excep);
1037}
1038
1039/*
1040 * Reduce the available stack size. By this point we should have finished
1041 * our overflow processing.
1042 */
1043void dvmCleanupStackOverflow(Thread* self)
1044{
1045 const u1* newStackEnd;
1046
1047 assert(self->stackOverflowed);
1048
1049 newStackEnd = (self->interpStackStart - self->interpStackSize)
1050 + STACK_OVERFLOW_RESERVE;
1051 if ((u1*)self->curFrame <= newStackEnd) {
1052 LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)\n",
1053 self->interpStackEnd, self->curFrame);
1054 dvmDumpThread(self, false);
1055 dvmAbort();
1056 }
1057
1058 self->interpStackEnd = newStackEnd;
1059 self->stackOverflowed = false;
1060
1061 LOGI("Shrank stack (to %p, curFrame is %p)\n", self->interpStackEnd,
1062 self->curFrame);
1063}
1064
1065
1066/*
1067 * Dump stack frames, starting from the specified frame and moving down.
1068 *
1069 * Each frame holds a pointer to the currently executing method, and the
1070 * saved program counter from the caller ("previous" frame). This means
1071 * we don't have the PC for the current method on the stack, which is
1072 * pretty reasonable since it's in the "PC register" for the VM. Because
1073 * exceptions need to show the correct line number we actually *do* have
1074 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1075 *
1076 * Note "framePtr" could be NULL in rare circumstances.
1077 */
1078static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1079 Thread* thread)
1080{
1081 const StackSaveArea* saveArea;
1082 const Method* method;
1083 int checkCount = 0;
1084 const u2* currentPc = NULL;
1085 bool first = true;
1086
1087 /*
1088 * The "currentPc" is updated whenever we execute an instruction that
1089 * might throw an exception. Show it here.
1090 */
1091 if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) {
1092 saveArea = SAVEAREA_FROM_FP(framePtr);
1093
1094 if (saveArea->xtra.currentPc != NULL)
1095 currentPc = saveArea->xtra.currentPc;
1096 }
1097
1098 while (framePtr != NULL) {
1099 saveArea = SAVEAREA_FROM_FP(framePtr);
1100 method = saveArea->method;
1101
1102 if (dvmIsBreakFrame(framePtr)) {
1103 //dvmPrintDebugMessage(target, " (break frame)\n");
1104 } else {
1105 int relPc;
1106
1107 if (currentPc != NULL)
1108 relPc = currentPc - saveArea->method->insns;
1109 else
1110 relPc = -1;
1111
1112 char* className = dvmDescriptorToDot(method->clazz->descriptor);
1113 if (dvmIsNativeMethod(method))
1114 dvmPrintDebugMessage(target,
1115 " at %s.%s(Native Method)\n", className, method->name);
1116 else {
1117 dvmPrintDebugMessage(target,
1118 " at %s.%s(%s:%s%d)\n",
1119 className, method->name, dvmGetMethodSourceFile(method),
1120 (relPc >= 0 && first) ? "~" : "",
1121 relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1122 }
1123 free(className);
1124
1125 if (first &&
1126 (thread->status == THREAD_WAIT ||
1127 thread->status == THREAD_TIMED_WAIT))
1128 {
1129 /* warning: wait status not stable, even in suspend */
1130 Monitor* mon = thread->waitMonitor;
1131 Object* obj = dvmGetMonitorObject(mon);
1132 if (obj != NULL) {
1133 className = dvmDescriptorToDot(obj->clazz->descriptor);
1134 dvmPrintDebugMessage(target,
1135 " - waiting on <%p> (a %s)\n", mon, className);
1136 free(className);
1137 }
1138 }
1139
1140 }
1141
1142 /*
1143 * Get saved PC for previous frame. There's no savedPc in a "break"
1144 * frame, because that represents native or interpreted code
1145 * invoked by the VM. The saved PC is sitting in the "PC register",
1146 * a local variable on the native stack.
1147 */
1148 currentPc = saveArea->savedPc;
1149
1150 first = false;
1151
Andy McFadden0083d372009-08-21 14:44:04 -07001152 if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1153 LOGW("Warning: loop in stack trace at frame %d (%p -> %p)\n",
1154 checkCount, framePtr, saveArea->prevFrame);
1155 break;
1156 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001157 framePtr = saveArea->prevFrame;
1158
1159 checkCount++;
Andy McFadden0083d372009-08-21 14:44:04 -07001160 if (checkCount > 300) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001161 dvmPrintDebugMessage(target,
1162 " ***** printed %d frames, not showing any more\n",
1163 checkCount);
1164 break;
1165 }
1166 }
1167 dvmPrintDebugMessage(target, "\n");
1168}
1169
1170
1171/*
1172 * Dump the stack for the specified thread.
1173 */
1174void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1175{
1176 dumpFrames(target, thread->curFrame, thread);
1177}
1178
1179/*
1180 * Dump the stack for the specified thread, which is still running.
1181 *
1182 * This is very dangerous, because stack frames are being pushed on and
1183 * popped off, and if the thread exits we'll be looking at freed memory.
1184 * The plan here is to take a snapshot of the stack and then dump that
1185 * to try to minimize the chances of catching it mid-update. This should
1186 * work reasonably well on a single-CPU system.
1187 *
1188 * There is a small chance that calling here will crash the VM.
1189 */
1190void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1191{
1192 StackSaveArea* saveArea;
1193 const u1* origStack;
1194 u1* stackCopy = NULL;
1195 int origSize, fpOffset;
1196 void* fp;
1197 int depthLimit = 200;
1198
1199 if (thread == NULL || thread->curFrame == NULL) {
1200 dvmPrintDebugMessage(target,
1201 "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1202 thread, (thread != NULL) ? thread->threadId : 0);
1203 return;
1204 }
1205
1206 /* wait for a full quantum */
1207 sched_yield();
1208
1209 /* copy the info we need, then the stack itself */
1210 origSize = thread->interpStackSize;
1211 origStack = (const u1*) thread->interpStackStart - origSize;
1212 stackCopy = (u1*) malloc(origSize);
1213 fpOffset = (u1*) thread->curFrame - origStack;
1214 memcpy(stackCopy, origStack, origSize);
1215
1216 /*
1217 * Run through the stack and rewrite the "prev" pointers.
1218 */
1219 //LOGI("DR: fpOff=%d (from %p %p)\n",fpOffset, origStack, thread->curFrame);
1220 fp = stackCopy + fpOffset;
1221 while (true) {
1222 int prevOffset;
1223
1224 if (depthLimit-- < 0) {
1225 /* we're probably screwed */
1226 dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1227 dvmAbort();
1228 }
1229 saveArea = SAVEAREA_FROM_FP(fp);
1230 if (saveArea->prevFrame == NULL)
1231 break;
1232
1233 prevOffset = (u1*) saveArea->prevFrame - origStack;
1234 if (prevOffset < 0 || prevOffset > origSize) {
1235 dvmPrintDebugMessage(target,
1236 "DumpRunning: bad offset found: %d (from %p %p)\n",
1237 prevOffset, origStack, saveArea->prevFrame);
1238 saveArea->prevFrame = NULL;
1239 break;
1240 }
1241
1242 saveArea->prevFrame = stackCopy + prevOffset;
1243 fp = saveArea->prevFrame;
1244 }
1245
1246 /*
1247 * We still need to pass the Thread for some monitor wait stuff.
1248 */
1249 dumpFrames(target, stackCopy + fpOffset, thread);
1250 free(stackCopy);
1251}
1252