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