blob: b0aad81010259020cd29c04b0130614bab269a38 [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 */
Andy McFadden4fbba1f2010-02-03 07:21:14 -080016
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080017/*
18 * Stacks and their uses (e.g. native --> interpreted method calls).
19 *
20 * See the majestic ASCII art in Stack.h.
21 */
22#include "Dalvik.h"
23#include "jni.h"
24
25#include <stdlib.h>
26#include <stdarg.h>
27
28/*
29 * Initialize the interpreter stack in a new thread.
30 *
31 * Currently this doesn't do much, since we don't need to zero out the
32 * stack (and we really don't want to if it was created with mmap).
33 */
34bool dvmInitInterpStack(Thread* thread, int stackSize)
35{
36 assert(thread->interpStackStart != NULL);
37
38 assert(thread->curFrame == NULL);
39
40 return true;
41}
42
43/*
44 * We're calling an interpreted method from an internal VM function or
45 * via reflection.
46 *
47 * Push a frame for an interpreted method onto the stack. This is only
48 * used when calling into interpreted code from native code. (The
49 * interpreter does its own stack frame manipulation for interp-->interp
50 * calls.)
51 *
52 * The size we need to reserve is the sum of parameters, local variables,
53 * saved goodies, and outbound parameters.
54 *
55 * We start by inserting a "break" frame, which ensures that the interpreter
56 * hands control back to us after the function we call returns or an
57 * uncaught exception is thrown.
58 */
59static bool dvmPushInterpFrame(Thread* self, const Method* method)
60{
61 StackSaveArea* saveBlock;
62 StackSaveArea* breakSaveBlock;
63 int stackReq;
64 u1* stackPtr;
65
66 assert(!dvmIsNativeMethod(method));
67 assert(!dvmIsAbstractMethod(method));
68
69 stackReq = method->registersSize * 4 // params + locals
70 + sizeof(StackSaveArea) * 2 // break frame + regular frame
71 + method->outsSize * 4; // args to other methods
72
73 if (self->curFrame != NULL)
74 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
75 else
76 stackPtr = self->interpStackStart;
77
78 if (stackPtr - stackReq < self->interpStackEnd) {
79 /* not enough space */
The Android Open Source Project99409882009-03-18 22:20:24 -070080 LOGW("Stack overflow on call to interp "
81 "(req=%d top=%p cur=%p size=%d %s.%s)\n",
82 stackReq, self->interpStackStart, self->curFrame,
83 self->interpStackSize, method->clazz->descriptor, method->name);
Andy McFadden6ed1a0f2009-09-10 15:34:19 -070084 dvmHandleStackOverflow(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080085 assert(dvmCheckException(self));
86 return false;
87 }
88
89 /*
90 * Shift the stack pointer down, leaving space for the function's
91 * args/registers and save area.
92 */
93 stackPtr -= sizeof(StackSaveArea);
94 breakSaveBlock = (StackSaveArea*)stackPtr;
95 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
96 saveBlock = (StackSaveArea*) stackPtr;
97
98#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
99 /* debug -- memset the new stack, unless we want valgrind's help */
100 memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
101#endif
102#ifdef EASY_GDB
103 breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
104 saveBlock->prevSave = breakSaveBlock;
105#endif
106
107 breakSaveBlock->prevFrame = self->curFrame;
108 breakSaveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700109 breakSaveBlock->xtra.localRefCookie = 0; // not required
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110 breakSaveBlock->method = NULL;
111 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
112 saveBlock->savedPc = NULL; // not required
113 saveBlock->xtra.currentPc = NULL; // not required?
114 saveBlock->method = method;
115
116 LOGVV("PUSH frame: old=%p new=%p (size=%d)\n",
117 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
118 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
119
120 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
121
122 return true;
123}
124
125/*
126 * We're calling a JNI native method from an internal VM fuction or
127 * via reflection. This is also used to create the "fake" native-method
128 * frames at the top of the interpreted stack.
129 *
130 * This actually pushes two frames; the first is a "break" frame.
131 *
132 * The top frame has additional space for JNI local reference tracking.
133 */
134bool dvmPushJNIFrame(Thread* self, const Method* method)
135{
136 StackSaveArea* saveBlock;
137 StackSaveArea* breakSaveBlock;
138 int stackReq;
139 u1* stackPtr;
140
141 assert(dvmIsNativeMethod(method));
142
143 stackReq = method->registersSize * 4 // params only
144 + sizeof(StackSaveArea) * 2; // break frame + regular frame
145
146 if (self->curFrame != NULL)
147 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
148 else
149 stackPtr = self->interpStackStart;
150
151 if (stackPtr - stackReq < self->interpStackEnd) {
152 /* not enough space */
The Android Open Source Project99409882009-03-18 22:20:24 -0700153 LOGW("Stack overflow on call to native "
154 "(req=%d top=%p cur=%p size=%d '%s')\n",
155 stackReq, self->interpStackStart, self->curFrame,
156 self->interpStackSize, method->name);
Andy McFadden6ed1a0f2009-09-10 15:34:19 -0700157 dvmHandleStackOverflow(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158 assert(dvmCheckException(self));
159 return false;
160 }
161
162 /*
163 * Shift the stack pointer down, leaving space for just the stack save
164 * area for the break frame, then shift down farther for the full frame.
165 * We leave space for the method args, which are copied in later.
166 */
167 stackPtr -= sizeof(StackSaveArea);
168 breakSaveBlock = (StackSaveArea*)stackPtr;
169 stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
170 saveBlock = (StackSaveArea*) stackPtr;
171
172#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
173 /* debug -- memset the new stack */
174 memset(stackPtr, 0xaf, stackReq);
175#endif
176#ifdef EASY_GDB
177 if (self->curFrame == NULL)
178 breakSaveBlock->prevSave = NULL;
179 else
180 breakSaveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
181 saveBlock->prevSave = breakSaveBlock;
182#endif
183
184 breakSaveBlock->prevFrame = self->curFrame;
185 breakSaveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700186 breakSaveBlock->xtra.localRefCookie = 0; // not required
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800187 breakSaveBlock->method = NULL;
188 saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
189 saveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700190#ifdef USE_INDIRECT_REF
191 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
192#else
193 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
194#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800195 saveBlock->method = method;
196
197 LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)\n",
198 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
199 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
200
201 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
202
203 return true;
204}
205
206/*
207 * This is used by the JNI PushLocalFrame call. We push a new frame onto
208 * the stack that has no ins, outs, or locals, and no break frame above it.
209 * It's strictly used for tracking JNI local refs, and will be popped off
210 * by dvmPopFrame if it's not removed explicitly.
211 */
212bool dvmPushLocalFrame(Thread* self, const Method* method)
213{
214 StackSaveArea* saveBlock;
215 int stackReq;
216 u1* stackPtr;
217
218 assert(dvmIsNativeMethod(method));
219
220 stackReq = sizeof(StackSaveArea); // regular frame
221
222 assert(self->curFrame != NULL);
223 stackPtr = (u1*) SAVEAREA_FROM_FP(self->curFrame);
224
225 if (stackPtr - stackReq < self->interpStackEnd) {
226 /* not enough space; let JNI throw the exception */
The Android Open Source Project99409882009-03-18 22:20:24 -0700227 LOGW("Stack overflow on PushLocal "
228 "(req=%d top=%p cur=%p size=%d '%s')\n",
229 stackReq, self->interpStackStart, self->curFrame,
230 self->interpStackSize, method->name);
Andy McFadden6ed1a0f2009-09-10 15:34:19 -0700231 dvmHandleStackOverflow(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800232 assert(dvmCheckException(self));
233 return false;
234 }
235
236 /*
237 * Shift the stack pointer down, leaving space for just the stack save
238 * area for the break frame, then shift down farther for the full frame.
239 */
240 stackPtr -= sizeof(StackSaveArea);
241 saveBlock = (StackSaveArea*) stackPtr;
242
243#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
244 /* debug -- memset the new stack */
245 memset(stackPtr, 0xaf, stackReq);
246#endif
247#ifdef EASY_GDB
248 saveBlock->prevSave = FP_FROM_SAVEAREA(self->curFrame);
249#endif
250
251 saveBlock->prevFrame = self->curFrame;
252 saveBlock->savedPc = NULL; // not required
Andy McFaddend5ab7262009-08-25 07:19:34 -0700253#ifdef USE_INDIRECT_REF
254 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
255#else
256 saveBlock->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
257#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800258 saveBlock->method = method;
259
260 LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)\n",
261 self->curFrame, FP_FROM_SAVEAREA(saveBlock),
262 (u1*)self->curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
263
264 self->curFrame = FP_FROM_SAVEAREA(saveBlock);
265
266 return true;
267}
268
269/*
270 * Pop one frame pushed on by JNI PushLocalFrame.
271 *
272 * If we've gone too far, the previous frame is either a break frame or
273 * an interpreted frame. Either way, the method pointer won't match.
274 */
275bool dvmPopLocalFrame(Thread* self)
276{
277 StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->curFrame);
278
279 assert(!dvmIsBreakFrame(self->curFrame));
280 if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
281 /*
282 * The previous frame doesn't have the same method pointer -- we've
283 * been asked to pop too much.
284 */
285 assert(dvmIsBreakFrame(saveBlock->prevFrame) ||
286 !dvmIsNativeMethod(
287 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
288 return false;
289 }
290
291 LOGVV("POP JNI local frame: removing %s, now %s\n",
292 saveBlock->method->name,
293 SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
294 dvmPopJniLocals(self, saveBlock);
295 self->curFrame = saveBlock->prevFrame;
296
297 return true;
298}
299
300/*
301 * Pop a frame we added. There should be one method frame and one break
302 * frame.
303 *
304 * If JNI Push/PopLocalFrame calls were mismatched, we might end up
305 * popping multiple method frames before we find the break.
306 *
307 * Returns "false" if there was no frame to pop.
308 */
309static bool dvmPopFrame(Thread* self)
310{
311 StackSaveArea* saveBlock;
312
313 if (self->curFrame == NULL)
314 return false;
315
316 saveBlock = SAVEAREA_FROM_FP(self->curFrame);
317 assert(!dvmIsBreakFrame(self->curFrame));
318
319 /*
320 * Remove everything up to the break frame. If this was a call into
321 * native code, pop the JNI local references table.
322 */
323 while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
324 /* probably a native->native JNI call */
325
326 if (dvmIsNativeMethod(saveBlock->method)) {
327 LOGVV("Popping JNI stack frame for %s.%s%s\n",
328 saveBlock->method->clazz->descriptor,
329 saveBlock->method->name,
330 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
331 "" : " (JNI local)");
Andy McFaddend5ab7262009-08-25 07:19:34 -0700332 assert(saveBlock->xtra.localRefCookie != 0);
333 //assert(saveBlock->xtra.localRefCookie >= self->jniLocalRefTable.table &&
334 // saveBlock->xtra.localRefCookie <=self->jniLocalRefTable.nextEntry);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800335
336 dvmPopJniLocals(self, saveBlock);
337 }
338
339 saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
340 }
341 if (saveBlock->method != NULL) {
342 LOGE("PopFrame missed the break\n");
343 assert(false);
344 dvmAbort(); // stack trashed -- nowhere to go in this thread
345 }
346
347 LOGVV("POP frame: cur=%p new=%p\n",
348 self->curFrame, saveBlock->prevFrame);
349
350 self->curFrame = saveBlock->prevFrame;
351 return true;
352}
353
354/*
355 * Common code for dvmCallMethodV/A and dvmInvokeMethod.
356 *
357 * Pushes a call frame on, advancing self->curFrame.
358 */
359static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
360 bool checkAccess)
361{
362 ClassObject* clazz;
363
364#ifndef NDEBUG
365 if (self->status != THREAD_RUNNING) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700366 LOGW("threadid=%d: status=%d on call to %s.%s -\n",
367 self->threadId, self->status,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800368 method->clazz->descriptor, method->name);
369 }
370#endif
371
372 assert(self != NULL);
373 assert(method != NULL);
374
375 if (obj != NULL)
376 clazz = obj->clazz;
377 else
378 clazz = method->clazz;
379
380 IF_LOGVV() {
381 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
382 LOGVV("thread=%d native code calling %s.%s %s\n", self->threadId,
383 clazz->descriptor, method->name, desc);
384 free(desc);
385 }
386
387 if (checkAccess) {
388 /* needed for java.lang.reflect.Method.invoke */
389 if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->curFrame),
390 method))
391 {
392 /* note this throws IAException, not IAError */
393 dvmThrowException("Ljava/lang/IllegalAccessException;",
394 "access to method denied");
395 return NULL;
396 }
397 }
398
399 /*
400 * Push a call frame on. If there isn't enough room for ins, locals,
401 * outs, and the saved state, it will throw an exception.
402 *
403 * This updates self->curFrame.
404 */
405 if (dvmIsNativeMethod(method)) {
406 /* native code calling native code the hard way */
407 if (!dvmPushJNIFrame(self, method)) {
408 assert(dvmCheckException(self));
409 return NULL;
410 }
411 } else {
412 /* native code calling interpreted code */
413 if (!dvmPushInterpFrame(self, method)) {
414 assert(dvmCheckException(self));
415 return NULL;
416 }
417 }
418
419 return clazz;
420}
421
422/*
423 * Issue a method call.
424 *
425 * Pass in NULL for "obj" on calls to static methods.
426 *
427 * (Note this can't be inlined because it takes a variable number of args.)
428 */
429void dvmCallMethod(Thread* self, const Method* method, Object* obj,
430 JValue* pResult, ...)
431{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800432 va_list args;
433 va_start(args, pResult);
Andy McFaddend5ab7262009-08-25 07:19:34 -0700434 dvmCallMethodV(self, method, obj, false, pResult, args);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800435 va_end(args);
436}
437
438/*
439 * Issue a method call with a variable number of arguments. We process
440 * the contents of "args" by scanning the method signature.
441 *
442 * Pass in NULL for "obj" on calls to static methods.
443 *
444 * We don't need to take the class as an argument because, in Dalvik,
445 * we don't need to worry about static synchronized methods.
446 */
447void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
Andy McFaddend5ab7262009-08-25 07:19:34 -0700448 bool fromJni, JValue* pResult, va_list args)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800449{
450 const char* desc = &(method->shorty[1]); // [0] is the return type.
451 int verifyCount = 0;
452 ClassObject* clazz;
453 u4* ins;
454
455 clazz = callPrep(self, method, obj, false);
456 if (clazz == NULL)
457 return;
458
459 /* "ins" for new frame start at frame pointer plus locals */
460 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
461
462 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
463
464 /* put "this" pointer into in0 if appropriate */
465 if (!dvmIsStaticMethod(method)) {
466#ifdef WITH_EXTRA_OBJECT_VALIDATION
467 assert(obj != NULL && dvmIsValidObject(obj));
468#endif
469 *ins++ = (u4) obj;
470 verifyCount++;
471 }
472
Andy McFadden0083d372009-08-21 14:44:04 -0700473 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800474 while (*desc != '\0') {
475 switch (*(desc++)) {
476 case 'D': case 'J': {
477 u8 val = va_arg(args, u8);
478 memcpy(ins, &val, 8); // EABI prevents direct store
479 ins += 2;
480 verifyCount += 2;
481 break;
482 }
483 case 'F': {
484 /* floats were normalized to doubles; convert back */
485 float f = (float) va_arg(args, double);
486 *ins++ = dvmFloatToU4(f);
487 verifyCount++;
488 break;
489 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800490 case 'L': { /* 'shorty' descr uses L for all refs, incl array */
Andy McFadden0083d372009-08-21 14:44:04 -0700491 void* argObj = va_arg(args, void*);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800492 assert(obj == NULL || dvmIsValidObject(obj));
Andy McFaddend5ab7262009-08-25 07:19:34 -0700493 if (fromJni)
494 *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
495 else
496 *ins++ = (u4) argObj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800497 verifyCount++;
498 break;
499 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800500 default: {
Andy McFadden0083d372009-08-21 14:44:04 -0700501 /* Z B C S I -- all passed as 32-bit integers */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800502 *ins++ = va_arg(args, u4);
503 verifyCount++;
504 break;
505 }
506 }
507 }
508
509#ifndef NDEBUG
510 if (verifyCount != method->insSize) {
511 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
512 method->insSize, clazz->descriptor, method->name);
513 assert(false);
514 goto bail;
515 }
516#endif
517
518 //dvmDumpThreadStack(dvmThreadSelf());
519
520 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700521 TRACE_METHOD_ENTER(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522 /*
523 * Because we leave no space for local variables, "curFrame" points
524 * directly at the method arguments.
525 */
526 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700527 TRACE_METHOD_EXIT(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800528 } else {
529 dvmInterpret(self, method, pResult);
530 }
531
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700532#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800533bail:
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700534#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800535 dvmPopFrame(self);
536}
537
538/*
539 * Issue a method call with arguments provided in an array. We process
540 * the contents of "args" by scanning the method signature.
541 *
542 * The values were likely placed into an uninitialized jvalue array using
543 * the field specifiers, which means that sub-32-bit fields (e.g. short,
544 * boolean) may not have 32 or 64 bits of valid data. This is different
545 * from the varargs invocation where the C compiler does a widening
546 * conversion when calling a function. As a result, we have to be a
547 * little more precise when pulling stuff out.
Andy McFadden8e5c7842009-07-23 17:47:18 -0700548 *
549 * "args" may be NULL if the method has no arguments.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800550 */
551void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
Andy McFaddend5ab7262009-08-25 07:19:34 -0700552 bool fromJni, JValue* pResult, const jvalue* args)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800553{
554 const char* desc = &(method->shorty[1]); // [0] is the return type.
555 int verifyCount = 0;
556 ClassObject* clazz;
557 u4* ins;
558
559 clazz = callPrep(self, method, obj, false);
560 if (clazz == NULL)
561 return;
562
563 /* "ins" for new frame start at frame pointer plus locals */
564 ins = ((u4*)self->curFrame) + (method->registersSize - method->insSize);
565
566 /* put "this" pointer into in0 if appropriate */
567 if (!dvmIsStaticMethod(method)) {
568 assert(obj != NULL);
Andy McFadden0083d372009-08-21 14:44:04 -0700569 *ins++ = (u4) obj; /* obj is a "real" ref */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800570 verifyCount++;
571 }
572
Andy McFadden0083d372009-08-21 14:44:04 -0700573 JNIEnv* env = self->jniEnv;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800574 while (*desc != '\0') {
Andy McFadden0083d372009-08-21 14:44:04 -0700575 switch (*desc++) {
576 case 'D': /* 64-bit quantity; have to use */
577 case 'J': /* memcpy() in case of mis-alignment */
578 memcpy(ins, &args->j, 8);
579 ins += 2;
580 verifyCount++; /* this needs an extra push */
581 break;
582 case 'L': /* includes array refs */
Andy McFaddend5ab7262009-08-25 07:19:34 -0700583 if (fromJni)
584 *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
585 else
586 *ins++ = (u4) args->l;
Andy McFadden0083d372009-08-21 14:44:04 -0700587 break;
588 case 'F':
589 case 'I':
590 *ins++ = args->i; /* full 32 bits */
591 break;
592 case 'S':
593 *ins++ = args->s; /* 16 bits, sign-extended */
594 break;
595 case 'C':
596 *ins++ = args->c; /* 16 bits, unsigned */
597 break;
598 case 'B':
599 *ins++ = args->b; /* 8 bits, sign-extended */
600 break;
601 case 'Z':
602 *ins++ = args->z; /* 8 bits, zero or non-zero */
603 break;
604 default:
605 LOGE("Invalid char %c in short signature of %s.%s\n",
606 *(desc-1), clazz->descriptor, method->name);
607 assert(false);
608 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800609 }
Andy McFadden0083d372009-08-21 14:44:04 -0700610
611 verifyCount++;
612 args++;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800613 }
614
615#ifndef NDEBUG
616 if (verifyCount != method->insSize) {
617 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
618 method->insSize, clazz->descriptor, method->name);
619 assert(false);
620 goto bail;
621 }
622#endif
623
624 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700625 TRACE_METHOD_ENTER(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800626 /*
627 * Because we leave no space for local variables, "curFrame" points
628 * directly at the method arguments.
629 */
630 (*method->nativeFunc)(self->curFrame, pResult, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700631 TRACE_METHOD_EXIT(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800632 } else {
633 dvmInterpret(self, method, pResult);
634 }
635
636bail:
637 dvmPopFrame(self);
638}
639
Elliott Hughes07946cf2010-12-03 17:59:32 -0800640static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected,
641 DataObject* arg)
642{
643 char* expectedClassName = dvmHumanReadableDescriptor(expected->descriptor);
644 char* actualClassName = (arg != NULL)
645 ? dvmHumanReadableDescriptor(arg->obj.clazz->descriptor)
646 : strdup("null");
647 dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
648 "argument %d should have type %s, got %s",
649 argIndex + 1, expectedClassName, actualClassName);
650 free(expectedClassName);
651 free(actualClassName);
652}
653
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800654/*
655 * Invoke a method, using the specified arguments and return type, through
656 * one of the reflection interfaces. Could be a virtual or direct method
657 * (including constructors). Used for reflection.
658 *
659 * Deals with boxing/unboxing primitives and performs widening conversions.
660 *
661 * "invokeObj" will be null for a static method.
662 *
663 * If the invocation returns with an exception raised, we have to wrap it.
664 */
665Object* dvmInvokeMethod(Object* obj, const Method* method,
666 ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
667 bool noAccessCheck)
668{
669 ClassObject* clazz;
670 Object* retObj = NULL;
671 Thread* self = dvmThreadSelf();
672 s4* ins;
673 int verifyCount, argListLength;
674 JValue retval;
Andy McFaddenbe420e72010-10-18 13:28:31 -0700675 bool needPop = false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800676
677 /* verify arg count */
678 if (argList != NULL)
679 argListLength = argList->length;
680 else
681 argListLength = 0;
682 if (argListLength != (int) params->length) {
Elliott Hughes07946cf2010-12-03 17:59:32 -0800683 dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
684 "wrong number of arguments; expected %d, got %d",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800685 params->length, argListLength);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800686 return NULL;
687 }
688
689 clazz = callPrep(self, method, obj, !noAccessCheck);
690 if (clazz == NULL)
691 return NULL;
Andy McFaddenbe420e72010-10-18 13:28:31 -0700692 needPop = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800693
694 /* "ins" for new frame start at frame pointer plus locals */
695 ins = ((s4*)self->curFrame) + (method->registersSize - method->insSize);
696 verifyCount = 0;
697
698 //LOGD(" FP is %p, INs live at >= %p\n", self->curFrame, ins);
699
700 /* put "this" pointer into in0 if appropriate */
701 if (!dvmIsStaticMethod(method)) {
702 assert(obj != NULL);
703 *ins++ = (s4) obj;
704 verifyCount++;
705 }
706
707 /*
708 * Copy the args onto the stack. Primitive types are converted when
709 * necessary, and object types are verified.
710 */
711 DataObject** args;
712 ClassObject** types;
713 int i;
714
715 args = (DataObject**) argList->contents;
716 types = (ClassObject**) params->contents;
717 for (i = 0; i < argListLength; i++) {
718 int width;
719
720 width = dvmConvertArgument(*args++, *types++, ins);
721 if (width < 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800722 dvmPopFrame(self); // throw wants to pull PC out of stack
Andy McFaddenbe420e72010-10-18 13:28:31 -0700723 needPop = false;
Elliott Hughes07946cf2010-12-03 17:59:32 -0800724 throwArgumentTypeMismatch(i, *(types-1), *(args-1));
Andy McFaddenbe420e72010-10-18 13:28:31 -0700725 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800726 }
727
728 ins += width;
729 verifyCount += width;
730 }
731
Andy McFaddenc4ae06f2010-11-04 12:37:51 -0700732#ifndef NDEBUG
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800733 if (verifyCount != method->insSize) {
734 LOGE("Got vfycount=%d insSize=%d for %s.%s\n", verifyCount,
735 method->insSize, clazz->descriptor, method->name);
736 assert(false);
737 goto bail;
738 }
Andy McFaddenc4ae06f2010-11-04 12:37:51 -0700739#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800740
741 if (dvmIsNativeMethod(method)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700742 TRACE_METHOD_ENTER(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800743 /*
744 * Because we leave no space for local variables, "curFrame" points
745 * directly at the method arguments.
746 */
747 (*method->nativeFunc)(self->curFrame, &retval, method, self);
The Android Open Source Project99409882009-03-18 22:20:24 -0700748 TRACE_METHOD_EXIT(self, method);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800749 } else {
750 dvmInterpret(self, method, &retval);
751 }
752
753 /*
Andy McFaddenbe420e72010-10-18 13:28:31 -0700754 * Pop the frame immediately. The "wrap" calls below can cause
755 * allocations, and we don't want the GC to walk the now-dead frame.
756 */
757 dvmPopFrame(self);
758 needPop = false;
759
760 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800761 * If an exception is raised, wrap and replace. This is necessary
762 * because the invoked method could have thrown a checked exception
763 * that the caller wasn't prepared for.
764 *
765 * We might be able to do this up in the interpreted code, but that will
766 * leave us with a shortened stack trace in the top-level exception.
767 */
768 if (dvmCheckException(self)) {
769 dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
770 } else {
771 /*
772 * If this isn't a void method or constructor, convert the return type
773 * to an appropriate object.
774 *
775 * We don't do this when an exception is raised because the value
776 * in "retval" is undefined.
777 */
778 if (returnType != NULL) {
Andy McFaddenc4ae06f2010-11-04 12:37:51 -0700779 retObj = (Object*)dvmBoxPrimitive(retval, returnType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780 dvmReleaseTrackedAlloc(retObj, NULL);
781 }
782 }
783
784bail:
Andy McFaddenbe420e72010-10-18 13:28:31 -0700785 if (needPop) {
786 dvmPopFrame(self);
787 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800788 return retObj;
789}
790
791typedef struct LineNumFromPcContext {
792 u4 address;
793 u4 lineNum;
794} LineNumFromPcContext;
795
796static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
797{
798 LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
799
Carl Shapirode750892010-06-08 16:37:12 -0700800 // We know that this callback will be called in
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800801 // ascending address order, so keep going until we find
802 // a match or we've just gone past it.
803
804 if (address > pContext->address) {
805 // The line number from the previous positions callback
806 // wil be the final result.
807 return 1;
808 }
809
810 pContext->lineNum = lineNum;
811
812 return (address == pContext->address) ? 1 : 0;
813}
814
815/*
816 * Determine the source file line number based on the program counter.
817 * "pc" is an offset, in 16-bit units, from the start of the method's code.
818 *
819 * Returns -1 if no match was found (possibly because the source files were
820 * compiled without "-g", so no line number information is present).
821 * Returns -2 for native methods (as expected in exception traces).
822 */
823int dvmLineNumFromPC(const Method* method, u4 relPc)
824{
825 const DexCode* pDexCode = dvmGetMethodCode(method);
826
827 if (pDexCode == NULL) {
828 if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
829 return -2;
830 return -1; /* can happen for abstract method stub */
831 }
832
833 LineNumFromPcContext context;
834 memset(&context, 0, sizeof(context));
835 context.address = relPc;
836 // A method with no line number info should return -1
837 context.lineNum = -1;
838
839 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
840 method->clazz->descriptor,
841 method->prototype.protoIdx,
842 method->accessFlags,
843 lineNumForPcCb, NULL, &context);
Carl Shapirode750892010-06-08 16:37:12 -0700844
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800845 return context.lineNum;
846}
847
848/*
849 * Compute the frame depth.
850 *
851 * Excludes "break" frames.
852 */
853int dvmComputeExactFrameDepth(const void* fp)
854{
855 int count = 0;
856
857 for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
858 if (!dvmIsBreakFrame(fp))
859 count++;
860 }
861
862 return count;
863}
864
865/*
866 * Compute the "vague" frame depth, which is just a pointer subtraction.
867 * The result is NOT an overly generous assessment of the number of
868 * frames; the only meaningful use is to compare against the result of
869 * an earlier invocation.
870 *
871 * Useful for implementing single-step debugger modes, which may need to
872 * call this for every instruction.
873 */
874int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
875{
876 const u1* interpStackStart = thread->interpStackStart;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800877
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700878 assert((u1*) fp >= interpStackStart - thread->interpStackSize);
879 assert((u1*) fp < interpStackStart);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800880 return interpStackStart - (u1*) fp;
881}
882
883/*
884 * Get the calling frame. Pass in the current fp.
885 *
886 * Skip "break" frames and reflection invoke frames.
887 */
888void* dvmGetCallerFP(const void* curFrame)
889{
890 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
891 StackSaveArea* saveArea;
892
893retry:
894 if (dvmIsBreakFrame(caller)) {
895 /* pop up one more */
896 caller = SAVEAREA_FROM_FP(caller)->prevFrame;
897 if (caller == NULL)
898 return NULL; /* hit the top */
899
900 /*
901 * If we got here by java.lang.reflect.Method.invoke(), we don't
902 * want to return Method's class loader. Shift up one and try
903 * again.
904 */
905 saveArea = SAVEAREA_FROM_FP(caller);
906 if (dvmIsReflectionMethod(saveArea->method)) {
907 caller = saveArea->prevFrame;
908 assert(caller != NULL);
909 goto retry;
910 }
911 }
912
913 return caller;
914}
915
916/*
917 * Get the caller's class. Pass in the current fp.
918 *
919 * This is used by e.g. java.lang.Class.
920 */
921ClassObject* dvmGetCallerClass(const void* curFrame)
922{
923 void* caller;
924
925 caller = dvmGetCallerFP(curFrame);
926 if (caller == NULL)
927 return NULL;
928
929 return SAVEAREA_FROM_FP(caller)->method->clazz;
930}
931
932/*
933 * Get the caller's caller's class. Pass in the current fp.
934 *
935 * This is used by e.g. java.lang.Class, which wants to know about the
936 * class loader of the method that called it.
937 */
938ClassObject* dvmGetCaller2Class(const void* curFrame)
939{
940 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
941 void* callerCaller;
942
943 /* at the top? */
944 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
945 return NULL;
946
947 /* go one more */
948 callerCaller = dvmGetCallerFP(caller);
949 if (callerCaller == NULL)
950 return NULL;
951
952 return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
953}
954
955/*
956 * Get the caller's caller's caller's class. Pass in the current fp.
957 *
958 * This is used by e.g. java.lang.Class, which wants to know about the
959 * class loader of the method that called it.
960 */
961ClassObject* dvmGetCaller3Class(const void* curFrame)
962{
963 void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
964 int i;
965
966 /* at the top? */
967 if (dvmIsBreakFrame(caller) && SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
968 return NULL;
969
970 /* Walk up two frames if possible. */
971 for (i = 0; i < 2; i++) {
972 caller = dvmGetCallerFP(caller);
973 if (caller == NULL)
974 return NULL;
975 }
Carl Shapirode750892010-06-08 16:37:12 -0700976
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800977 return SAVEAREA_FROM_FP(caller)->method->clazz;
978}
979
980/*
981 * Create a flat array of methods that comprise the current interpreter
982 * stack trace. Pass in the current frame ptr.
983 *
984 * Allocates a new array and fills it with method pointers. Break frames
985 * are skipped, but reflection invocations are not. The caller must free
986 * "*pArray".
987 *
988 * The current frame will be in element 0.
989 *
990 * Returns "true" on success, "false" on failure (e.g. malloc failed).
991 */
992bool dvmCreateStackTraceArray(const void* fp, const Method*** pArray,
993 int* pLength)
994{
995 const Method** array;
996 int idx, depth;
997
998 depth = dvmComputeExactFrameDepth(fp);
999 array = (const Method**) malloc(depth * sizeof(Method*));
1000 if (array == NULL)
1001 return false;
1002
1003 for (idx = 0; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
1004 if (!dvmIsBreakFrame(fp))
1005 array[idx++] = SAVEAREA_FROM_FP(fp)->method;
1006 }
1007 assert(idx == depth);
1008
1009 *pArray = array;
1010 *pLength = depth;
1011 return true;
1012}
1013
1014/*
1015 * Open up the reserved area and throw an exception. The reserved area
1016 * should only be needed to create and initialize the exception itself.
1017 *
1018 * If we already opened it and we're continuing to overflow, abort the VM.
1019 *
1020 * We have to leave the "reserved" area open until the "catch" handler has
1021 * finished doing its processing. This is because the catch handler may
1022 * need to resolve classes, which requires calling into the class loader if
1023 * the classes aren't already in the "initiating loader" list.
1024 */
Andy McFadden6ed1a0f2009-09-10 15:34:19 -07001025void dvmHandleStackOverflow(Thread* self, const Method* method)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026{
1027 /*
1028 * Can we make the reserved area available?
1029 */
1030 if (self->stackOverflowed) {
1031 /*
1032 * Already did, nothing to do but bail.
1033 */
1034 LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting\n",
1035 self->threadId);
1036 dvmDumpThread(self, false);
1037 dvmAbort();
1038 }
1039
1040 /* open it up to the full range */
Andy McFadden6ed1a0f2009-09-10 15:34:19 -07001041 LOGI("threadid=%d: stack overflow on call to %s.%s:%s\n",
1042 self->threadId,
1043 method->clazz->descriptor, method->name, method->shorty);
1044 StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->curFrame);
1045 LOGI(" method requires %d+%d+%d=%d bytes, fp is %p (%d left)\n",
1046 method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1047 (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1048 saveArea, (u1*) saveArea - self->interpStackEnd);
1049 LOGI(" expanding stack end (%p to %p)\n", self->interpStackEnd,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001050 self->interpStackStart - self->interpStackSize);
1051 //dvmDumpThread(self, false);
1052 self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1053 self->stackOverflowed = true;
1054
1055 /*
1056 * If we were trying to throw an exception when the stack overflowed,
1057 * we will blow up when doing the class lookup on StackOverflowError
1058 * because of the pending exception. So, we clear it and make it
1059 * the cause of the SOE.
1060 */
1061 Object* excep = dvmGetException(self);
1062 if (excep != NULL) {
1063 LOGW("Stack overflow while throwing exception\n");
1064 dvmClearException(self);
1065 }
Andy McFadden4fbba1f2010-02-03 07:21:14 -08001066 dvmThrowChainedExceptionByClass(gDvm.classJavaLangStackOverflowError,
1067 NULL, excep);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068}
1069
1070/*
1071 * Reduce the available stack size. By this point we should have finished
1072 * our overflow processing.
1073 */
Andy McFadden4fbba1f2010-02-03 07:21:14 -08001074void dvmCleanupStackOverflow(Thread* self, const Object* exception)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001075{
1076 const u1* newStackEnd;
1077
1078 assert(self->stackOverflowed);
1079
Andy McFadden4fbba1f2010-02-03 07:21:14 -08001080 if (exception->clazz != gDvm.classJavaLangStackOverflowError) {
1081 /* exception caused during SOE, not the SOE itself */
1082 return;
1083 }
1084
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001085 newStackEnd = (self->interpStackStart - self->interpStackSize)
1086 + STACK_OVERFLOW_RESERVE;
1087 if ((u1*)self->curFrame <= newStackEnd) {
1088 LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)\n",
1089 self->interpStackEnd, self->curFrame);
1090 dvmDumpThread(self, false);
1091 dvmAbort();
1092 }
1093
1094 self->interpStackEnd = newStackEnd;
1095 self->stackOverflowed = false;
1096
1097 LOGI("Shrank stack (to %p, curFrame is %p)\n", self->interpStackEnd,
1098 self->curFrame);
1099}
1100
1101
1102/*
Andy McFaddenfd542662010-03-12 13:39:59 -08001103 * Extract the object that is the target of a monitor-enter instruction
1104 * in the top stack frame of "thread".
1105 *
1106 * The other thread might be alive, so this has to work carefully.
1107 *
Andy McFaddend19988d2010-10-22 13:32:12 -07001108 * The thread list lock must be held.
Andy McFaddenfd542662010-03-12 13:39:59 -08001109 *
1110 * Returns "true" if we successfully recover the object. "*pOwner" will
1111 * be NULL if we can't determine the owner for some reason (e.g. race
1112 * condition on ownership transfer).
1113 */
1114static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1115 Thread** pOwner)
1116{
1117 void* framePtr = thread->curFrame;
1118
1119 if (framePtr == NULL || dvmIsBreakFrame(framePtr))
1120 return false;
1121
1122 const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1123 const Method* method = saveArea->method;
1124 const u2* currentPc = saveArea->xtra.currentPc;
1125
1126 /* check Method* */
1127 if (!dvmLinearAllocContains(method, sizeof(Method))) {
1128 LOGD("ExtrMon: method %p not valid\n", method);
1129 return false;
1130 }
1131
1132 /* check currentPc */
1133 u4 insnsSize = dvmGetMethodInsnsSize(method);
1134 if (currentPc < method->insns ||
1135 currentPc >= method->insns + insnsSize)
1136 {
1137 LOGD("ExtrMon: insns %p not valid (%p - %p)\n",
1138 currentPc, method->insns, method->insns + insnsSize);
1139 return false;
1140 }
1141
1142 /* check the instruction */
1143 if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1144 LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)\n",
1145 currentPc, *currentPc & 0xff);
1146 return false;
1147 }
1148
1149 /* get and check the register index */
1150 unsigned int reg = *currentPc >> 8;
1151 if (reg >= method->registersSize) {
1152 LOGD("ExtrMon: invalid register %d (max %d)\n",
1153 reg, method->registersSize);
1154 return false;
1155 }
1156
1157 /* get and check the object in that register */
1158 u4* fp = (u4*) framePtr;
1159 Object* obj = (Object*) fp[reg];
1160 if (!dvmIsValidObject(obj)) {
1161 LOGD("ExtrMon: invalid object %p at %p[%d]\n", obj, fp, reg);
1162 return false;
1163 }
1164 *pLockObj = obj;
1165
1166 /*
1167 * Try to determine the object's lock holder; it's okay if this fails.
1168 *
1169 * We're assuming the thread list lock is already held by this thread.
1170 * If it's not, we may be living dangerously if we have to scan through
1171 * the thread list to find a match. (The VM will generally be in a
1172 * suspended state when executing here, so this is a minor concern
1173 * unless we're dumping while threads are running, in which case there's
1174 * a good chance of stuff blowing up anyway.)
1175 */
1176 *pOwner = dvmGetObjectLockHolder(obj);
1177
1178 return true;
1179}
1180
1181/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001182 * Dump stack frames, starting from the specified frame and moving down.
1183 *
1184 * Each frame holds a pointer to the currently executing method, and the
1185 * saved program counter from the caller ("previous" frame). This means
1186 * we don't have the PC for the current method on the stack, which is
1187 * pretty reasonable since it's in the "PC register" for the VM. Because
1188 * exceptions need to show the correct line number we actually *do* have
1189 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1190 *
1191 * Note "framePtr" could be NULL in rare circumstances.
1192 */
1193static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1194 Thread* thread)
1195{
1196 const StackSaveArea* saveArea;
1197 const Method* method;
1198 int checkCount = 0;
1199 const u2* currentPc = NULL;
1200 bool first = true;
1201
1202 /*
Andy McFaddend19988d2010-10-22 13:32:12 -07001203 * We call functions that require us to be holding the thread list lock.
1204 * It's probable that the caller has already done so, but it's not
1205 * guaranteed. If it's not locked, lock it now.
1206 */
1207 bool needThreadUnlock = dvmTryLockThreadList();
1208
1209 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001210 * The "currentPc" is updated whenever we execute an instruction that
1211 * might throw an exception. Show it here.
1212 */
1213 if (framePtr != NULL && !dvmIsBreakFrame(framePtr)) {
1214 saveArea = SAVEAREA_FROM_FP(framePtr);
1215
1216 if (saveArea->xtra.currentPc != NULL)
1217 currentPc = saveArea->xtra.currentPc;
1218 }
1219
1220 while (framePtr != NULL) {
1221 saveArea = SAVEAREA_FROM_FP(framePtr);
1222 method = saveArea->method;
1223
1224 if (dvmIsBreakFrame(framePtr)) {
1225 //dvmPrintDebugMessage(target, " (break frame)\n");
1226 } else {
1227 int relPc;
1228
1229 if (currentPc != NULL)
1230 relPc = currentPc - saveArea->method->insns;
1231 else
1232 relPc = -1;
1233
Elliott Hughes50169662010-11-22 13:14:23 -08001234 char* className = dvmHumanReadableDescriptor(method->clazz->descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001235 if (dvmIsNativeMethod(method))
1236 dvmPrintDebugMessage(target,
1237 " at %s.%s(Native Method)\n", className, method->name);
1238 else {
1239 dvmPrintDebugMessage(target,
1240 " at %s.%s(%s:%s%d)\n",
1241 className, method->name, dvmGetMethodSourceFile(method),
1242 (relPc >= 0 && first) ? "~" : "",
1243 relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1244 }
1245 free(className);
1246
Andy McFaddenfd542662010-03-12 13:39:59 -08001247 if (first) {
1248 /*
1249 * Decorate WAIT and MONITOR threads with some detail on
1250 * the first frame.
1251 *
1252 * warning: wait status not stable, even in suspend
1253 */
1254 if (thread->status == THREAD_WAIT ||
1255 thread->status == THREAD_TIMED_WAIT)
1256 {
1257 Monitor* mon = thread->waitMonitor;
1258 Object* obj = dvmGetMonitorObject(mon);
1259 if (obj != NULL) {
Andy McFaddend19988d2010-10-22 13:32:12 -07001260 Thread* joinThread = NULL;
Elliott Hughes50169662010-11-22 13:14:23 -08001261 className = dvmHumanReadableDescriptor(obj->clazz->descriptor);
Andy McFaddend19988d2010-10-22 13:32:12 -07001262 if (strcmp(className, "java.lang.VMThread") == 0) {
1263 joinThread = dvmGetThreadFromThreadObject(obj);
1264 }
1265 if (joinThread == NULL) {
1266 dvmPrintDebugMessage(target,
1267 " - waiting on <%p> (a %s)\n", obj, className);
1268 } else {
1269 dvmPrintDebugMessage(target,
1270 " - waiting on <%p> (a %s) tid=%d\n",
1271 obj, className, joinThread->threadId);
1272 }
Andy McFaddenfd542662010-03-12 13:39:59 -08001273 free(className);
1274 }
1275 } else if (thread->status == THREAD_MONITOR) {
1276 Object* obj;
1277 Thread* owner;
1278 if (extractMonitorEnterObject(thread, &obj, &owner)) {
Elliott Hughes50169662010-11-22 13:14:23 -08001279 className = dvmHumanReadableDescriptor(obj->clazz->descriptor);
Andy McFaddenfd542662010-03-12 13:39:59 -08001280 if (owner != NULL) {
1281 char* threadName = dvmGetThreadName(owner);
1282 dvmPrintDebugMessage(target,
1283 " - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
1284 obj, className, owner->threadId, threadName);
1285 free(threadName);
1286 } else {
1287 dvmPrintDebugMessage(target,
1288 " - waiting to lock <%p> (a %s) held by ???\n",
1289 obj, className);
1290 }
1291 free(className);
1292 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001293 }
1294 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001295 }
1296
1297 /*
1298 * Get saved PC for previous frame. There's no savedPc in a "break"
1299 * frame, because that represents native or interpreted code
1300 * invoked by the VM. The saved PC is sitting in the "PC register",
1301 * a local variable on the native stack.
1302 */
1303 currentPc = saveArea->savedPc;
1304
1305 first = false;
1306
Andy McFadden0083d372009-08-21 14:44:04 -07001307 if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1308 LOGW("Warning: loop in stack trace at frame %d (%p -> %p)\n",
1309 checkCount, framePtr, saveArea->prevFrame);
1310 break;
1311 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001312 framePtr = saveArea->prevFrame;
1313
1314 checkCount++;
Andy McFadden0083d372009-08-21 14:44:04 -07001315 if (checkCount > 300) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001316 dvmPrintDebugMessage(target,
1317 " ***** printed %d frames, not showing any more\n",
1318 checkCount);
1319 break;
1320 }
1321 }
1322 dvmPrintDebugMessage(target, "\n");
Andy McFaddend19988d2010-10-22 13:32:12 -07001323
1324 if (needThreadUnlock) {
1325 dvmUnlockThreadList();
1326 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001327}
1328
1329
1330/*
1331 * Dump the stack for the specified thread.
1332 */
1333void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1334{
1335 dumpFrames(target, thread->curFrame, thread);
1336}
1337
1338/*
1339 * Dump the stack for the specified thread, which is still running.
1340 *
1341 * This is very dangerous, because stack frames are being pushed on and
1342 * popped off, and if the thread exits we'll be looking at freed memory.
1343 * The plan here is to take a snapshot of the stack and then dump that
1344 * to try to minimize the chances of catching it mid-update. This should
1345 * work reasonably well on a single-CPU system.
1346 *
1347 * There is a small chance that calling here will crash the VM.
1348 */
1349void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1350{
1351 StackSaveArea* saveArea;
1352 const u1* origStack;
1353 u1* stackCopy = NULL;
1354 int origSize, fpOffset;
1355 void* fp;
1356 int depthLimit = 200;
1357
1358 if (thread == NULL || thread->curFrame == NULL) {
1359 dvmPrintDebugMessage(target,
1360 "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1361 thread, (thread != NULL) ? thread->threadId : 0);
1362 return;
1363 }
1364
1365 /* wait for a full quantum */
1366 sched_yield();
1367
1368 /* copy the info we need, then the stack itself */
1369 origSize = thread->interpStackSize;
1370 origStack = (const u1*) thread->interpStackStart - origSize;
1371 stackCopy = (u1*) malloc(origSize);
1372 fpOffset = (u1*) thread->curFrame - origStack;
1373 memcpy(stackCopy, origStack, origSize);
1374
1375 /*
1376 * Run through the stack and rewrite the "prev" pointers.
1377 */
1378 //LOGI("DR: fpOff=%d (from %p %p)\n",fpOffset, origStack, thread->curFrame);
1379 fp = stackCopy + fpOffset;
1380 while (true) {
1381 int prevOffset;
1382
1383 if (depthLimit-- < 0) {
1384 /* we're probably screwed */
1385 dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1386 dvmAbort();
1387 }
1388 saveArea = SAVEAREA_FROM_FP(fp);
1389 if (saveArea->prevFrame == NULL)
1390 break;
1391
1392 prevOffset = (u1*) saveArea->prevFrame - origStack;
1393 if (prevOffset < 0 || prevOffset > origSize) {
1394 dvmPrintDebugMessage(target,
1395 "DumpRunning: bad offset found: %d (from %p %p)\n",
1396 prevOffset, origStack, saveArea->prevFrame);
1397 saveArea->prevFrame = NULL;
1398 break;
1399 }
1400
1401 saveArea->prevFrame = stackCopy + prevOffset;
1402 fp = saveArea->prevFrame;
1403 }
1404
1405 /*
1406 * We still need to pass the Thread for some monitor wait stuff.
1407 */
1408 dumpFrames(target, stackCopy + fpOffset, thread);
1409 free(stackCopy);
1410}