Home | History | Annotate | Download | only in c
      1 /*
      2  * C footer.  This has some common code shared by the various targets.
      3  */
      4 
      5 /*
      6  * Everything from here on is a "goto target".  In the basic interpreter
      7  * we jump into these targets and then jump directly to the handler for
      8  * next instruction.  Here, these are subroutines that return to the caller.
      9  */
     10 
     11 GOTO_TARGET(filledNewArray, bool methodCallRange, bool)
     12     {
     13         ClassObject* arrayClass;
     14         ArrayObject* newArray;
     15         u4* contents;
     16         char typeCh;
     17         int i;
     18         u4 arg5;
     19 
     20         EXPORT_PC();
     21 
     22         ref = FETCH(1);             /* class ref */
     23         vdst = FETCH(2);            /* first 4 regs -or- range base */
     24 
     25         if (methodCallRange) {
     26             vsrc1 = INST_AA(inst);  /* #of elements */
     27             arg5 = -1;              /* silence compiler warning */
     28             ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
     29                 vsrc1, ref, vdst, vdst+vsrc1-1);
     30         } else {
     31             arg5 = INST_A(inst);
     32             vsrc1 = INST_B(inst);   /* #of elements */
     33             ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
     34                vsrc1, ref, vdst, arg5);
     35         }
     36 
     37         /*
     38          * Resolve the array class.
     39          */
     40         arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
     41         if (arrayClass == NULL) {
     42             arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
     43             if (arrayClass == NULL)
     44                 GOTO_exceptionThrown();
     45         }
     46         /*
     47         if (!dvmIsArrayClass(arrayClass)) {
     48             dvmThrowRuntimeException(
     49                 "filled-new-array needs array class");
     50             GOTO_exceptionThrown();
     51         }
     52         */
     53         /* verifier guarantees this is an array class */
     54         assert(dvmIsArrayClass(arrayClass));
     55         assert(dvmIsClassInitialized(arrayClass));
     56 
     57         /*
     58          * Create an array of the specified type.
     59          */
     60         LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
     61         typeCh = arrayClass->descriptor[1];
     62         if (typeCh == 'D' || typeCh == 'J') {
     63             /* category 2 primitives not allowed */
     64             dvmThrowRuntimeException("bad filled array req");
     65             GOTO_exceptionThrown();
     66         } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
     67             /* TODO: requires multiple "fill in" loops with different widths */
     68             ALOGE("non-int primitives not implemented");
     69             dvmThrowInternalError(
     70                 "filled-new-array not implemented for anything but 'int'");
     71             GOTO_exceptionThrown();
     72         }
     73 
     74         newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
     75         if (newArray == NULL)
     76             GOTO_exceptionThrown();
     77 
     78         /*
     79          * Fill in the elements.  It's legal for vsrc1 to be zero.
     80          */
     81         contents = (u4*)(void*)newArray->contents;
     82         if (methodCallRange) {
     83             for (i = 0; i < vsrc1; i++)
     84                 contents[i] = GET_REGISTER(vdst+i);
     85         } else {
     86             assert(vsrc1 <= 5);
     87             if (vsrc1 == 5) {
     88                 contents[4] = GET_REGISTER(arg5);
     89                 vsrc1--;
     90             }
     91             for (i = 0; i < vsrc1; i++) {
     92                 contents[i] = GET_REGISTER(vdst & 0x0f);
     93                 vdst >>= 4;
     94             }
     95         }
     96         if (typeCh == 'L' || typeCh == '[') {
     97             dvmWriteBarrierArray(newArray, 0, newArray->length);
     98         }
     99 
    100         retval.l = (Object*)newArray;
    101     }
    102     FINISH(3);
    103 GOTO_TARGET_END
    104 
    105 
    106 GOTO_TARGET(invokeVirtual, bool methodCallRange, bool)
    107     {
    108         Method* baseMethod;
    109         Object* thisPtr;
    110 
    111         EXPORT_PC();
    112 
    113         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    114         ref = FETCH(1);             /* method ref */
    115         vdst = FETCH(2);            /* 4 regs -or- first reg */
    116 
    117         /*
    118          * The object against which we are executing a method is always
    119          * in the first argument.
    120          */
    121         if (methodCallRange) {
    122             assert(vsrc1 > 0);
    123             ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
    124                 vsrc1, ref, vdst, vdst+vsrc1-1);
    125             thisPtr = (Object*) GET_REGISTER(vdst);
    126         } else {
    127             assert((vsrc1>>4) > 0);
    128             ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
    129                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    130             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
    131         }
    132 
    133         if (!checkForNull(thisPtr))
    134             GOTO_exceptionThrown();
    135 
    136         /*
    137          * Resolve the method.  This is the correct method for the static
    138          * type of the object.  We also verify access permissions here.
    139          */
    140         baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
    141         if (baseMethod == NULL) {
    142             baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
    143             if (baseMethod == NULL) {
    144                 ILOGV("+ unknown method or access denied");
    145                 GOTO_exceptionThrown();
    146             }
    147         }
    148 
    149         /*
    150          * Combine the object we found with the vtable offset in the
    151          * method.
    152          */
    153         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
    154         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
    155 
    156 #if defined(WITH_JIT) && defined(MTERP_STUB)
    157         self->methodToCall = methodToCall;
    158         self->callsiteClass = thisPtr->clazz;
    159 #endif
    160 
    161 #if 0
    162         if (dvmIsAbstractMethod(methodToCall)) {
    163             /*
    164              * This can happen if you create two classes, Base and Sub, where
    165              * Sub is a sub-class of Base.  Declare a protected abstract
    166              * method foo() in Base, and invoke foo() from a method in Base.
    167              * Base is an "abstract base class" and is never instantiated
    168              * directly.  Now, Override foo() in Sub, and use Sub.  This
    169              * Works fine unless Sub stops providing an implementation of
    170              * the method.
    171              */
    172             dvmThrowAbstractMethodError("abstract method not implemented");
    173             GOTO_exceptionThrown();
    174         }
    175 #else
    176         assert(!dvmIsAbstractMethod(methodToCall) ||
    177             methodToCall->nativeFunc != NULL);
    178 #endif
    179 
    180         LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
    181             baseMethod->clazz->descriptor, baseMethod->name,
    182             (u4) baseMethod->methodIndex,
    183             methodToCall->clazz->descriptor, methodToCall->name);
    184         assert(methodToCall != NULL);
    185 
    186 #if 0
    187         if (vsrc1 != methodToCall->insSize) {
    188             ALOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
    189                 baseMethod->clazz->descriptor, baseMethod->name,
    190                 (u4) baseMethod->methodIndex,
    191                 methodToCall->clazz->descriptor, methodToCall->name);
    192             //dvmDumpClass(baseMethod->clazz);
    193             //dvmDumpClass(methodToCall->clazz);
    194             dvmDumpAllClasses(0);
    195         }
    196 #endif
    197 
    198         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    199     }
    200 GOTO_TARGET_END
    201 
    202 GOTO_TARGET(invokeSuper, bool methodCallRange)
    203     {
    204         Method* baseMethod;
    205         u2 thisReg;
    206 
    207         EXPORT_PC();
    208 
    209         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    210         ref = FETCH(1);             /* method ref */
    211         vdst = FETCH(2);            /* 4 regs -or- first reg */
    212 
    213         if (methodCallRange) {
    214             ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
    215                 vsrc1, ref, vdst, vdst+vsrc1-1);
    216             thisReg = vdst;
    217         } else {
    218             ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
    219                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    220             thisReg = vdst & 0x0f;
    221         }
    222 
    223         /* impossible in well-formed code, but we must check nevertheless */
    224         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
    225             GOTO_exceptionThrown();
    226 
    227         /*
    228          * Resolve the method.  This is the correct method for the static
    229          * type of the object.  We also verify access permissions here.
    230          * The first arg to dvmResolveMethod() is just the referring class
    231          * (used for class loaders and such), so we don't want to pass
    232          * the superclass into the resolution call.
    233          */
    234         baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
    235         if (baseMethod == NULL) {
    236             baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
    237             if (baseMethod == NULL) {
    238                 ILOGV("+ unknown method or access denied");
    239                 GOTO_exceptionThrown();
    240             }
    241         }
    242 
    243         /*
    244          * Combine the object we found with the vtable offset in the
    245          * method's class.
    246          *
    247          * We're using the current method's class' superclass, not the
    248          * superclass of "this".  This is because we might be executing
    249          * in a method inherited from a superclass, and we want to run
    250          * in that class' superclass.
    251          */
    252         if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
    253             /*
    254              * Method does not exist in the superclass.  Could happen if
    255              * superclass gets updated.
    256              */
    257             dvmThrowNoSuchMethodError(baseMethod->name);
    258             GOTO_exceptionThrown();
    259         }
    260         methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
    261 
    262 #if 0
    263         if (dvmIsAbstractMethod(methodToCall)) {
    264             dvmThrowAbstractMethodError("abstract method not implemented");
    265             GOTO_exceptionThrown();
    266         }
    267 #else
    268         assert(!dvmIsAbstractMethod(methodToCall) ||
    269             methodToCall->nativeFunc != NULL);
    270 #endif
    271         LOGVV("+++ base=%s.%s super-virtual=%s.%s",
    272             baseMethod->clazz->descriptor, baseMethod->name,
    273             methodToCall->clazz->descriptor, methodToCall->name);
    274         assert(methodToCall != NULL);
    275 
    276         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    277     }
    278 GOTO_TARGET_END
    279 
    280 GOTO_TARGET(invokeInterface, bool methodCallRange)
    281     {
    282         Object* thisPtr;
    283         ClassObject* thisClass;
    284 
    285         EXPORT_PC();
    286 
    287         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    288         ref = FETCH(1);             /* method ref */
    289         vdst = FETCH(2);            /* 4 regs -or- first reg */
    290 
    291         /*
    292          * The object against which we are executing a method is always
    293          * in the first argument.
    294          */
    295         if (methodCallRange) {
    296             assert(vsrc1 > 0);
    297             ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
    298                 vsrc1, ref, vdst, vdst+vsrc1-1);
    299             thisPtr = (Object*) GET_REGISTER(vdst);
    300         } else {
    301             assert((vsrc1>>4) > 0);
    302             ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
    303                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    304             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
    305         }
    306 
    307         if (!checkForNull(thisPtr))
    308             GOTO_exceptionThrown();
    309 
    310         thisClass = thisPtr->clazz;
    311 
    312         /*
    313          * Given a class and a method index, find the Method* with the
    314          * actual code we want to execute.
    315          */
    316         methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
    317                         methodClassDex);
    318 #if defined(WITH_JIT) && defined(MTERP_STUB)
    319         self->callsiteClass = thisClass;
    320         self->methodToCall = methodToCall;
    321 #endif
    322         if (methodToCall == NULL) {
    323             assert(dvmCheckException(self));
    324             GOTO_exceptionThrown();
    325         }
    326 
    327         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    328     }
    329 GOTO_TARGET_END
    330 
    331 GOTO_TARGET(invokeDirect, bool methodCallRange)
    332     {
    333         u2 thisReg;
    334 
    335         EXPORT_PC();
    336 
    337         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    338         ref = FETCH(1);             /* method ref */
    339         vdst = FETCH(2);            /* 4 regs -or- first reg */
    340 
    341         if (methodCallRange) {
    342             ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
    343                 vsrc1, ref, vdst, vdst+vsrc1-1);
    344             thisReg = vdst;
    345         } else {
    346             ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
    347                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    348             thisReg = vdst & 0x0f;
    349         }
    350 
    351         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
    352             GOTO_exceptionThrown();
    353 
    354         methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
    355         if (methodToCall == NULL) {
    356             methodToCall = dvmResolveMethod(curMethod->clazz, ref,
    357                             METHOD_DIRECT);
    358             if (methodToCall == NULL) {
    359                 ILOGV("+ unknown direct method");     // should be impossible
    360                 GOTO_exceptionThrown();
    361             }
    362         }
    363         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    364     }
    365 GOTO_TARGET_END
    366 
    367 GOTO_TARGET(invokeStatic, bool methodCallRange)
    368     EXPORT_PC();
    369 
    370     vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    371     ref = FETCH(1);             /* method ref */
    372     vdst = FETCH(2);            /* 4 regs -or- first reg */
    373 
    374     if (methodCallRange)
    375         ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
    376             vsrc1, ref, vdst, vdst+vsrc1-1);
    377     else
    378         ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
    379             vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    380 
    381     methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
    382     if (methodToCall == NULL) {
    383         methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
    384         if (methodToCall == NULL) {
    385             ILOGV("+ unknown method");
    386             GOTO_exceptionThrown();
    387         }
    388 
    389 #if defined(WITH_JIT) && defined(MTERP_STUB)
    390         /*
    391          * The JIT needs dvmDexGetResolvedMethod() to return non-null.
    392          * Include the check if this code is being used as a stub
    393          * called from the assembly interpreter.
    394          */
    395         if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
    396             (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
    397             /* Class initialization is still ongoing */
    398             dvmJitEndTraceSelect(self,pc);
    399         }
    400 #endif
    401     }
    402     GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    403 GOTO_TARGET_END
    404 
    405 GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
    406     {
    407         Object* thisPtr;
    408 
    409         EXPORT_PC();
    410 
    411         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    412         ref = FETCH(1);             /* vtable index */
    413         vdst = FETCH(2);            /* 4 regs -or- first reg */
    414 
    415         /*
    416          * The object against which we are executing a method is always
    417          * in the first argument.
    418          */
    419         if (methodCallRange) {
    420             assert(vsrc1 > 0);
    421             ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
    422                 vsrc1, ref, vdst, vdst+vsrc1-1);
    423             thisPtr = (Object*) GET_REGISTER(vdst);
    424         } else {
    425             assert((vsrc1>>4) > 0);
    426             ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
    427                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    428             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
    429         }
    430 
    431         if (!checkForNull(thisPtr))
    432             GOTO_exceptionThrown();
    433 
    434 
    435         /*
    436          * Combine the object we found with the vtable offset in the
    437          * method.
    438          */
    439         assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
    440         methodToCall = thisPtr->clazz->vtable[ref];
    441 #if defined(WITH_JIT) && defined(MTERP_STUB)
    442         self->callsiteClass = thisPtr->clazz;
    443         self->methodToCall = methodToCall;
    444 #endif
    445 
    446 #if 0
    447         if (dvmIsAbstractMethod(methodToCall)) {
    448             dvmThrowAbstractMethodError("abstract method not implemented");
    449             GOTO_exceptionThrown();
    450         }
    451 #else
    452         assert(!dvmIsAbstractMethod(methodToCall) ||
    453             methodToCall->nativeFunc != NULL);
    454 #endif
    455 
    456         LOGVV("+++ virtual[%d]=%s.%s",
    457             ref, methodToCall->clazz->descriptor, methodToCall->name);
    458         assert(methodToCall != NULL);
    459 
    460         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    461     }
    462 GOTO_TARGET_END
    463 
    464 GOTO_TARGET(invokeSuperQuick, bool methodCallRange)
    465     {
    466         u2 thisReg;
    467 
    468         EXPORT_PC();
    469 
    470         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
    471         ref = FETCH(1);             /* vtable index */
    472         vdst = FETCH(2);            /* 4 regs -or- first reg */
    473 
    474         if (methodCallRange) {
    475             ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
    476                 vsrc1, ref, vdst, vdst+vsrc1-1);
    477             thisReg = vdst;
    478         } else {
    479             ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
    480                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
    481             thisReg = vdst & 0x0f;
    482         }
    483         /* impossible in well-formed code, but we must check nevertheless */
    484         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
    485             GOTO_exceptionThrown();
    486 
    487 #if 0   /* impossible in optimized + verified code */
    488         if (ref >= curMethod->clazz->super->vtableCount) {
    489             dvmThrowNoSuchMethodError(NULL);
    490             GOTO_exceptionThrown();
    491         }
    492 #else
    493         assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
    494 #endif
    495 
    496         /*
    497          * Combine the object we found with the vtable offset in the
    498          * method's class.
    499          *
    500          * We're using the current method's class' superclass, not the
    501          * superclass of "this".  This is because we might be executing
    502          * in a method inherited from a superclass, and we want to run
    503          * in the method's class' superclass.
    504          */
    505         methodToCall = curMethod->clazz->super->vtable[ref];
    506 
    507 #if 0
    508         if (dvmIsAbstractMethod(methodToCall)) {
    509             dvmThrowAbstractMethodError("abstract method not implemented");
    510             GOTO_exceptionThrown();
    511         }
    512 #else
    513         assert(!dvmIsAbstractMethod(methodToCall) ||
    514             methodToCall->nativeFunc != NULL);
    515 #endif
    516         LOGVV("+++ super-virtual[%d]=%s.%s",
    517             ref, methodToCall->clazz->descriptor, methodToCall->name);
    518         assert(methodToCall != NULL);
    519         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
    520     }
    521 GOTO_TARGET_END
    522 
    523 
    524     /*
    525      * General handling for return-void, return, and return-wide.  Put the
    526      * return value in "retval" before jumping here.
    527      */
    528 GOTO_TARGET(returnFromMethod)
    529     {
    530         StackSaveArea* saveArea;
    531 
    532         /*
    533          * We must do this BEFORE we pop the previous stack frame off, so
    534          * that the GC can see the return value (if any) in the local vars.
    535          *
    536          * Since this is now an interpreter switch point, we must do it before
    537          * we do anything at all.
    538          */
    539         PERIODIC_CHECKS(0);
    540 
    541         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
    542             retval.j, curMethod->clazz->descriptor, curMethod->name,
    543             curMethod->shorty);
    544         //DUMP_REGS(curMethod, fp);
    545 
    546         saveArea = SAVEAREA_FROM_FP(fp);
    547 
    548 #ifdef EASY_GDB
    549         debugSaveArea = saveArea;
    550 #endif
    551 
    552         /* back up to previous frame and see if we hit a break */
    553         fp = (u4*)saveArea->prevFrame;
    554         assert(fp != NULL);
    555 
    556         /* Handle any special subMode requirements */
    557         if (self->interpBreak.ctl.subMode != 0) {
    558             PC_FP_TO_SELF();
    559             dvmReportReturn(self);
    560         }
    561 
    562         if (dvmIsBreakFrame(fp)) {
    563             /* bail without popping the method frame from stack */
    564             LOGVV("+++ returned into break frame");
    565             GOTO_bail();
    566         }
    567 
    568         /* update thread FP, and reset local variables */
    569         self->interpSave.curFrame = fp;
    570         curMethod = SAVEAREA_FROM_FP(fp)->method;
    571         self->interpSave.method = curMethod;
    572         //methodClass = curMethod->clazz;
    573         methodClassDex = curMethod->clazz->pDvmDex;
    574         pc = saveArea->savedPc;
    575         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
    576             curMethod->name, curMethod->shorty);
    577 
    578         /* use FINISH on the caller's invoke instruction */
    579         //u2 invokeInstr = INST_INST(FETCH(0));
    580         if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
    581             invokeInstr <= OP_INVOKE_INTERFACE*/)
    582         {
    583             FINISH(3);
    584         } else {
    585             //ALOGE("Unknown invoke instr %02x at %d",
    586             //    invokeInstr, (int) (pc - curMethod->insns));
    587             assert(false);
    588         }
    589     }
    590 GOTO_TARGET_END
    591 
    592 
    593     /*
    594      * Jump here when the code throws an exception.
    595      *
    596      * By the time we get here, the Throwable has been created and the stack
    597      * trace has been saved off.
    598      */
    599 GOTO_TARGET(exceptionThrown)
    600     {
    601         Object* exception;
    602         int catchRelPc;
    603 
    604         PERIODIC_CHECKS(0);
    605 
    606         /*
    607          * We save off the exception and clear the exception status.  While
    608          * processing the exception we might need to load some Throwable
    609          * classes, and we don't want class loader exceptions to get
    610          * confused with this one.
    611          */
    612         assert(dvmCheckException(self));
    613         exception = dvmGetException(self);
    614         dvmAddTrackedAlloc(exception, self);
    615         dvmClearException(self);
    616 
    617         ALOGV("Handling exception %s at %s:%d",
    618             exception->clazz->descriptor, curMethod->name,
    619             dvmLineNumFromPC(curMethod, pc - curMethod->insns));
    620 
    621         /*
    622          * Report the exception throw to any "subMode" watchers.
    623          *
    624          * TODO: if the exception was thrown by interpreted code, control
    625          * fell through native, and then back to us, we will report the
    626          * exception at the point of the throw and again here.  We can avoid
    627          * this by not reporting exceptions when we jump here directly from
    628          * the native call code above, but then we won't report exceptions
    629          * that were thrown *from* the JNI code (as opposed to *through* it).
    630          *
    631          * The correct solution is probably to ignore from-native exceptions
    632          * here, and have the JNI exception code do the reporting to the
    633          * debugger.
    634          */
    635         if (self->interpBreak.ctl.subMode != 0) {
    636             PC_FP_TO_SELF();
    637             dvmReportExceptionThrow(self, exception);
    638         }
    639 
    640         /*
    641          * We need to unroll to the catch block or the nearest "break"
    642          * frame.
    643          *
    644          * A break frame could indicate that we have reached an intermediate
    645          * native call, or have gone off the top of the stack and the thread
    646          * needs to exit.  Either way, we return from here, leaving the
    647          * exception raised.
    648          *
    649          * If we do find a catch block, we want to transfer execution to
    650          * that point.
    651          *
    652          * Note this can cause an exception while resolving classes in
    653          * the "catch" blocks.
    654          */
    655         catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
    656                     exception, false, (void**)(void*)&fp);
    657 
    658         /*
    659          * Restore the stack bounds after an overflow.  This isn't going to
    660          * be correct in all circumstances, e.g. if JNI code devours the
    661          * exception this won't happen until some other exception gets
    662          * thrown.  If the code keeps pushing the stack bounds we'll end
    663          * up aborting the VM.
    664          *
    665          * Note we want to do this *after* the call to dvmFindCatchBlock,
    666          * because that may need extra stack space to resolve exception
    667          * classes (e.g. through a class loader).
    668          *
    669          * It's possible for the stack overflow handling to cause an
    670          * exception (specifically, class resolution in a "catch" block
    671          * during the call above), so we could see the thread's overflow
    672          * flag raised but actually be running in a "nested" interpreter
    673          * frame.  We don't allow doubled-up StackOverflowErrors, so
    674          * we can check for this by just looking at the exception type
    675          * in the cleanup function.  Also, we won't unroll past the SOE
    676          * point because the more-recent exception will hit a break frame
    677          * as it unrolls to here.
    678          */
    679         if (self->stackOverflowed)
    680             dvmCleanupStackOverflow(self, exception);
    681 
    682         if (catchRelPc < 0) {
    683             /* falling through to JNI code or off the bottom of the stack */
    684 #if DVM_SHOW_EXCEPTION >= 2
    685             ALOGD("Exception %s from %s:%d not caught locally",
    686                 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
    687                 dvmLineNumFromPC(curMethod, pc - curMethod->insns));
    688 #endif
    689             dvmSetException(self, exception);
    690             dvmReleaseTrackedAlloc(exception, self);
    691             GOTO_bail();
    692         }
    693 
    694 #if DVM_SHOW_EXCEPTION >= 3
    695         {
    696             const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
    697             ALOGD("Exception %s thrown from %s:%d to %s:%d",
    698                 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
    699                 dvmLineNumFromPC(curMethod, pc - curMethod->insns),
    700                 dvmGetMethodSourceFile(catchMethod),
    701                 dvmLineNumFromPC(catchMethod, catchRelPc));
    702         }
    703 #endif
    704 
    705         /*
    706          * Adjust local variables to match self->interpSave.curFrame and the
    707          * updated PC.
    708          */
    709         //fp = (u4*) self->interpSave.curFrame;
    710         curMethod = SAVEAREA_FROM_FP(fp)->method;
    711         self->interpSave.method = curMethod;
    712         //methodClass = curMethod->clazz;
    713         methodClassDex = curMethod->clazz->pDvmDex;
    714         pc = curMethod->insns + catchRelPc;
    715         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
    716             curMethod->name, curMethod->shorty);
    717         DUMP_REGS(curMethod, fp, false);            // show all regs
    718 
    719         /*
    720          * Restore the exception if the handler wants it.
    721          *
    722          * The Dalvik spec mandates that, if an exception handler wants to
    723          * do something with the exception, the first instruction executed
    724          * must be "move-exception".  We can pass the exception along
    725          * through the thread struct, and let the move-exception instruction
    726          * clear it for us.
    727          *
    728          * If the handler doesn't call move-exception, we don't want to
    729          * finish here with an exception still pending.
    730          */
    731         if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
    732             dvmSetException(self, exception);
    733 
    734         dvmReleaseTrackedAlloc(exception, self);
    735         FINISH(0);
    736     }
    737 GOTO_TARGET_END
    738 
    739 
    740 
    741     /*
    742      * General handling for invoke-{virtual,super,direct,static,interface},
    743      * including "quick" variants.
    744      *
    745      * Set "methodToCall" to the Method we're calling, and "methodCallRange"
    746      * depending on whether this is a "/range" instruction.
    747      *
    748      * For a range call:
    749      *  "vsrc1" holds the argument count (8 bits)
    750      *  "vdst" holds the first argument in the range
    751      * For a non-range call:
    752      *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
    753      *  "vdst" holds four 4-bit register indices
    754      *
    755      * The caller must EXPORT_PC before jumping here, because any method
    756      * call can throw a stack overflow exception.
    757      */
    758 GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
    759     u2 count, u2 regs)
    760     {
    761         STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
    762 
    763         //printf("range=%d call=%p count=%d regs=0x%04x\n",
    764         //    methodCallRange, methodToCall, count, regs);
    765         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
    766         //    methodToCall->name, methodToCall->shorty);
    767 
    768         u4* outs;
    769         int i;
    770 
    771         /*
    772          * Copy args.  This may corrupt vsrc1/vdst.
    773          */
    774         if (methodCallRange) {
    775             // could use memcpy or a "Duff's device"; most functions have
    776             // so few args it won't matter much
    777             assert(vsrc1 <= curMethod->outsSize);
    778             assert(vsrc1 == methodToCall->insSize);
    779             outs = OUTS_FROM_FP(fp, vsrc1);
    780             for (i = 0; i < vsrc1; i++)
    781                 outs[i] = GET_REGISTER(vdst+i);
    782         } else {
    783             u4 count = vsrc1 >> 4;
    784 
    785             assert(count <= curMethod->outsSize);
    786             assert(count == methodToCall->insSize);
    787             assert(count <= 5);
    788 
    789             outs = OUTS_FROM_FP(fp, count);
    790 #if 0
    791             if (count == 5) {
    792                 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
    793                 count--;
    794             }
    795             for (i = 0; i < (int) count; i++) {
    796                 outs[i] = GET_REGISTER(vdst & 0x0f);
    797                 vdst >>= 4;
    798             }
    799 #else
    800             // This version executes fewer instructions but is larger
    801             // overall.  Seems to be a teensy bit faster.
    802             assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
    803             switch (count) {
    804             case 5:
    805                 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
    806             case 4:
    807                 outs[3] = GET_REGISTER(vdst >> 12);
    808             case 3:
    809                 outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
    810             case 2:
    811                 outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
    812             case 1:
    813                 outs[0] = GET_REGISTER(vdst & 0x0f);
    814             default:
    815                 ;
    816             }
    817 #endif
    818         }
    819     }
    820 
    821     /*
    822      * (This was originally a "goto" target; I've kept it separate from the
    823      * stuff above in case we want to refactor things again.)
    824      *
    825      * At this point, we have the arguments stored in the "outs" area of
    826      * the current method's stack frame, and the method to call in
    827      * "methodToCall".  Push a new stack frame.
    828      */
    829     {
    830         StackSaveArea* newSaveArea;
    831         u4* newFp;
    832 
    833         ILOGV("> %s%s.%s %s",
    834             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
    835             methodToCall->clazz->descriptor, methodToCall->name,
    836             methodToCall->shorty);
    837 
    838         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
    839         newSaveArea = SAVEAREA_FROM_FP(newFp);
    840 
    841         /* verify that we have enough space */
    842         if (true) {
    843             u1* bottom;
    844             bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
    845             if (bottom < self->interpStackEnd) {
    846                 /* stack overflow */
    847                 ALOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
    848                     self->interpStackStart, self->interpStackEnd, bottom,
    849                     (u1*) fp - bottom, self->interpStackSize,
    850                     methodToCall->name);
    851                 dvmHandleStackOverflow(self, methodToCall);
    852                 assert(dvmCheckException(self));
    853                 GOTO_exceptionThrown();
    854             }
    855             //ALOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
    856             //    fp, newFp, newSaveArea, bottom);
    857         }
    858 
    859 #ifdef LOG_INSTR
    860         if (methodToCall->registersSize > methodToCall->insSize) {
    861             /*
    862              * This makes valgrind quiet when we print registers that
    863              * haven't been initialized.  Turn it off when the debug
    864              * messages are disabled -- we want valgrind to report any
    865              * used-before-initialized issues.
    866              */
    867             memset(newFp, 0xcc,
    868                 (methodToCall->registersSize - methodToCall->insSize) * 4);
    869         }
    870 #endif
    871 
    872 #ifdef EASY_GDB
    873         newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
    874 #endif
    875         newSaveArea->prevFrame = fp;
    876         newSaveArea->savedPc = pc;
    877 #if defined(WITH_JIT) && defined(MTERP_STUB)
    878         newSaveArea->returnAddr = 0;
    879 #endif
    880         newSaveArea->method = methodToCall;
    881 
    882         if (self->interpBreak.ctl.subMode != 0) {
    883             /*
    884              * We mark ENTER here for both native and non-native
    885              * calls.  For native calls, we'll mark EXIT on return.
    886              * For non-native calls, EXIT is marked in the RETURN op.
    887              */
    888             PC_TO_SELF();
    889             dvmReportInvoke(self, methodToCall);
    890         }
    891 
    892         if (!dvmIsNativeMethod(methodToCall)) {
    893             /*
    894              * "Call" interpreted code.  Reposition the PC, update the
    895              * frame pointer and other local state, and continue.
    896              */
    897             curMethod = methodToCall;
    898             self->interpSave.method = curMethod;
    899             methodClassDex = curMethod->clazz->pDvmDex;
    900             pc = methodToCall->insns;
    901             fp = newFp;
    902             self->interpSave.curFrame = fp;
    903 #ifdef EASY_GDB
    904             debugSaveArea = SAVEAREA_FROM_FP(newFp);
    905 #endif
    906             self->debugIsMethodEntry = true;        // profiling, debugging
    907             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
    908                 curMethod->name, curMethod->shorty);
    909             DUMP_REGS(curMethod, fp, true);         // show input args
    910             FINISH(0);                              // jump to method start
    911         } else {
    912             /* set this up for JNI locals, even if not a JNI native */
    913             newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
    914 
    915             self->interpSave.curFrame = newFp;
    916 
    917             DUMP_REGS(methodToCall, newFp, true);   // show input args
    918 
    919             if (self->interpBreak.ctl.subMode != 0) {
    920                 dvmReportPreNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
    921             }
    922 
    923             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
    924                   methodToCall->name, methodToCall->shorty);
    925 
    926             /*
    927              * Jump through native call bridge.  Because we leave no
    928              * space for locals on native calls, "newFp" points directly
    929              * to the method arguments.
    930              */
    931             (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
    932 
    933             if (self->interpBreak.ctl.subMode != 0) {
    934                 dvmReportPostNativeInvoke(methodToCall, self, newSaveArea->prevFrame);
    935             }
    936 
    937             /* pop frame off */
    938             dvmPopJniLocals(self, newSaveArea);
    939             self->interpSave.curFrame = newSaveArea->prevFrame;
    940             fp = newSaveArea->prevFrame;
    941 
    942             /*
    943              * If the native code threw an exception, or interpreted code
    944              * invoked by the native call threw one and nobody has cleared
    945              * it, jump to our local exception handling.
    946              */
    947             if (dvmCheckException(self)) {
    948                 ALOGV("Exception thrown by/below native code");
    949                 GOTO_exceptionThrown();
    950             }
    951 
    952             ILOGD("> retval=0x%llx (leaving native)", retval.j);
    953             ILOGD("> (return from native %s.%s to %s.%s %s)",
    954                 methodToCall->clazz->descriptor, methodToCall->name,
    955                 curMethod->clazz->descriptor, curMethod->name,
    956                 curMethod->shorty);
    957 
    958             //u2 invokeInstr = INST_INST(FETCH(0));
    959             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
    960                 invokeInstr <= OP_INVOKE_INTERFACE*/)
    961             {
    962                 FINISH(3);
    963             } else {
    964                 //ALOGE("Unknown invoke instr %02x at %d",
    965                 //    invokeInstr, (int) (pc - curMethod->insns));
    966                 assert(false);
    967             }
    968         }
    969     }
    970     assert(false);      // should not get here
    971 GOTO_TARGET_END
    972