Home | History | Annotate | Download | only in interp
      1 /*
      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 /*
     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  */
     34 bool dvmInitInterpStack(Thread* thread, int stackSize)
     35 {
     36     assert(thread->interpStackStart != NULL);
     37 
     38     assert(thread->interpSave.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  */
     59 static 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->interpSave.curFrame != NULL)
     74         stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
     75     else
     76         stackPtr = self->interpStackStart;
     77 
     78     if (stackPtr - stackReq < self->interpStackEnd) {
     79         /* not enough space */
     80         LOGW("Stack overflow on call to interp "
     81              "(req=%d top=%p cur=%p size=%d %s.%s)",
     82             stackReq, self->interpStackStart, self->interpSave.curFrame,
     83             self->interpStackSize, method->clazz->descriptor, method->name);
     84         dvmHandleStackOverflow(self, method);
     85         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 =
    104        (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
    105     saveBlock->prevSave = breakSaveBlock;
    106 #endif
    107 
    108     breakSaveBlock->prevFrame = self->interpSave.curFrame;
    109     breakSaveBlock->savedPc = NULL;             // not required
    110     breakSaveBlock->xtra.localRefCookie = 0;    // not required
    111     breakSaveBlock->method = NULL;
    112     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
    113     saveBlock->savedPc = NULL;                  // not required
    114     saveBlock->xtra.currentPc = NULL;           // not required?
    115     saveBlock->method = method;
    116 
    117     LOGVV("PUSH frame: old=%p new=%p (size=%d)",
    118         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
    119         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
    120 
    121     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
    122 
    123     return true;
    124 }
    125 
    126 /*
    127  * We're calling a JNI native method from an internal VM fuction or
    128  * via reflection.  This is also used to create the "fake" native-method
    129  * frames at the top of the interpreted stack.
    130  *
    131  * This actually pushes two frames; the first is a "break" frame.
    132  *
    133  * The top frame has additional space for JNI local reference tracking.
    134  */
    135 bool dvmPushJNIFrame(Thread* self, const Method* method)
    136 {
    137     StackSaveArea* saveBlock;
    138     StackSaveArea* breakSaveBlock;
    139     int stackReq;
    140     u1* stackPtr;
    141 
    142     assert(dvmIsNativeMethod(method));
    143 
    144     stackReq = method->registersSize * 4        // params only
    145                 + sizeof(StackSaveArea) * 2;    // break frame + regular frame
    146 
    147     if (self->interpSave.curFrame != NULL)
    148         stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
    149     else
    150         stackPtr = self->interpStackStart;
    151 
    152     if (stackPtr - stackReq < self->interpStackEnd) {
    153         /* not enough space */
    154         LOGW("Stack overflow on call to native "
    155              "(req=%d top=%p cur=%p size=%d '%s')",
    156             stackReq, self->interpStackStart, self->interpSave.curFrame,
    157             self->interpStackSize, method->name);
    158         dvmHandleStackOverflow(self, method);
    159         assert(dvmCheckException(self));
    160         return false;
    161     }
    162 
    163     /*
    164      * Shift the stack pointer down, leaving space for just the stack save
    165      * area for the break frame, then shift down farther for the full frame.
    166      * We leave space for the method args, which are copied in later.
    167      */
    168     stackPtr -= sizeof(StackSaveArea);
    169     breakSaveBlock = (StackSaveArea*)stackPtr;
    170     stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
    171     saveBlock = (StackSaveArea*) stackPtr;
    172 
    173 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
    174     /* debug -- memset the new stack */
    175     memset(stackPtr, 0xaf, stackReq);
    176 #endif
    177 #ifdef EASY_GDB
    178     if (self->interpSave.curFrame == NULL)
    179         breakSaveBlock->prevSave = NULL;
    180     else {
    181         void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame);
    182         breakSaveBlock->prevSave = (StackSaveArea*)fp;
    183     }
    184     saveBlock->prevSave = breakSaveBlock;
    185 #endif
    186 
    187     breakSaveBlock->prevFrame = self->interpSave.curFrame;
    188     breakSaveBlock->savedPc = NULL;             // not required
    189     breakSaveBlock->xtra.localRefCookie = 0;    // not required
    190     breakSaveBlock->method = NULL;
    191     saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
    192     saveBlock->savedPc = NULL;                  // not required
    193     saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
    194     saveBlock->method = method;
    195 
    196     LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)",
    197         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
    198         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
    199 
    200     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
    201 
    202     return true;
    203 }
    204 
    205 /*
    206  * This is used by the JNI PushLocalFrame call.  We push a new frame onto
    207  * the stack that has no ins, outs, or locals, and no break frame above it.
    208  * It's strictly used for tracking JNI local refs, and will be popped off
    209  * by dvmPopFrame if it's not removed explicitly.
    210  */
    211 bool dvmPushLocalFrame(Thread* self, const Method* method)
    212 {
    213     StackSaveArea* saveBlock;
    214     int stackReq;
    215     u1* stackPtr;
    216 
    217     assert(dvmIsNativeMethod(method));
    218 
    219     stackReq = sizeof(StackSaveArea);       // regular frame
    220 
    221     assert(self->interpSave.curFrame != NULL);
    222     stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
    223 
    224     if (stackPtr - stackReq < self->interpStackEnd) {
    225         /* not enough space; let JNI throw the exception */
    226         LOGW("Stack overflow on PushLocal "
    227              "(req=%d top=%p cur=%p size=%d '%s')",
    228             stackReq, self->interpStackStart, self->interpSave.curFrame,
    229             self->interpStackSize, method->name);
    230         dvmHandleStackOverflow(self, method);
    231         assert(dvmCheckException(self));
    232         return false;
    233     }
    234 
    235     /*
    236      * Shift the stack pointer down, leaving space for just the stack save
    237      * area for the break frame, then shift down farther for the full frame.
    238      */
    239     stackPtr -= sizeof(StackSaveArea);
    240     saveBlock = (StackSaveArea*) stackPtr;
    241 
    242 #if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
    243     /* debug -- memset the new stack */
    244     memset(stackPtr, 0xaf, stackReq);
    245 #endif
    246 #ifdef EASY_GDB
    247     saveBlock->prevSave =
    248         (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
    249 #endif
    250 
    251     saveBlock->prevFrame = self->interpSave.curFrame;
    252     saveBlock->savedPc = NULL;                  // not required
    253     saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
    254     saveBlock->method = method;
    255 
    256     LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)",
    257         self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
    258         (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
    259 
    260     self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
    261 
    262     return true;
    263 }
    264 
    265 /*
    266  * Pop one frame pushed on by JNI PushLocalFrame.
    267  *
    268  * If we've gone too far, the previous frame is either a break frame or
    269  * an interpreted frame.  Either way, the method pointer won't match.
    270  */
    271 bool dvmPopLocalFrame(Thread* self)
    272 {
    273     StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
    274 
    275     assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
    276     if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
    277         /*
    278          * The previous frame doesn't have the same method pointer -- we've
    279          * been asked to pop too much.
    280          */
    281         assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) ||
    282                !dvmIsNativeMethod(
    283                        SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
    284         return false;
    285     }
    286 
    287     LOGVV("POP JNI local frame: removing %s, now %s",
    288         saveBlock->method->name,
    289         SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
    290     dvmPopJniLocals(self, saveBlock);
    291     self->interpSave.curFrame = saveBlock->prevFrame;
    292 
    293     return true;
    294 }
    295 
    296 /*
    297  * Pop a frame we added.  There should be one method frame and one break
    298  * frame.
    299  *
    300  * If JNI Push/PopLocalFrame calls were mismatched, we might end up
    301  * popping multiple method frames before we find the break.
    302  *
    303  * Returns "false" if there was no frame to pop.
    304  */
    305 static bool dvmPopFrame(Thread* self)
    306 {
    307     StackSaveArea* saveBlock;
    308 
    309     if (self->interpSave.curFrame == NULL)
    310         return false;
    311 
    312     saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
    313     assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
    314 
    315     /*
    316      * Remove everything up to the break frame.  If this was a call into
    317      * native code, pop the JNI local references table.
    318      */
    319     while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
    320         /* probably a native->native JNI call */
    321 
    322         if (dvmIsNativeMethod(saveBlock->method)) {
    323             LOGVV("Popping JNI stack frame for %s.%s%s",
    324                 saveBlock->method->clazz->descriptor,
    325                 saveBlock->method->name,
    326                 (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
    327                 "" : " (JNI local)");
    328             dvmPopJniLocals(self, saveBlock);
    329         }
    330 
    331         saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
    332     }
    333     if (saveBlock->method != NULL) {
    334         LOGE("PopFrame missed the break");
    335         assert(false);
    336         dvmAbort();     // stack trashed -- nowhere to go in this thread
    337     }
    338 
    339     LOGVV("POP frame: cur=%p new=%p",
    340         self->interpSave.curFrame, saveBlock->prevFrame);
    341 
    342     self->interpSave.curFrame = saveBlock->prevFrame;
    343     return true;
    344 }
    345 
    346 /*
    347  * Common code for dvmCallMethodV/A and dvmInvokeMethod.
    348  *
    349  * Pushes a call frame on, advancing self->interpSave.curFrame.
    350  */
    351 static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
    352     bool checkAccess)
    353 {
    354     ClassObject* clazz;
    355 
    356 #ifndef NDEBUG
    357     if (self->status != THREAD_RUNNING) {
    358         LOGW("threadid=%d: status=%d on call to %s.%s -",
    359             self->threadId, self->status,
    360             method->clazz->descriptor, method->name);
    361     }
    362 #endif
    363 
    364     assert(self != NULL);
    365     assert(method != NULL);
    366 
    367     if (obj != NULL)
    368         clazz = obj->clazz;
    369     else
    370         clazz = method->clazz;
    371 
    372     IF_LOGVV() {
    373         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
    374         LOGVV("thread=%d native code calling %s.%s %s", self->threadId,
    375             clazz->descriptor, method->name, desc);
    376         free(desc);
    377     }
    378 
    379     if (checkAccess) {
    380         /* needed for java.lang.reflect.Method.invoke */
    381         if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame),
    382                 method))
    383         {
    384             /* note this throws IAException, not IAError */
    385             dvmThrowIllegalAccessException("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->interpSave.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  */
    420 void dvmCallMethod(Thread* self, const Method* method, Object* obj,
    421     JValue* pResult, ...)
    422 {
    423     va_list args;
    424     va_start(args, pResult);
    425     dvmCallMethodV(self, method, obj, false, pResult, args);
    426     va_end(args);
    427 }
    428 
    429 /*
    430  * Issue a method call with a variable number of arguments.  We process
    431  * the contents of "args" by scanning the method signature.
    432  *
    433  * Pass in NULL for "obj" on calls to static methods.
    434  *
    435  * We don't need to take the class as an argument because, in Dalvik,
    436  * we don't need to worry about static synchronized methods.
    437  */
    438 void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
    439     bool fromJni, JValue* pResult, va_list args)
    440 {
    441     const char* desc = &(method->shorty[1]); // [0] is the return type.
    442     int verifyCount = 0;
    443     ClassObject* clazz;
    444     u4* ins;
    445 
    446     clazz = callPrep(self, method, obj, false);
    447     if (clazz == NULL)
    448         return;
    449 
    450     /* "ins" for new frame start at frame pointer plus locals */
    451     ins = ((u4*)self->interpSave.curFrame) +
    452            (method->registersSize - method->insSize);
    453 
    454     //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
    455 
    456     /* put "this" pointer into in0 if appropriate */
    457     if (!dvmIsStaticMethod(method)) {
    458 #ifdef WITH_EXTRA_OBJECT_VALIDATION
    459         assert(obj != NULL && dvmIsHeapAddress(obj));
    460 #endif
    461         *ins++ = (u4) obj;
    462         verifyCount++;
    463     }
    464 
    465     JNIEnv* env = self->jniEnv;
    466     while (*desc != '\0') {
    467         switch (*(desc++)) {
    468             case 'D': case 'J': {
    469                 u8 val = va_arg(args, u8);
    470                 memcpy(ins, &val, 8);       // EABI prevents direct store
    471                 ins += 2;
    472                 verifyCount += 2;
    473                 break;
    474             }
    475             case 'F': {
    476                 /* floats were normalized to doubles; convert back */
    477                 float f = (float) va_arg(args, double);
    478                 *ins++ = dvmFloatToU4(f);
    479                 verifyCount++;
    480                 break;
    481             }
    482             case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
    483                 void* arg = va_arg(args, void*);
    484                 assert(obj == NULL || dvmIsHeapAddress(obj));
    485                 jobject argObj = reinterpret_cast<jobject>(arg);
    486                 if (fromJni)
    487                     *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
    488                 else
    489                     *ins++ = (u4) argObj;
    490                 verifyCount++;
    491                 break;
    492             }
    493             default: {
    494                 /* Z B C S I -- all passed as 32-bit integers */
    495                 *ins++ = va_arg(args, u4);
    496                 verifyCount++;
    497                 break;
    498             }
    499         }
    500     }
    501 
    502 #ifndef NDEBUG
    503     if (verifyCount != method->insSize) {
    504         LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
    505             method->insSize, clazz->descriptor, method->name);
    506         assert(false);
    507         goto bail;
    508     }
    509 #endif
    510 
    511     //dvmDumpThreadStack(dvmThreadSelf());
    512 
    513     if (dvmIsNativeMethod(method)) {
    514         TRACE_METHOD_ENTER(self, method);
    515         /*
    516          * Because we leave no space for local variables, "curFrame" points
    517          * directly at the method arguments.
    518          */
    519         (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
    520                               method, self);
    521         TRACE_METHOD_EXIT(self, method);
    522     } else {
    523         dvmInterpret(self, method, pResult);
    524     }
    525 
    526 #ifndef NDEBUG
    527 bail:
    528 #endif
    529     dvmPopFrame(self);
    530 }
    531 
    532 /*
    533  * Issue a method call with arguments provided in an array.  We process
    534  * the contents of "args" by scanning the method signature.
    535  *
    536  * The values were likely placed into an uninitialized jvalue array using
    537  * the field specifiers, which means that sub-32-bit fields (e.g. short,
    538  * boolean) may not have 32 or 64 bits of valid data.  This is different
    539  * from the varargs invocation where the C compiler does a widening
    540  * conversion when calling a function.  As a result, we have to be a
    541  * little more precise when pulling stuff out.
    542  *
    543  * "args" may be NULL if the method has no arguments.
    544  */
    545 void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
    546     bool fromJni, JValue* pResult, const jvalue* args)
    547 {
    548     const char* desc = &(method->shorty[1]); // [0] is the return type.
    549     int verifyCount = 0;
    550     ClassObject* clazz;
    551     u4* ins;
    552 
    553     clazz = callPrep(self, method, obj, false);
    554     if (clazz == NULL)
    555         return;
    556 
    557     /* "ins" for new frame start at frame pointer plus locals */
    558     ins = ((u4*)self->interpSave.curFrame) +
    559         (method->registersSize - method->insSize);
    560 
    561     /* put "this" pointer into in0 if appropriate */
    562     if (!dvmIsStaticMethod(method)) {
    563         assert(obj != NULL);
    564         *ins++ = (u4) obj;              /* obj is a "real" ref */
    565         verifyCount++;
    566     }
    567 
    568     JNIEnv* env = self->jniEnv;
    569     while (*desc != '\0') {
    570         switch (*desc++) {
    571         case 'D':                       /* 64-bit quantity; have to use */
    572         case 'J':                       /*  memcpy() in case of mis-alignment */
    573             memcpy(ins, &args->j, 8);
    574             ins += 2;
    575             verifyCount++;              /* this needs an extra push */
    576             break;
    577         case 'L':                       /* includes array refs */
    578             if (fromJni)
    579                 *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
    580             else
    581                 *ins++ = (u4) args->l;
    582             break;
    583         case 'F':
    584         case 'I':
    585             *ins++ = args->i;           /* full 32 bits */
    586             break;
    587         case 'S':
    588             *ins++ = args->s;           /* 16 bits, sign-extended */
    589             break;
    590         case 'C':
    591             *ins++ = args->c;           /* 16 bits, unsigned */
    592             break;
    593         case 'B':
    594             *ins++ = args->b;           /* 8 bits, sign-extended */
    595             break;
    596         case 'Z':
    597             *ins++ = args->z;           /* 8 bits, zero or non-zero */
    598             break;
    599         default:
    600             LOGE("Invalid char %c in short signature of %s.%s",
    601                 *(desc-1), clazz->descriptor, method->name);
    602             assert(false);
    603             goto bail;
    604         }
    605 
    606         verifyCount++;
    607         args++;
    608     }
    609 
    610 #ifndef NDEBUG
    611     if (verifyCount != method->insSize) {
    612         LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
    613             method->insSize, clazz->descriptor, method->name);
    614         assert(false);
    615         goto bail;
    616     }
    617 #endif
    618 
    619     if (dvmIsNativeMethod(method)) {
    620         TRACE_METHOD_ENTER(self, method);
    621         /*
    622          * Because we leave no space for local variables, "curFrame" points
    623          * directly at the method arguments.
    624          */
    625         (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
    626                               method, self);
    627         TRACE_METHOD_EXIT(self, method);
    628     } else {
    629         dvmInterpret(self, method, pResult);
    630     }
    631 
    632 bail:
    633     dvmPopFrame(self);
    634 }
    635 
    636 static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
    637     std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
    638     std::string actualClassName = dvmHumanReadableType(arg);
    639     dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
    640             argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
    641 }
    642 
    643 /*
    644  * Invoke a method, using the specified arguments and return type, through
    645  * one of the reflection interfaces.  Could be a virtual or direct method
    646  * (including constructors).  Used for reflection.
    647  *
    648  * Deals with boxing/unboxing primitives and performs widening conversions.
    649  *
    650  * "invokeObj" will be null for a static method.
    651  *
    652  * If the invocation returns with an exception raised, we have to wrap it.
    653  */
    654 Object* dvmInvokeMethod(Object* obj, const Method* method,
    655     ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
    656     bool noAccessCheck)
    657 {
    658     ClassObject* clazz;
    659     Object* retObj = NULL;
    660     Thread* self = dvmThreadSelf();
    661     s4* ins;
    662     int verifyCount, argListLength;
    663     JValue retval;
    664     bool needPop = false;
    665 
    666     /* verify arg count */
    667     if (argList != NULL)
    668         argListLength = argList->length;
    669     else
    670         argListLength = 0;
    671     if (argListLength != (int) params->length) {
    672         dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
    673             "wrong number of arguments; expected %d, got %d",
    674             params->length, argListLength);
    675         return NULL;
    676     }
    677 
    678     clazz = callPrep(self, method, obj, !noAccessCheck);
    679     if (clazz == NULL)
    680         return NULL;
    681     needPop = true;
    682 
    683     /* "ins" for new frame start at frame pointer plus locals */
    684     ins = ((s4*)self->interpSave.curFrame) +
    685         (method->registersSize - method->insSize);
    686     verifyCount = 0;
    687 
    688     //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
    689 
    690     /* put "this" pointer into in0 if appropriate */
    691     if (!dvmIsStaticMethod(method)) {
    692         assert(obj != NULL);
    693         *ins++ = (s4) obj;
    694         verifyCount++;
    695     }
    696 
    697     /*
    698      * Copy the args onto the stack.  Primitive types are converted when
    699      * necessary, and object types are verified.
    700      */
    701     DataObject** args = (DataObject**)(void*)argList->contents;
    702     ClassObject** types = (ClassObject**)(void*)params->contents;
    703     for (int i = 0; i < argListLength; i++) {
    704         int width = dvmConvertArgument(*args++, *types++, ins);
    705         if (width < 0) {
    706             dvmPopFrame(self);      // throw wants to pull PC out of stack
    707             needPop = false;
    708             throwArgumentTypeMismatch(i, *(types-1), *(args-1));
    709             goto bail;
    710         }
    711 
    712         ins += width;
    713         verifyCount += width;
    714     }
    715 
    716 #ifndef NDEBUG
    717     if (verifyCount != method->insSize) {
    718         LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
    719             method->insSize, clazz->descriptor, method->name);
    720         assert(false);
    721         goto bail;
    722     }
    723 #endif
    724 
    725     if (dvmIsNativeMethod(method)) {
    726         TRACE_METHOD_ENTER(self, method);
    727         /*
    728          * Because we leave no space for local variables, "curFrame" points
    729          * directly at the method arguments.
    730          */
    731         (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
    732                               method, self);
    733         TRACE_METHOD_EXIT(self, method);
    734     } else {
    735         dvmInterpret(self, method, &retval);
    736     }
    737 
    738     /*
    739      * Pop the frame immediately.  The "wrap" calls below can cause
    740      * allocations, and we don't want the GC to walk the now-dead frame.
    741      */
    742     dvmPopFrame(self);
    743     needPop = false;
    744 
    745     /*
    746      * If an exception is raised, wrap and replace.  This is necessary
    747      * because the invoked method could have thrown a checked exception
    748      * that the caller wasn't prepared for.
    749      *
    750      * We might be able to do this up in the interpreted code, but that will
    751      * leave us with a shortened stack trace in the top-level exception.
    752      */
    753     if (dvmCheckException(self)) {
    754         dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
    755     } else {
    756         /*
    757          * If this isn't a void method or constructor, convert the return type
    758          * to an appropriate object.
    759          *
    760          * We don't do this when an exception is raised because the value
    761          * in "retval" is undefined.
    762          */
    763         if (returnType != NULL) {
    764             retObj = (Object*)dvmBoxPrimitive(retval, returnType);
    765             dvmReleaseTrackedAlloc(retObj, NULL);
    766         }
    767     }
    768 
    769 bail:
    770     if (needPop) {
    771         dvmPopFrame(self);
    772     }
    773     return retObj;
    774 }
    775 
    776 struct LineNumFromPcContext {
    777     u4 address;
    778     u4 lineNum;
    779 };
    780 
    781 static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
    782 {
    783     LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
    784 
    785     // We know that this callback will be called in
    786     // ascending address order, so keep going until we find
    787     // a match or we've just gone past it.
    788 
    789     if (address > pContext->address) {
    790         // The line number from the previous positions callback
    791         // wil be the final result.
    792         return 1;
    793     }
    794 
    795     pContext->lineNum = lineNum;
    796 
    797     return (address == pContext->address) ? 1 : 0;
    798 }
    799 
    800 /*
    801  * Determine the source file line number based on the program counter.
    802  * "pc" is an offset, in 16-bit units, from the start of the method's code.
    803  *
    804  * Returns -1 if no match was found (possibly because the source files were
    805  * compiled without "-g", so no line number information is present).
    806  * Returns -2 for native methods (as expected in exception traces).
    807  */
    808 int dvmLineNumFromPC(const Method* method, u4 relPc)
    809 {
    810     const DexCode* pDexCode = dvmGetMethodCode(method);
    811 
    812     if (pDexCode == NULL) {
    813         if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
    814             return -2;
    815         return -1;      /* can happen for abstract method stub */
    816     }
    817 
    818     LineNumFromPcContext context;
    819     memset(&context, 0, sizeof(context));
    820     context.address = relPc;
    821     // A method with no line number info should return -1
    822     context.lineNum = -1;
    823 
    824     dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
    825             method->clazz->descriptor,
    826             method->prototype.protoIdx,
    827             method->accessFlags,
    828             lineNumForPcCb, NULL, &context);
    829 
    830     return context.lineNum;
    831 }
    832 
    833 /*
    834  * Compute the frame depth.
    835  *
    836  * Excludes "break" frames.
    837  */
    838 int dvmComputeExactFrameDepth(const void* fp)
    839 {
    840     int count = 0;
    841 
    842     for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
    843         if (!dvmIsBreakFrame((u4*)fp))
    844             count++;
    845     }
    846 
    847     return count;
    848 }
    849 
    850 /*
    851  * Compute the "vague" frame depth, which is just a pointer subtraction.
    852  * The result is NOT an overly generous assessment of the number of
    853  * frames; the only meaningful use is to compare against the result of
    854  * an earlier invocation.
    855  *
    856  * Useful for implementing single-step debugger modes, which may need to
    857  * call this for every instruction.
    858  */
    859 int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
    860 {
    861     const u1* interpStackStart = thread->interpStackStart;
    862 
    863     assert((u1*) fp >= interpStackStart - thread->interpStackSize);
    864     assert((u1*) fp < interpStackStart);
    865     return interpStackStart - (u1*) fp;
    866 }
    867 
    868 /*
    869  * Get the calling frame.  Pass in the current fp.
    870  *
    871  * Skip "break" frames and reflection invoke frames.
    872  */
    873 void* dvmGetCallerFP(const void* curFrame)
    874 {
    875     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
    876     StackSaveArea* saveArea;
    877 
    878 retry:
    879     if (dvmIsBreakFrame((u4*)caller)) {
    880         /* pop up one more */
    881         caller = SAVEAREA_FROM_FP(caller)->prevFrame;
    882         if (caller == NULL)
    883             return NULL;        /* hit the top */
    884 
    885         /*
    886          * If we got here by java.lang.reflect.Method.invoke(), we don't
    887          * want to return Method's class loader.  Shift up one and try
    888          * again.
    889          */
    890         saveArea = SAVEAREA_FROM_FP(caller);
    891         if (dvmIsReflectionMethod(saveArea->method)) {
    892             caller = saveArea->prevFrame;
    893             assert(caller != NULL);
    894             goto retry;
    895         }
    896     }
    897 
    898     return caller;
    899 }
    900 
    901 /*
    902  * Get the caller's class.  Pass in the current fp.
    903  *
    904  * This is used by e.g. java.lang.Class.
    905  */
    906 ClassObject* dvmGetCallerClass(const void* curFrame)
    907 {
    908     void* caller;
    909 
    910     caller = dvmGetCallerFP(curFrame);
    911     if (caller == NULL)
    912         return NULL;
    913 
    914     return SAVEAREA_FROM_FP(caller)->method->clazz;
    915 }
    916 
    917 /*
    918  * Get the caller's caller's class.  Pass in the current fp.
    919  *
    920  * This is used by e.g. java.lang.Class, which wants to know about the
    921  * class loader of the method that called it.
    922  */
    923 ClassObject* dvmGetCaller2Class(const void* curFrame)
    924 {
    925     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
    926     void* callerCaller;
    927 
    928     /* at the top? */
    929     if (dvmIsBreakFrame((u4*)caller) &&
    930         SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
    931         return NULL;
    932 
    933     /* go one more */
    934     callerCaller = dvmGetCallerFP(caller);
    935     if (callerCaller == NULL)
    936         return NULL;
    937 
    938     return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
    939 }
    940 
    941 /*
    942  * Get the caller's caller's caller's class.  Pass in the current fp.
    943  *
    944  * This is used by e.g. java.lang.Class, which wants to know about the
    945  * class loader of the method that called it.
    946  */
    947 ClassObject* dvmGetCaller3Class(const void* curFrame)
    948 {
    949     void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
    950     int i;
    951 
    952     /* at the top? */
    953     if (dvmIsBreakFrame((u4*)caller) &&
    954         SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
    955         return NULL;
    956 
    957     /* Walk up two frames if possible. */
    958     for (i = 0; i < 2; i++) {
    959         caller = dvmGetCallerFP(caller);
    960         if (caller == NULL)
    961             return NULL;
    962     }
    963 
    964     return SAVEAREA_FROM_FP(caller)->method->clazz;
    965 }
    966 
    967 /*
    968  * Fill a flat array of methods that comprise the current interpreter
    969  * stack trace.  Pass in the current frame ptr.  Break frames are
    970  * skipped, but reflection invocations are not.
    971  *
    972  * The current frame will be in element 0.
    973  */
    974 void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
    975 {
    976     assert(fp != NULL);
    977     assert(array != NULL);
    978     size_t i = 0;
    979     while (fp != NULL) {
    980         if (!dvmIsBreakFrame((u4*)fp)) {
    981             assert(i < length);
    982             array[i++] = SAVEAREA_FROM_FP(fp)->method;
    983         }
    984         fp = SAVEAREA_FROM_FP(fp)->prevFrame;
    985     }
    986 }
    987 
    988 /*
    989  * Open up the reserved area and throw an exception.  The reserved area
    990  * should only be needed to create and initialize the exception itself.
    991  *
    992  * If we already opened it and we're continuing to overflow, abort the VM.
    993  *
    994  * We have to leave the "reserved" area open until the "catch" handler has
    995  * finished doing its processing.  This is because the catch handler may
    996  * need to resolve classes, which requires calling into the class loader if
    997  * the classes aren't already in the "initiating loader" list.
    998  */
    999 void dvmHandleStackOverflow(Thread* self, const Method* method)
   1000 {
   1001     /*
   1002      * Can we make the reserved area available?
   1003      */
   1004     if (self->stackOverflowed) {
   1005         /*
   1006          * Already did, nothing to do but bail.
   1007          */
   1008         LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
   1009             self->threadId);
   1010         dvmDumpThread(self, false);
   1011         dvmAbort();
   1012     }
   1013 
   1014     /* open it up to the full range */
   1015     LOGI("threadid=%d: stack overflow on call to %s.%s:%s",
   1016         self->threadId,
   1017         method->clazz->descriptor, method->name, method->shorty);
   1018     StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
   1019     LOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
   1020         method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
   1021         (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
   1022         saveArea, (u1*) saveArea - self->interpStackEnd);
   1023     LOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
   1024         self->interpStackStart - self->interpStackSize);
   1025     //dvmDumpThread(self, false);
   1026     self->interpStackEnd = self->interpStackStart - self->interpStackSize;
   1027     self->stackOverflowed = true;
   1028 
   1029     /*
   1030      * If we were trying to throw an exception when the stack overflowed,
   1031      * we will blow up when doing the class lookup on StackOverflowError
   1032      * because of the pending exception.  So, we clear it and make it
   1033      * the cause of the SOE.
   1034      */
   1035     Object* excep = dvmGetException(self);
   1036     if (excep != NULL) {
   1037         LOGW("Stack overflow while throwing exception");
   1038         dvmClearException(self);
   1039     }
   1040     dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
   1041 }
   1042 
   1043 /*
   1044  * Reduce the available stack size.  By this point we should have finished
   1045  * our overflow processing.
   1046  */
   1047 void dvmCleanupStackOverflow(Thread* self, const Object* exception)
   1048 {
   1049     const u1* newStackEnd;
   1050 
   1051     assert(self->stackOverflowed);
   1052 
   1053     if (exception->clazz != gDvm.exStackOverflowError) {
   1054         /* exception caused during SOE, not the SOE itself */
   1055         return;
   1056     }
   1057 
   1058     newStackEnd = (self->interpStackStart - self->interpStackSize)
   1059         + STACK_OVERFLOW_RESERVE;
   1060     if ((u1*)self->interpSave.curFrame <= newStackEnd) {
   1061         LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
   1062             self->interpStackEnd, self->interpSave.curFrame);
   1063         dvmDumpThread(self, false);
   1064         dvmAbort();
   1065     }
   1066 
   1067     self->interpStackEnd = newStackEnd;
   1068     self->stackOverflowed = false;
   1069 
   1070     LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
   1071         self->interpSave.curFrame);
   1072 }
   1073 
   1074 
   1075 /*
   1076  * Extract the object that is the target of a monitor-enter instruction
   1077  * in the top stack frame of "thread".
   1078  *
   1079  * The other thread might be alive, so this has to work carefully.
   1080  *
   1081  * The thread list lock must be held.
   1082  *
   1083  * Returns "true" if we successfully recover the object.  "*pOwner" will
   1084  * be NULL if we can't determine the owner for some reason (e.g. race
   1085  * condition on ownership transfer).
   1086  */
   1087 static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
   1088     Thread** pOwner)
   1089 {
   1090     void* framePtr = thread->interpSave.curFrame;
   1091 
   1092     if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
   1093         return false;
   1094 
   1095     const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
   1096     const Method* method = saveArea->method;
   1097     const u2* currentPc = saveArea->xtra.currentPc;
   1098 
   1099     /* check Method* */
   1100     if (!dvmLinearAllocContains(method, sizeof(Method))) {
   1101         LOGD("ExtrMon: method %p not valid", method);
   1102         return false;
   1103     }
   1104 
   1105     /* check currentPc */
   1106     u4 insnsSize = dvmGetMethodInsnsSize(method);
   1107     if (currentPc < method->insns ||
   1108         currentPc >= method->insns + insnsSize)
   1109     {
   1110         LOGD("ExtrMon: insns %p not valid (%p - %p)",
   1111             currentPc, method->insns, method->insns + insnsSize);
   1112         return false;
   1113     }
   1114 
   1115     /* check the instruction */
   1116     if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
   1117         LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
   1118             currentPc, *currentPc & 0xff);
   1119         return false;
   1120     }
   1121 
   1122     /* get and check the register index */
   1123     unsigned int reg = *currentPc >> 8;
   1124     if (reg >= method->registersSize) {
   1125         LOGD("ExtrMon: invalid register %d (max %d)",
   1126             reg, method->registersSize);
   1127         return false;
   1128     }
   1129 
   1130     /* get and check the object in that register */
   1131     u4* fp = (u4*) framePtr;
   1132     Object* obj = (Object*) fp[reg];
   1133     if (obj != NULL && !dvmIsHeapAddress(obj)) {
   1134         LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
   1135         return false;
   1136     }
   1137     *pLockObj = obj;
   1138 
   1139     /*
   1140      * Try to determine the object's lock holder; it's okay if this fails.
   1141      *
   1142      * We're assuming the thread list lock is already held by this thread.
   1143      * If it's not, we may be living dangerously if we have to scan through
   1144      * the thread list to find a match.  (The VM will generally be in a
   1145      * suspended state when executing here, so this is a minor concern
   1146      * unless we're dumping while threads are running, in which case there's
   1147      * a good chance of stuff blowing up anyway.)
   1148      */
   1149     *pOwner = dvmGetObjectLockHolder(obj);
   1150 
   1151     return true;
   1152 }
   1153 
   1154 static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
   1155         Thread* thread)
   1156 {
   1157     std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
   1158 
   1159     if (obj->clazz != gDvm.classJavaLangClass) {
   1160         // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
   1161         // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
   1162         msg += "(a " + dvmHumanReadableType(obj) + ")";
   1163     }
   1164 
   1165     if (thread != NULL) {
   1166         std::string threadName(dvmGetThreadName(thread));
   1167         StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
   1168     }
   1169 
   1170     dvmPrintDebugMessage(target, "%s\n", msg.c_str());
   1171 }
   1172 
   1173 /*
   1174  * Dump stack frames, starting from the specified frame and moving down.
   1175  *
   1176  * Each frame holds a pointer to the currently executing method, and the
   1177  * saved program counter from the caller ("previous" frame).  This means
   1178  * we don't have the PC for the current method on the stack, which is
   1179  * pretty reasonable since it's in the "PC register" for the VM.  Because
   1180  * exceptions need to show the correct line number we actually *do* have
   1181  * an updated version in the fame's "xtra.currentPc", but it's unreliable.
   1182  *
   1183  * Note "framePtr" could be NULL in rare circumstances.
   1184  */
   1185 static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
   1186     Thread* thread)
   1187 {
   1188     const StackSaveArea* saveArea;
   1189     const Method* method;
   1190     int checkCount = 0;
   1191     const u2* currentPc = NULL;
   1192     bool first = true;
   1193 
   1194     /*
   1195      * We call functions that require us to be holding the thread list lock.
   1196      * It's probable that the caller has already done so, but it's not
   1197      * guaranteed.  If it's not locked, lock it now.
   1198      */
   1199     bool needThreadUnlock = dvmTryLockThreadList();
   1200 
   1201     /*
   1202      * The "currentPc" is updated whenever we execute an instruction that
   1203      * might throw an exception.  Show it here.
   1204      */
   1205     if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
   1206         saveArea = SAVEAREA_FROM_FP(framePtr);
   1207 
   1208         if (saveArea->xtra.currentPc != NULL)
   1209             currentPc = saveArea->xtra.currentPc;
   1210     }
   1211 
   1212     while (framePtr != NULL) {
   1213         saveArea = SAVEAREA_FROM_FP(framePtr);
   1214         method = saveArea->method;
   1215 
   1216         if (dvmIsBreakFrame((u4*)framePtr)) {
   1217             //dvmPrintDebugMessage(target, "  (break frame)\n");
   1218         } else {
   1219             int relPc;
   1220 
   1221             if (currentPc != NULL)
   1222                 relPc = currentPc - saveArea->method->insns;
   1223             else
   1224                 relPc = -1;
   1225 
   1226             std::string methodName(dvmHumanReadableMethod(method, false));
   1227             if (dvmIsNativeMethod(method)) {
   1228                 dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
   1229                         methodName.c_str());
   1230             } else {
   1231                 dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
   1232                         methodName.c_str(), dvmGetMethodSourceFile(method),
   1233                         (relPc >= 0 && first) ? "~" : "",
   1234                         relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
   1235             }
   1236 
   1237             if (first) {
   1238                 /*
   1239                  * Decorate WAIT and MONITOR threads with some detail on
   1240                  * the first frame.
   1241                  *
   1242                  * warning: wait status not stable, even in suspend
   1243                  */
   1244                 if (thread->status == THREAD_WAIT ||
   1245                     thread->status == THREAD_TIMED_WAIT)
   1246                 {
   1247                     Monitor* mon = thread->waitMonitor;
   1248                     Object* obj = dvmGetMonitorObject(mon);
   1249                     if (obj != NULL) {
   1250                         Thread* joinThread = NULL;
   1251                         if (obj->clazz == gDvm.classJavaLangVMThread) {
   1252                             joinThread = dvmGetThreadFromThreadObject(obj);
   1253                         }
   1254                         printWaitMessage(target, "on", obj, joinThread);
   1255                     }
   1256                 } else if (thread->status == THREAD_MONITOR) {
   1257                     Object* obj;
   1258                     Thread* owner;
   1259                     if (extractMonitorEnterObject(thread, &obj, &owner)) {
   1260                         printWaitMessage(target, "to lock", obj, owner);
   1261                     }
   1262                 }
   1263             }
   1264         }
   1265 
   1266         /*
   1267          * Get saved PC for previous frame.  There's no savedPc in a "break"
   1268          * frame, because that represents native or interpreted code
   1269          * invoked by the VM.  The saved PC is sitting in the "PC register",
   1270          * a local variable on the native stack.
   1271          */
   1272         currentPc = saveArea->savedPc;
   1273 
   1274         first = false;
   1275 
   1276         if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
   1277             LOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
   1278                 checkCount, framePtr, saveArea->prevFrame);
   1279             break;
   1280         }
   1281         framePtr = saveArea->prevFrame;
   1282 
   1283         checkCount++;
   1284         if (checkCount > 300) {
   1285             dvmPrintDebugMessage(target,
   1286                 "  ***** printed %d frames, not showing any more\n",
   1287                 checkCount);
   1288             break;
   1289         }
   1290     }
   1291     dvmPrintDebugMessage(target, "\n");
   1292 
   1293     if (needThreadUnlock) {
   1294         dvmUnlockThreadList();
   1295     }
   1296 }
   1297 
   1298 
   1299 /*
   1300  * Dump the stack for the specified thread.
   1301  */
   1302 void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
   1303 {
   1304     dumpFrames(target, thread->interpSave.curFrame, thread);
   1305 }
   1306 
   1307 /*
   1308  * Dump the stack for the specified thread, which is still running.
   1309  *
   1310  * This is very dangerous, because stack frames are being pushed on and
   1311  * popped off, and if the thread exits we'll be looking at freed memory.
   1312  * The plan here is to take a snapshot of the stack and then dump that
   1313  * to try to minimize the chances of catching it mid-update.  This should
   1314  * work reasonably well on a single-CPU system.
   1315  *
   1316  * There is a small chance that calling here will crash the VM.
   1317  */
   1318 void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
   1319 {
   1320     StackSaveArea* saveArea;
   1321     const u1* origStack;
   1322     u1* stackCopy = NULL;
   1323     int origSize, fpOffset;
   1324     void* fp;
   1325     int depthLimit = 200;
   1326 
   1327     if (thread == NULL || thread->interpSave.curFrame == NULL) {
   1328         dvmPrintDebugMessage(target,
   1329             "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
   1330             thread, (thread != NULL) ? thread->threadId : 0);
   1331         return;
   1332     }
   1333 
   1334     /* wait for a full quantum */
   1335     sched_yield();
   1336 
   1337     /* copy the info we need, then the stack itself */
   1338     origSize = thread->interpStackSize;
   1339     origStack = (const u1*) thread->interpStackStart - origSize;
   1340     stackCopy = (u1*) malloc(origSize);
   1341     fpOffset = (u1*) thread->interpSave.curFrame - origStack;
   1342     memcpy(stackCopy, origStack, origSize);
   1343 
   1344     /*
   1345      * Run through the stack and rewrite the "prev" pointers.
   1346      */
   1347     //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
   1348     //     thread->interpSave.curFrame);
   1349     fp = stackCopy + fpOffset;
   1350     while (true) {
   1351         int prevOffset;
   1352 
   1353         if (depthLimit-- < 0) {
   1354             /* we're probably screwed */
   1355             dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
   1356             dvmAbort();
   1357         }
   1358         saveArea = SAVEAREA_FROM_FP(fp);
   1359         if (saveArea->prevFrame == NULL)
   1360             break;
   1361 
   1362         prevOffset = (u1*) saveArea->prevFrame - origStack;
   1363         if (prevOffset < 0 || prevOffset > origSize) {
   1364             dvmPrintDebugMessage(target,
   1365                 "DumpRunning: bad offset found: %d (from %p %p)\n",
   1366                 prevOffset, origStack, saveArea->prevFrame);
   1367             saveArea->prevFrame = NULL;
   1368             break;
   1369         }
   1370 
   1371         saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
   1372         fp = saveArea->prevFrame;
   1373     }
   1374 
   1375     /*
   1376      * We still need to pass the Thread for some monitor wait stuff.
   1377      */
   1378     dumpFrames(target, stackCopy + fpOffset, thread);
   1379     free(stackCopy);
   1380 }
   1381