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