Home | History | Annotate | Download | only in out
      1 /*
      2  * This file was generated automatically by gen-mterp.py for 'allstubs'.
      3  *
      4  * --> DO NOT EDIT <--
      5  */
      6 
      7 /* File: c/header.cpp */
      8 /*
      9  * Copyright (C) 2008 The Android Open Source Project
     10  *
     11  * Licensed under the Apache License, Version 2.0 (the "License");
     12  * you may not use this file except in compliance with the License.
     13  * You may obtain a copy of the License at
     14  *
     15  *      http://www.apache.org/licenses/LICENSE-2.0
     16  *
     17  * Unless required by applicable law or agreed to in writing, software
     18  * distributed under the License is distributed on an "AS IS" BASIS,
     19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20  * See the License for the specific language governing permissions and
     21  * limitations under the License.
     22  */
     23 
     24 /* common includes */
     25 #include "Dalvik.h"
     26 #include "interp/InterpDefs.h"
     27 #include "mterp/Mterp.h"
     28 #include <math.h>                   // needed for fmod, fmodf
     29 #include "mterp/common/FindInterface.h"
     30 
     31 /*
     32  * Configuration defines.  These affect the C implementations, i.e. the
     33  * portable interpreter(s) and C stubs.
     34  *
     35  * Some defines are controlled by the Makefile, e.g.:
     36  *   WITH_INSTR_CHECKS
     37  *   WITH_TRACKREF_CHECKS
     38  *   EASY_GDB
     39  *   NDEBUG
     40  */
     41 
     42 #ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
     43 # define CHECK_BRANCH_OFFSETS
     44 # define CHECK_REGISTER_INDICES
     45 #endif
     46 
     47 /*
     48  * Some architectures require 64-bit alignment for access to 64-bit data
     49  * types.  We can't just use pointers to copy 64-bit values out of our
     50  * interpreted register set, because gcc may assume the pointer target is
     51  * aligned and generate invalid code.
     52  *
     53  * There are two common approaches:
     54  *  (1) Use a union that defines a 32-bit pair and a 64-bit value.
     55  *  (2) Call memcpy().
     56  *
     57  * Depending upon what compiler you're using and what options are specified,
     58  * one may be faster than the other.  For example, the compiler might
     59  * convert a memcpy() of 8 bytes into a series of instructions and omit
     60  * the call.  The union version could cause some strange side-effects,
     61  * e.g. for a while ARM gcc thought it needed separate storage for each
     62  * inlined instance, and generated instructions to zero out ~700 bytes of
     63  * stack space at the top of the interpreter.
     64  *
     65  * The default is to use memcpy().  The current gcc for ARM seems to do
     66  * better with the union.
     67  */
     68 #if defined(__ARM_EABI__)
     69 # define NO_UNALIGN_64__UNION
     70 #endif
     71 
     72 
     73 //#define LOG_INSTR                   /* verbose debugging */
     74 /* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
     75 
     76 /*
     77  * Export another copy of the PC on every instruction; this is largely
     78  * redundant with EXPORT_PC and the debugger code.  This value can be
     79  * compared against what we have stored on the stack with EXPORT_PC to
     80  * help ensure that we aren't missing any export calls.
     81  */
     82 #if WITH_EXTRA_GC_CHECKS > 1
     83 # define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
     84 #else
     85 # define EXPORT_EXTRA_PC()
     86 #endif
     87 
     88 /*
     89  * Adjust the program counter.  "_offset" is a signed int, in 16-bit units.
     90  *
     91  * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
     92  *
     93  * We don't advance the program counter until we finish an instruction or
     94  * branch, because we do want to have to unroll the PC if there's an
     95  * exception.
     96  */
     97 #ifdef CHECK_BRANCH_OFFSETS
     98 # define ADJUST_PC(_offset) do {                                            \
     99         int myoff = _offset;        /* deref only once */                   \
    100         if (pc + myoff < curMethod->insns ||                                \
    101             pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
    102         {                                                                   \
    103             char* desc;                                                     \
    104             desc = dexProtoCopyMethodDescriptor(&curMethod->prototype);     \
    105             ALOGE("Invalid branch %d at 0x%04x in %s.%s %s",                 \
    106                 myoff, (int) (pc - curMethod->insns),                       \
    107                 curMethod->clazz->descriptor, curMethod->name, desc);       \
    108             free(desc);                                                     \
    109             dvmAbort();                                                     \
    110         }                                                                   \
    111         pc += myoff;                                                        \
    112         EXPORT_EXTRA_PC();                                                  \
    113     } while (false)
    114 #else
    115 # define ADJUST_PC(_offset) do {                                            \
    116         pc += _offset;                                                      \
    117         EXPORT_EXTRA_PC();                                                  \
    118     } while (false)
    119 #endif
    120 
    121 /*
    122  * If enabled, log instructions as we execute them.
    123  */
    124 #ifdef LOG_INSTR
    125 # define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
    126 # define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
    127 # define ILOG(_level, ...) do {                                             \
    128         char debugStrBuf[128];                                              \
    129         snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__);            \
    130         if (curMethod != NULL)                                              \
    131             ALOG(_level, LOG_TAG"i", "%-2d|%04x%s",                          \
    132                 self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
    133         else                                                                \
    134             ALOG(_level, LOG_TAG"i", "%-2d|####%s",                          \
    135                 self->threadId, debugStrBuf);                               \
    136     } while(false)
    137 void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
    138 # define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
    139 static const char kSpacing[] = "            ";
    140 #else
    141 # define ILOGD(...) ((void)0)
    142 # define ILOGV(...) ((void)0)
    143 # define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
    144 #endif
    145 
    146 /* get a long from an array of u4 */
    147 static inline s8 getLongFromArray(const u4* ptr, int idx)
    148 {
    149 #if defined(NO_UNALIGN_64__UNION)
    150     union { s8 ll; u4 parts[2]; } conv;
    151 
    152     ptr += idx;
    153     conv.parts[0] = ptr[0];
    154     conv.parts[1] = ptr[1];
    155     return conv.ll;
    156 #else
    157     s8 val;
    158     memcpy(&val, &ptr[idx], 8);
    159     return val;
    160 #endif
    161 }
    162 
    163 /* store a long into an array of u4 */
    164 static inline void putLongToArray(u4* ptr, int idx, s8 val)
    165 {
    166 #if defined(NO_UNALIGN_64__UNION)
    167     union { s8 ll; u4 parts[2]; } conv;
    168 
    169     ptr += idx;
    170     conv.ll = val;
    171     ptr[0] = conv.parts[0];
    172     ptr[1] = conv.parts[1];
    173 #else
    174     memcpy(&ptr[idx], &val, 8);
    175 #endif
    176 }
    177 
    178 /* get a double from an array of u4 */
    179 static inline double getDoubleFromArray(const u4* ptr, int idx)
    180 {
    181 #if defined(NO_UNALIGN_64__UNION)
    182     union { double d; u4 parts[2]; } conv;
    183 
    184     ptr += idx;
    185     conv.parts[0] = ptr[0];
    186     conv.parts[1] = ptr[1];
    187     return conv.d;
    188 #else
    189     double dval;
    190     memcpy(&dval, &ptr[idx], 8);
    191     return dval;
    192 #endif
    193 }
    194 
    195 /* store a double into an array of u4 */
    196 static inline void putDoubleToArray(u4* ptr, int idx, double dval)
    197 {
    198 #if defined(NO_UNALIGN_64__UNION)
    199     union { double d; u4 parts[2]; } conv;
    200 
    201     ptr += idx;
    202     conv.d = dval;
    203     ptr[0] = conv.parts[0];
    204     ptr[1] = conv.parts[1];
    205 #else
    206     memcpy(&ptr[idx], &dval, 8);
    207 #endif
    208 }
    209 
    210 /*
    211  * If enabled, validate the register number on every access.  Otherwise,
    212  * just do an array access.
    213  *
    214  * Assumes the existence of "u4* fp".
    215  *
    216  * "_idx" may be referenced more than once.
    217  */
    218 #ifdef CHECK_REGISTER_INDICES
    219 # define GET_REGISTER(_idx) \
    220     ( (_idx) < curMethod->registersSize ? \
    221         (fp[(_idx)]) : (assert(!"bad reg"),1969) )
    222 # define SET_REGISTER(_idx, _val) \
    223     ( (_idx) < curMethod->registersSize ? \
    224         (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
    225 # define GET_REGISTER_AS_OBJECT(_idx)       ((Object *)GET_REGISTER(_idx))
    226 # define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
    227 # define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
    228 # define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
    229 # define GET_REGISTER_WIDE(_idx) \
    230     ( (_idx) < curMethod->registersSize-1 ? \
    231         getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
    232 # define SET_REGISTER_WIDE(_idx, _val) \
    233     ( (_idx) < curMethod->registersSize-1 ? \
    234         (void)putLongToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
    235 # define GET_REGISTER_FLOAT(_idx) \
    236     ( (_idx) < curMethod->registersSize ? \
    237         (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
    238 # define SET_REGISTER_FLOAT(_idx, _val) \
    239     ( (_idx) < curMethod->registersSize ? \
    240         (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
    241 # define GET_REGISTER_DOUBLE(_idx) \
    242     ( (_idx) < curMethod->registersSize-1 ? \
    243         getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
    244 # define SET_REGISTER_DOUBLE(_idx, _val) \
    245     ( (_idx) < curMethod->registersSize-1 ? \
    246         (void)putDoubleToArray(fp, (_idx), (_val)) : assert(!"bad reg") )
    247 #else
    248 # define GET_REGISTER(_idx)                 (fp[(_idx)])
    249 # define SET_REGISTER(_idx, _val)           (fp[(_idx)] = (_val))
    250 # define GET_REGISTER_AS_OBJECT(_idx)       ((Object*) fp[(_idx)])
    251 # define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
    252 # define GET_REGISTER_INT(_idx)             ((s4)GET_REGISTER(_idx))
    253 # define SET_REGISTER_INT(_idx, _val)       SET_REGISTER(_idx, (s4)_val)
    254 # define GET_REGISTER_WIDE(_idx)            getLongFromArray(fp, (_idx))
    255 # define SET_REGISTER_WIDE(_idx, _val)      putLongToArray(fp, (_idx), (_val))
    256 # define GET_REGISTER_FLOAT(_idx)           (*((float*) &fp[(_idx)]))
    257 # define SET_REGISTER_FLOAT(_idx, _val)     (*((float*) &fp[(_idx)]) = (_val))
    258 # define GET_REGISTER_DOUBLE(_idx)          getDoubleFromArray(fp, (_idx))
    259 # define SET_REGISTER_DOUBLE(_idx, _val)    putDoubleToArray(fp, (_idx), (_val))
    260 #endif
    261 
    262 /*
    263  * Get 16 bits from the specified offset of the program counter.  We always
    264  * want to load 16 bits at a time from the instruction stream -- it's more
    265  * efficient than 8 and won't have the alignment problems that 32 might.
    266  *
    267  * Assumes existence of "const u2* pc".
    268  */
    269 #define FETCH(_offset)     (pc[(_offset)])
    270 
    271 /*
    272  * Extract instruction byte from 16-bit fetch (_inst is a u2).
    273  */
    274 #define INST_INST(_inst)    ((_inst) & 0xff)
    275 
    276 /*
    277  * Replace the opcode (used when handling breakpoints).  _opcode is a u1.
    278  */
    279 #define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
    280 
    281 /*
    282  * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
    283  */
    284 #define INST_A(_inst)       (((_inst) >> 8) & 0x0f)
    285 #define INST_B(_inst)       ((_inst) >> 12)
    286 
    287 /*
    288  * Get the 8-bit "vAA" 8-bit register index from the instruction word.
    289  * (_inst is u2)
    290  */
    291 #define INST_AA(_inst)      ((_inst) >> 8)
    292 
    293 /*
    294  * The current PC must be available to Throwable constructors, e.g.
    295  * those created by the various exception throw routines, so that the
    296  * exception stack trace can be generated correctly.  If we don't do this,
    297  * the offset within the current method won't be shown correctly.  See the
    298  * notes in Exception.c.
    299  *
    300  * This is also used to determine the address for precise GC.
    301  *
    302  * Assumes existence of "u4* fp" and "const u2* pc".
    303  */
    304 #define EXPORT_PC()         (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
    305 
    306 /*
    307  * Check to see if "obj" is NULL.  If so, throw an exception.  Assumes the
    308  * pc has already been exported to the stack.
    309  *
    310  * Perform additional checks on debug builds.
    311  *
    312  * Use this to check for NULL when the instruction handler calls into
    313  * something that could throw an exception (so we have already called
    314  * EXPORT_PC at the top).
    315  */
    316 static inline bool checkForNull(Object* obj)
    317 {
    318     if (obj == NULL) {
    319         dvmThrowNullPointerException(NULL);
    320         return false;
    321     }
    322 #ifdef WITH_EXTRA_OBJECT_VALIDATION
    323     if (!dvmIsHeapAddress(obj)) {
    324         ALOGE("Invalid object %p", obj);
    325         dvmAbort();
    326     }
    327 #endif
    328 #ifndef NDEBUG
    329     if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
    330         /* probable heap corruption */
    331         ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
    332         dvmAbort();
    333     }
    334 #endif
    335     return true;
    336 }
    337 
    338 /*
    339  * Check to see if "obj" is NULL.  If so, export the PC into the stack
    340  * frame and throw an exception.
    341  *
    342  * Perform additional checks on debug builds.
    343  *
    344  * Use this to check for NULL when the instruction handler doesn't do
    345  * anything else that can throw an exception.
    346  */
    347 static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
    348 {
    349     if (obj == NULL) {
    350         EXPORT_PC();
    351         dvmThrowNullPointerException(NULL);
    352         return false;
    353     }
    354 #ifdef WITH_EXTRA_OBJECT_VALIDATION
    355     if (!dvmIsHeapAddress(obj)) {
    356         ALOGE("Invalid object %p", obj);
    357         dvmAbort();
    358     }
    359 #endif
    360 #ifndef NDEBUG
    361     if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
    362         /* probable heap corruption */
    363         ALOGE("Invalid object class %p (in %p)", obj->clazz, obj);
    364         dvmAbort();
    365     }
    366 #endif
    367     return true;
    368 }
    369 
    370 /* File: cstubs/stubdefs.cpp */
    371 /*
    372  * In the C mterp stubs, "goto" is a function call followed immediately
    373  * by a return.
    374  */
    375 
    376 #define GOTO_TARGET_DECL(_target, ...)                                      \
    377     extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);
    378 
    379 /* (void)xxx to quiet unused variable compiler warnings. */
    380 #define GOTO_TARGET(_target, ...)                                           \
    381     void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
    382         u2 ref, vsrc1, vsrc2, vdst;                                         \
    383         u2 inst = FETCH(0);                                                 \
    384         const Method* methodToCall;                                         \
    385         StackSaveArea* debugSaveArea;                                       \
    386         (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
    387         (void)methodToCall; (void)debugSaveArea;
    388 
    389 #define GOTO_TARGET_END }
    390 
    391 /*
    392  * Redefine what used to be local variable accesses into Thread struct
    393  * references.  (These are undefined down in "footer.cpp".)
    394  */
    395 #define retval                  self->interpSave.retval
    396 #define pc                      self->interpSave.pc
    397 #define fp                      self->interpSave.curFrame
    398 #define curMethod               self->interpSave.method
    399 #define methodClassDex          self->interpSave.methodClassDex
    400 #define debugTrackedRefStart    self->interpSave.debugTrackedRefStart
    401 
    402 /* ugh */
    403 #define STUB_HACK(x) x
    404 #if defined(WITH_JIT)
    405 #define JIT_STUB_HACK(x) x
    406 #else
    407 #define JIT_STUB_HACK(x)
    408 #endif
    409 
    410 /*
    411  * InterpSave's pc and fp must be valid when breaking out to a
    412  * "Reportxxx" routine.  Because the portable interpreter uses local
    413  * variables for these, we must flush prior.  Stubs, however, use
    414  * the interpSave vars directly, so this is a nop for stubs.
    415  */
    416 #define PC_FP_TO_SELF()
    417 #define PC_TO_SELF()
    418 
    419 /*
    420  * Opcode handler framing macros.  Here, each opcode is a separate function
    421  * that takes a "self" argument and returns void.  We can't declare
    422  * these "static" because they may be called from an assembly stub.
    423  * (void)xxx to quiet unused variable compiler warnings.
    424  */
    425 #define HANDLE_OPCODE(_op)                                                  \
    426     extern "C" void dvmMterp_##_op(Thread* self);                           \
    427     void dvmMterp_##_op(Thread* self) {                                     \
    428         u4 ref;                                                             \
    429         u2 vsrc1, vsrc2, vdst;                                              \
    430         u2 inst = FETCH(0);                                                 \
    431         (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;
    432 
    433 #define OP_END }
    434 
    435 /*
    436  * Like the "portable" FINISH, but don't reload "inst", and return to caller
    437  * when done.  Further, debugger/profiler checks are handled
    438  * before handler execution in mterp, so we don't do them here either.
    439  */
    440 #if defined(WITH_JIT)
    441 #define FINISH(_offset) {                                                   \
    442         ADJUST_PC(_offset);                                                 \
    443         if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
    444             dvmCheckJit(pc, self);                                          \
    445         }                                                                   \
    446         return;                                                             \
    447     }
    448 #else
    449 #define FINISH(_offset) {                                                   \
    450         ADJUST_PC(_offset);                                                 \
    451         return;                                                             \
    452     }
    453 #endif
    454 
    455 
    456 /*
    457  * The "goto label" statements turn into function calls followed by
    458  * return statements.  Some of the functions take arguments, which in the
    459  * portable interpreter are handled by assigning values to globals.
    460  */
    461 
    462 #define GOTO_exceptionThrown()                                              \
    463     do {                                                                    \
    464         dvmMterp_exceptionThrown(self);                                     \
    465         return;                                                             \
    466     } while(false)
    467 
    468 #define GOTO_returnFromMethod()                                             \
    469     do {                                                                    \
    470         dvmMterp_returnFromMethod(self);                                    \
    471         return;                                                             \
    472     } while(false)
    473 
    474 #define GOTO_invoke(_target, _methodCallRange)                              \
    475     do {                                                                    \
    476         dvmMterp_##_target(self, _methodCallRange);                         \
    477         return;                                                             \
    478     } while(false)
    479 
    480 #define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
    481     do {                                                                    \
    482         dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
    483             _vsrc1, _vdst);                                                 \
    484         return;                                                             \
    485     } while(false)
    486 
    487 /*
    488  * As a special case, "goto bail" turns into a longjmp.
    489  */
    490 #define GOTO_bail()                                                         \
    491     dvmMterpStdBail(self, false);
    492 
    493 /*
    494  * Periodically check for thread suspension.
    495  *
    496  * While we're at it, see if a debugger has attached or the profiler has
    497  * started.
    498  */
    499 #define PERIODIC_CHECKS(_pcadj) {                              \
    500         if (dvmCheckSuspendQuick(self)) {                                   \
    501             EXPORT_PC();  /* need for precise GC */                         \
    502             dvmCheckSuspendPending(self);                                   \
    503         }                                                                   \
    504     }
    505 
    506 /* File: c/opcommon.cpp */
    507 /* forward declarations of goto targets */
    508 GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
    509 GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
    510 GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
    511 GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
    512 GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
    513 GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
    514 GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
    515 GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
    516 GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
    517     u2 count, u2 regs);
    518 GOTO_TARGET_DECL(returnFromMethod);
    519 GOTO_TARGET_DECL(exceptionThrown);
    520 
    521 /*
    522  * ===========================================================================
    523  *
    524  * What follows are opcode definitions shared between multiple opcodes with
    525  * minor substitutions handled by the C pre-processor.  These should probably
    526  * use the mterp substitution mechanism instead, with the code here moved
    527  * into common fragment files (like the asm "binop.S"), although it's hard
    528  * to give up the C preprocessor in favor of the much simpler text subst.
    529  *
    530  * ===========================================================================
    531  */
    532 
    533 #define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype)                \
    534     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    535         vdst = INST_A(inst);                                                \
    536         vsrc1 = INST_B(inst);                                               \
    537         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
    538         SET_REGISTER##_totype(vdst,                                         \
    539             GET_REGISTER##_fromtype(vsrc1));                                \
    540         FINISH(1);
    541 
    542 #define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype,       \
    543         _tovtype, _tortype)                                                 \
    544     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    545     {                                                                       \
    546         /* spec defines specific handling for +/- inf and NaN values */     \
    547         _fromvtype val;                                                     \
    548         _tovtype intMin, intMax, result;                                    \
    549         vdst = INST_A(inst);                                                \
    550         vsrc1 = INST_B(inst);                                               \
    551         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
    552         val = GET_REGISTER##_fromrtype(vsrc1);                              \
    553         intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1);                 \
    554         intMax = ~intMin;                                                   \
    555         result = (_tovtype) val;                                            \
    556         if (val >= intMax)          /* +inf */                              \
    557             result = intMax;                                                \
    558         else if (val <= intMin)     /* -inf */                              \
    559             result = intMin;                                                \
    560         else if (val != val)        /* NaN */                               \
    561             result = 0;                                                     \
    562         else                                                                \
    563             result = (_tovtype) val;                                        \
    564         SET_REGISTER##_tortype(vdst, result);                               \
    565     }                                                                       \
    566     FINISH(1);
    567 
    568 #define HANDLE_INT_TO_SMALL(_opcode, _opname, _type)                        \
    569     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    570         vdst = INST_A(inst);                                                \
    571         vsrc1 = INST_B(inst);                                               \
    572         ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1);                \
    573         SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1));                    \
    574         FINISH(1);
    575 
    576 /* NOTE: the comparison result is always a signed 4-byte integer */
    577 #define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal)          \
    578     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    579     {                                                                       \
    580         int result;                                                         \
    581         u2 regs;                                                            \
    582         _varType val1, val2;                                                \
    583         vdst = INST_AA(inst);                                               \
    584         regs = FETCH(1);                                                    \
    585         vsrc1 = regs & 0xff;                                                \
    586         vsrc2 = regs >> 8;                                                  \
    587         ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);         \
    588         val1 = GET_REGISTER##_type(vsrc1);                                  \
    589         val2 = GET_REGISTER##_type(vsrc2);                                  \
    590         if (val1 == val2)                                                   \
    591             result = 0;                                                     \
    592         else if (val1 < val2)                                               \
    593             result = -1;                                                    \
    594         else if (val1 > val2)                                               \
    595             result = 1;                                                     \
    596         else                                                                \
    597             result = (_nanVal);                                             \
    598         ILOGV("+ result=%d", result);                                       \
    599         SET_REGISTER(vdst, result);                                         \
    600     }                                                                       \
    601     FINISH(2);
    602 
    603 #define HANDLE_OP_IF_XX(_opcode, _opname, _cmp)                             \
    604     HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/)                                \
    605         vsrc1 = INST_A(inst);                                               \
    606         vsrc2 = INST_B(inst);                                               \
    607         if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) {       \
    608             int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
    609             ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2,        \
    610                 branchOffset);                                              \
    611             ILOGV("> branch taken");                                        \
    612             if (branchOffset < 0)                                           \
    613                 PERIODIC_CHECKS(branchOffset);                              \
    614             FINISH(branchOffset);                                           \
    615         } else {                                                            \
    616             ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2);             \
    617             FINISH(2);                                                      \
    618         }
    619 
    620 #define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp)                            \
    621     HANDLE_OPCODE(_opcode /*vAA, +BBBB*/)                                   \
    622         vsrc1 = INST_AA(inst);                                              \
    623         if ((s4) GET_REGISTER(vsrc1) _cmp 0) {                              \
    624             int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
    625             ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset);    \
    626             ILOGV("> branch taken");                                        \
    627             if (branchOffset < 0)                                           \
    628                 PERIODIC_CHECKS(branchOffset);                              \
    629             FINISH(branchOffset);                                           \
    630         } else {                                                            \
    631             ILOGV("|if-%s v%d,-", (_opname), vsrc1);                        \
    632             FINISH(2);                                                      \
    633         }
    634 
    635 #define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type)                    \
    636     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    637         vdst = INST_A(inst);                                                \
    638         vsrc1 = INST_B(inst);                                               \
    639         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
    640         SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx);    \
    641         FINISH(1);
    642 
    643 #define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv)                     \
    644     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    645     {                                                                       \
    646         u2 srcRegs;                                                         \
    647         vdst = INST_AA(inst);                                               \
    648         srcRegs = FETCH(1);                                                 \
    649         vsrc1 = srcRegs & 0xff;                                             \
    650         vsrc2 = srcRegs >> 8;                                               \
    651         ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
    652         if (_chkdiv != 0) {                                                 \
    653             s4 firstVal, secondVal, result;                                 \
    654             firstVal = GET_REGISTER(vsrc1);                                 \
    655             secondVal = GET_REGISTER(vsrc2);                                \
    656             if (secondVal == 0) {                                           \
    657                 EXPORT_PC();                                                \
    658                 dvmThrowArithmeticException("divide by zero");              \
    659                 GOTO_exceptionThrown();                                     \
    660             }                                                               \
    661             if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
    662                 if (_chkdiv == 1)                                           \
    663                     result = firstVal;  /* division */                      \
    664                 else                                                        \
    665                     result = 0;         /* remainder */                     \
    666             } else {                                                        \
    667                 result = firstVal _op secondVal;                            \
    668             }                                                               \
    669             SET_REGISTER(vdst, result);                                     \
    670         } else {                                                            \
    671             /* non-div/rem case */                                          \
    672             SET_REGISTER(vdst,                                              \
    673                 (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2));     \
    674         }                                                                   \
    675     }                                                                       \
    676     FINISH(2);
    677 
    678 #define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op)                     \
    679     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    680     {                                                                       \
    681         u2 srcRegs;                                                         \
    682         vdst = INST_AA(inst);                                               \
    683         srcRegs = FETCH(1);                                                 \
    684         vsrc1 = srcRegs & 0xff;                                             \
    685         vsrc2 = srcRegs >> 8;                                               \
    686         ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
    687         SET_REGISTER(vdst,                                                  \
    688             _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f));    \
    689     }                                                                       \
    690     FINISH(2);
    691 
    692 #define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv)               \
    693     HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/)                               \
    694         vdst = INST_A(inst);                                                \
    695         vsrc1 = INST_B(inst);                                               \
    696         vsrc2 = FETCH(1);                                                   \
    697         ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x",                             \
    698             (_opname), vdst, vsrc1, vsrc2);                                 \
    699         if (_chkdiv != 0) {                                                 \
    700             s4 firstVal, result;                                            \
    701             firstVal = GET_REGISTER(vsrc1);                                 \
    702             if ((s2) vsrc2 == 0) {                                          \
    703                 EXPORT_PC();                                                \
    704                 dvmThrowArithmeticException("divide by zero");              \
    705                 GOTO_exceptionThrown();                                     \
    706             }                                                               \
    707             if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) {         \
    708                 /* won't generate /lit16 instr for this; check anyway */    \
    709                 if (_chkdiv == 1)                                           \
    710                     result = firstVal;  /* division */                      \
    711                 else                                                        \
    712                     result = 0;         /* remainder */                     \
    713             } else {                                                        \
    714                 result = firstVal _op (s2) vsrc2;                           \
    715             }                                                               \
    716             SET_REGISTER(vdst, result);                                     \
    717         } else {                                                            \
    718             /* non-div/rem case */                                          \
    719             SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2);         \
    720         }                                                                   \
    721         FINISH(2);
    722 
    723 #define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv)                \
    724     HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
    725     {                                                                       \
    726         u2 litInfo;                                                         \
    727         vdst = INST_AA(inst);                                               \
    728         litInfo = FETCH(1);                                                 \
    729         vsrc1 = litInfo & 0xff;                                             \
    730         vsrc2 = litInfo >> 8;       /* constant */                          \
    731         ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
    732             (_opname), vdst, vsrc1, vsrc2);                                 \
    733         if (_chkdiv != 0) {                                                 \
    734             s4 firstVal, result;                                            \
    735             firstVal = GET_REGISTER(vsrc1);                                 \
    736             if ((s1) vsrc2 == 0) {                                          \
    737                 EXPORT_PC();                                                \
    738                 dvmThrowArithmeticException("divide by zero");              \
    739                 GOTO_exceptionThrown();                                     \
    740             }                                                               \
    741             if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) {         \
    742                 if (_chkdiv == 1)                                           \
    743                     result = firstVal;  /* division */                      \
    744                 else                                                        \
    745                     result = 0;         /* remainder */                     \
    746             } else {                                                        \
    747                 result = firstVal _op ((s1) vsrc2);                         \
    748             }                                                               \
    749             SET_REGISTER(vdst, result);                                     \
    750         } else {                                                            \
    751             SET_REGISTER(vdst,                                              \
    752                 (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2);                   \
    753         }                                                                   \
    754     }                                                                       \
    755     FINISH(2);
    756 
    757 #define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op)                \
    758     HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
    759     {                                                                       \
    760         u2 litInfo;                                                         \
    761         vdst = INST_AA(inst);                                               \
    762         litInfo = FETCH(1);                                                 \
    763         vsrc1 = litInfo & 0xff;                                             \
    764         vsrc2 = litInfo >> 8;       /* constant */                          \
    765         ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
    766             (_opname), vdst, vsrc1, vsrc2);                                 \
    767         SET_REGISTER(vdst,                                                  \
    768             _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f));                  \
    769     }                                                                       \
    770     FINISH(2);
    771 
    772 #define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv)               \
    773     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    774         vdst = INST_A(inst);                                                \
    775         vsrc1 = INST_B(inst);                                               \
    776         ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
    777         if (_chkdiv != 0) {                                                 \
    778             s4 firstVal, secondVal, result;                                 \
    779             firstVal = GET_REGISTER(vdst);                                  \
    780             secondVal = GET_REGISTER(vsrc1);                                \
    781             if (secondVal == 0) {                                           \
    782                 EXPORT_PC();                                                \
    783                 dvmThrowArithmeticException("divide by zero");              \
    784                 GOTO_exceptionThrown();                                     \
    785             }                                                               \
    786             if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
    787                 if (_chkdiv == 1)                                           \
    788                     result = firstVal;  /* division */                      \
    789                 else                                                        \
    790                     result = 0;         /* remainder */                     \
    791             } else {                                                        \
    792                 result = firstVal _op secondVal;                            \
    793             }                                                               \
    794             SET_REGISTER(vdst, result);                                     \
    795         } else {                                                            \
    796             SET_REGISTER(vdst,                                              \
    797                 (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1));      \
    798         }                                                                   \
    799         FINISH(1);
    800 
    801 #define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op)               \
    802     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    803         vdst = INST_A(inst);                                                \
    804         vsrc1 = INST_B(inst);                                               \
    805         ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
    806         SET_REGISTER(vdst,                                                  \
    807             _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f));     \
    808         FINISH(1);
    809 
    810 #define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv)                    \
    811     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    812     {                                                                       \
    813         u2 srcRegs;                                                         \
    814         vdst = INST_AA(inst);                                               \
    815         srcRegs = FETCH(1);                                                 \
    816         vsrc1 = srcRegs & 0xff;                                             \
    817         vsrc2 = srcRegs >> 8;                                               \
    818         ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
    819         if (_chkdiv != 0) {                                                 \
    820             s8 firstVal, secondVal, result;                                 \
    821             firstVal = GET_REGISTER_WIDE(vsrc1);                            \
    822             secondVal = GET_REGISTER_WIDE(vsrc2);                           \
    823             if (secondVal == 0LL) {                                         \
    824                 EXPORT_PC();                                                \
    825                 dvmThrowArithmeticException("divide by zero");              \
    826                 GOTO_exceptionThrown();                                     \
    827             }                                                               \
    828             if ((u8)firstVal == 0x8000000000000000ULL &&                    \
    829                 secondVal == -1LL)                                          \
    830             {                                                               \
    831                 if (_chkdiv == 1)                                           \
    832                     result = firstVal;  /* division */                      \
    833                 else                                                        \
    834                     result = 0;         /* remainder */                     \
    835             } else {                                                        \
    836                 result = firstVal _op secondVal;                            \
    837             }                                                               \
    838             SET_REGISTER_WIDE(vdst, result);                                \
    839         } else {                                                            \
    840             SET_REGISTER_WIDE(vdst,                                         \
    841                 (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
    842         }                                                                   \
    843     }                                                                       \
    844     FINISH(2);
    845 
    846 #define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op)                    \
    847     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    848     {                                                                       \
    849         u2 srcRegs;                                                         \
    850         vdst = INST_AA(inst);                                               \
    851         srcRegs = FETCH(1);                                                 \
    852         vsrc1 = srcRegs & 0xff;                                             \
    853         vsrc2 = srcRegs >> 8;                                               \
    854         ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
    855         SET_REGISTER_WIDE(vdst,                                             \
    856             _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
    857     }                                                                       \
    858     FINISH(2);
    859 
    860 #define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv)              \
    861     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    862         vdst = INST_A(inst);                                                \
    863         vsrc1 = INST_B(inst);                                               \
    864         ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
    865         if (_chkdiv != 0) {                                                 \
    866             s8 firstVal, secondVal, result;                                 \
    867             firstVal = GET_REGISTER_WIDE(vdst);                             \
    868             secondVal = GET_REGISTER_WIDE(vsrc1);                           \
    869             if (secondVal == 0LL) {                                         \
    870                 EXPORT_PC();                                                \
    871                 dvmThrowArithmeticException("divide by zero");              \
    872                 GOTO_exceptionThrown();                                     \
    873             }                                                               \
    874             if ((u8)firstVal == 0x8000000000000000ULL &&                    \
    875                 secondVal == -1LL)                                          \
    876             {                                                               \
    877                 if (_chkdiv == 1)                                           \
    878                     result = firstVal;  /* division */                      \
    879                 else                                                        \
    880                     result = 0;         /* remainder */                     \
    881             } else {                                                        \
    882                 result = firstVal _op secondVal;                            \
    883             }                                                               \
    884             SET_REGISTER_WIDE(vdst, result);                                \
    885         } else {                                                            \
    886             SET_REGISTER_WIDE(vdst,                                         \
    887                 (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
    888         }                                                                   \
    889         FINISH(1);
    890 
    891 #define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op)              \
    892     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    893         vdst = INST_A(inst);                                                \
    894         vsrc1 = INST_B(inst);                                               \
    895         ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
    896         SET_REGISTER_WIDE(vdst,                                             \
    897             _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
    898         FINISH(1);
    899 
    900 #define HANDLE_OP_X_FLOAT(_opcode, _opname, _op)                            \
    901     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    902     {                                                                       \
    903         u2 srcRegs;                                                         \
    904         vdst = INST_AA(inst);                                               \
    905         srcRegs = FETCH(1);                                                 \
    906         vsrc1 = srcRegs & 0xff;                                             \
    907         vsrc2 = srcRegs >> 8;                                               \
    908         ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);      \
    909         SET_REGISTER_FLOAT(vdst,                                            \
    910             GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2));       \
    911     }                                                                       \
    912     FINISH(2);
    913 
    914 #define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op)                           \
    915     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    916     {                                                                       \
    917         u2 srcRegs;                                                         \
    918         vdst = INST_AA(inst);                                               \
    919         srcRegs = FETCH(1);                                                 \
    920         vsrc1 = srcRegs & 0xff;                                             \
    921         vsrc2 = srcRegs >> 8;                                               \
    922         ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);     \
    923         SET_REGISTER_DOUBLE(vdst,                                           \
    924             GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2));     \
    925     }                                                                       \
    926     FINISH(2);
    927 
    928 #define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op)                      \
    929     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    930         vdst = INST_A(inst);                                                \
    931         vsrc1 = INST_B(inst);                                               \
    932         ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1);           \
    933         SET_REGISTER_FLOAT(vdst,                                            \
    934             GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1));        \
    935         FINISH(1);
    936 
    937 #define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op)                     \
    938     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
    939         vdst = INST_A(inst);                                                \
    940         vsrc1 = INST_B(inst);                                               \
    941         ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1);          \
    942         SET_REGISTER_DOUBLE(vdst,                                           \
    943             GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1));      \
    944         FINISH(1);
    945 
    946 #define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize)                   \
    947     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    948     {                                                                       \
    949         ArrayObject* arrayObj;                                              \
    950         u2 arrayInfo;                                                       \
    951         EXPORT_PC();                                                        \
    952         vdst = INST_AA(inst);                                               \
    953         arrayInfo = FETCH(1);                                               \
    954         vsrc1 = arrayInfo & 0xff;    /* array ptr */                        \
    955         vsrc2 = arrayInfo >> 8;      /* index */                            \
    956         ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
    957         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
    958         if (!checkForNull((Object*) arrayObj))                              \
    959             GOTO_exceptionThrown();                                         \
    960         if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
    961             dvmThrowArrayIndexOutOfBoundsException(                         \
    962                 arrayObj->length, GET_REGISTER(vsrc2));                     \
    963             GOTO_exceptionThrown();                                         \
    964         }                                                                   \
    965         SET_REGISTER##_regsize(vdst,                                        \
    966             ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
    967         ILOGV("+ AGET[%d]=%#x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));   \
    968     }                                                                       \
    969     FINISH(2);
    970 
    971 #define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize)                   \
    972     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
    973     {                                                                       \
    974         ArrayObject* arrayObj;                                              \
    975         u2 arrayInfo;                                                       \
    976         EXPORT_PC();                                                        \
    977         vdst = INST_AA(inst);       /* AA: source value */                  \
    978         arrayInfo = FETCH(1);                                               \
    979         vsrc1 = arrayInfo & 0xff;   /* BB: array ptr */                     \
    980         vsrc2 = arrayInfo >> 8;     /* CC: index */                         \
    981         ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
    982         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
    983         if (!checkForNull((Object*) arrayObj))                              \
    984             GOTO_exceptionThrown();                                         \
    985         if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
    986             dvmThrowArrayIndexOutOfBoundsException(                         \
    987                 arrayObj->length, GET_REGISTER(vsrc2));                     \
    988             GOTO_exceptionThrown();                                         \
    989         }                                                                   \
    990         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
    991         ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)] =          \
    992             GET_REGISTER##_regsize(vdst);                                   \
    993     }                                                                       \
    994     FINISH(2);
    995 
    996 /*
    997  * It's possible to get a bad value out of a field with sub-32-bit stores
    998  * because the -quick versions always operate on 32 bits.  Consider:
    999  *   short foo = -1  (sets a 32-bit register to 0xffffffff)
   1000  *   iput-quick foo  (writes all 32 bits to the field)
   1001  *   short bar = 1   (sets a 32-bit register to 0x00000001)
   1002  *   iput-short      (writes the low 16 bits to the field)
   1003  *   iget-quick foo  (reads all 32 bits from the field, yielding 0xffff0001)
   1004  * This can only happen when optimized and non-optimized code has interleaved
   1005  * access to the same field.  This is unlikely but possible.
   1006  *
   1007  * The easiest way to fix this is to always read/write 32 bits at a time.  On
   1008  * a device with a 16-bit data bus this is sub-optimal.  (The alternative
   1009  * approach is to have sub-int versions of iget-quick, but now we're wasting
   1010  * Dalvik instruction space and making it less likely that handler code will
   1011  * already be in the CPU i-cache.)
   1012  */
   1013 #define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize)                   \
   1014     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
   1015     {                                                                       \
   1016         InstField* ifield;                                                  \
   1017         Object* obj;                                                        \
   1018         EXPORT_PC();                                                        \
   1019         vdst = INST_A(inst);                                                \
   1020         vsrc1 = INST_B(inst);   /* object ptr */                            \
   1021         ref = FETCH(1);         /* field ref */                             \
   1022         ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
   1023         obj = (Object*) GET_REGISTER(vsrc1);                                \
   1024         if (!checkForNull(obj))                                             \
   1025             GOTO_exceptionThrown();                                         \
   1026         ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
   1027         if (ifield == NULL) {                                               \
   1028             ifield = dvmResolveInstField(curMethod->clazz, ref);            \
   1029             if (ifield == NULL)                                             \
   1030                 GOTO_exceptionThrown();                                     \
   1031         }                                                                   \
   1032         SET_REGISTER##_regsize(vdst,                                        \
   1033             dvmGetField##_ftype(obj, ifield->byteOffset));                  \
   1034         ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name,                   \
   1035             (u8) GET_REGISTER##_regsize(vdst));                             \
   1036     }                                                                       \
   1037     FINISH(2);
   1038 
   1039 #define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
   1040     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
   1041     {                                                                       \
   1042         Object* obj;                                                        \
   1043         vdst = INST_A(inst);                                                \
   1044         vsrc1 = INST_B(inst);   /* object ptr */                            \
   1045         ref = FETCH(1);         /* field offset */                          \
   1046         ILOGV("|iget%s-quick v%d,v%d,field@+%u",                            \
   1047             (_opname), vdst, vsrc1, ref);                                   \
   1048         obj = (Object*) GET_REGISTER(vsrc1);                                \
   1049         if (!checkForNullExportPC(obj, fp, pc))                             \
   1050             GOTO_exceptionThrown();                                         \
   1051         SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref));        \
   1052         ILOGV("+ IGETQ %d=0x%08llx", ref,                                   \
   1053             (u8) GET_REGISTER##_regsize(vdst));                             \
   1054     }                                                                       \
   1055     FINISH(2);
   1056 
   1057 #define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize)                   \
   1058     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
   1059     {                                                                       \
   1060         InstField* ifield;                                                  \
   1061         Object* obj;                                                        \
   1062         EXPORT_PC();                                                        \
   1063         vdst = INST_A(inst);                                                \
   1064         vsrc1 = INST_B(inst);   /* object ptr */                            \
   1065         ref = FETCH(1);         /* field ref */                             \
   1066         ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
   1067         obj = (Object*) GET_REGISTER(vsrc1);                                \
   1068         if (!checkForNull(obj))                                             \
   1069             GOTO_exceptionThrown();                                         \
   1070         ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
   1071         if (ifield == NULL) {                                               \
   1072             ifield = dvmResolveInstField(curMethod->clazz, ref);            \
   1073             if (ifield == NULL)                                             \
   1074                 GOTO_exceptionThrown();                                     \
   1075         }                                                                   \
   1076         dvmSetField##_ftype(obj, ifield->byteOffset,                        \
   1077             GET_REGISTER##_regsize(vdst));                                  \
   1078         ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name,                   \
   1079             (u8) GET_REGISTER##_regsize(vdst));                             \
   1080     }                                                                       \
   1081     FINISH(2);
   1082 
   1083 #define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
   1084     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
   1085     {                                                                       \
   1086         Object* obj;                                                        \
   1087         vdst = INST_A(inst);                                                \
   1088         vsrc1 = INST_B(inst);   /* object ptr */                            \
   1089         ref = FETCH(1);         /* field offset */                          \
   1090         ILOGV("|iput%s-quick v%d,v%d,field@0x%04x",                         \
   1091             (_opname), vdst, vsrc1, ref);                                   \
   1092         obj = (Object*) GET_REGISTER(vsrc1);                                \
   1093         if (!checkForNullExportPC(obj, fp, pc))                             \
   1094             GOTO_exceptionThrown();                                         \
   1095         dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst));        \
   1096         ILOGV("+ IPUTQ %d=0x%08llx", ref,                                   \
   1097             (u8) GET_REGISTER##_regsize(vdst));                             \
   1098     }                                                                       \
   1099     FINISH(2);
   1100 
   1101 /*
   1102  * The JIT needs dvmDexGetResolvedField() to return non-null.
   1103  * Because the portable interpreter is not involved with the JIT
   1104  * and trace building, we only need the extra check here when this
   1105  * code is massaged into a stub called from an assembly interpreter.
   1106  * This is controlled by the JIT_STUB_HACK maco.
   1107  */
   1108 
   1109 #define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize)                   \
   1110     HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
   1111     {                                                                       \
   1112         StaticField* sfield;                                                \
   1113         vdst = INST_AA(inst);                                               \
   1114         ref = FETCH(1);         /* field ref */                             \
   1115         ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
   1116         sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
   1117         if (sfield == NULL) {                                               \
   1118             EXPORT_PC();                                                    \
   1119             sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
   1120             if (sfield == NULL)                                             \
   1121                 GOTO_exceptionThrown();                                     \
   1122             if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
   1123                 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
   1124             }                                                               \
   1125         }                                                                   \
   1126         SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
   1127         ILOGV("+ SGET '%s'=0x%08llx",                                       \
   1128             sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
   1129     }                                                                       \
   1130     FINISH(2);
   1131 
   1132 #define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize)                   \
   1133     HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
   1134     {                                                                       \
   1135         StaticField* sfield;                                                \
   1136         vdst = INST_AA(inst);                                               \
   1137         ref = FETCH(1);         /* field ref */                             \
   1138         ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
   1139         sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
   1140         if (sfield == NULL) {                                               \
   1141             EXPORT_PC();                                                    \
   1142             sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
   1143             if (sfield == NULL)                                             \
   1144                 GOTO_exceptionThrown();                                     \
   1145             if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
   1146                 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
   1147             }                                                               \
   1148         }                                                                   \
   1149         dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
   1150         ILOGV("+ SPUT '%s'=0x%08llx",                                       \
   1151             sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
   1152     }                                                                       \
   1153     FINISH(2);
   1154 
   1155 /* File: c/OP_NOP.cpp */
   1156 HANDLE_OPCODE(OP_NOP)
   1157     FINISH(1);
   1158 OP_END
   1159 
   1160 /* File: c/OP_MOVE.cpp */
   1161 HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
   1162     vdst = INST_A(inst);
   1163     vsrc1 = INST_B(inst);
   1164     ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
   1165         (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
   1166         kSpacing, vdst, GET_REGISTER(vsrc1));
   1167     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1168     FINISH(1);
   1169 OP_END
   1170 
   1171 /* File: c/OP_MOVE_FROM16.cpp */
   1172 HANDLE_OPCODE(OP_MOVE_FROM16 /*vAA, vBBBB*/)
   1173     vdst = INST_AA(inst);
   1174     vsrc1 = FETCH(1);
   1175     ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
   1176         (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
   1177         kSpacing, vdst, GET_REGISTER(vsrc1));
   1178     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1179     FINISH(2);
   1180 OP_END
   1181 
   1182 /* File: c/OP_MOVE_16.cpp */
   1183 HANDLE_OPCODE(OP_MOVE_16 /*vAAAA, vBBBB*/)
   1184     vdst = FETCH(1);
   1185     vsrc1 = FETCH(2);
   1186     ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
   1187         (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
   1188         kSpacing, vdst, GET_REGISTER(vsrc1));
   1189     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1190     FINISH(3);
   1191 OP_END
   1192 
   1193 /* File: c/OP_MOVE_WIDE.cpp */
   1194 HANDLE_OPCODE(OP_MOVE_WIDE /*vA, vB*/)
   1195     /* IMPORTANT: must correctly handle overlapping registers, e.g. both
   1196      * "move-wide v6, v7" and "move-wide v7, v6" */
   1197     vdst = INST_A(inst);
   1198     vsrc1 = INST_B(inst);
   1199     ILOGV("|move-wide v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
   1200         kSpacing+5, vdst, GET_REGISTER_WIDE(vsrc1));
   1201     SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
   1202     FINISH(1);
   1203 OP_END
   1204 
   1205 /* File: c/OP_MOVE_WIDE_FROM16.cpp */
   1206 HANDLE_OPCODE(OP_MOVE_WIDE_FROM16 /*vAA, vBBBB*/)
   1207     vdst = INST_AA(inst);
   1208     vsrc1 = FETCH(1);
   1209     ILOGV("|move-wide/from16 v%d,v%d  (v%d=0x%08llx)", vdst, vsrc1,
   1210         vdst, GET_REGISTER_WIDE(vsrc1));
   1211     SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
   1212     FINISH(2);
   1213 OP_END
   1214 
   1215 /* File: c/OP_MOVE_WIDE_16.cpp */
   1216 HANDLE_OPCODE(OP_MOVE_WIDE_16 /*vAAAA, vBBBB*/)
   1217     vdst = FETCH(1);
   1218     vsrc1 = FETCH(2);
   1219     ILOGV("|move-wide/16 v%d,v%d %s(v%d=0x%08llx)", vdst, vsrc1,
   1220         kSpacing+8, vdst, GET_REGISTER_WIDE(vsrc1));
   1221     SET_REGISTER_WIDE(vdst, GET_REGISTER_WIDE(vsrc1));
   1222     FINISH(3);
   1223 OP_END
   1224 
   1225 /* File: c/OP_MOVE_OBJECT.cpp */
   1226 /* File: c/OP_MOVE.cpp */
   1227 HANDLE_OPCODE(OP_MOVE_OBJECT /*vA, vB*/)
   1228     vdst = INST_A(inst);
   1229     vsrc1 = INST_B(inst);
   1230     ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
   1231         (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
   1232         kSpacing, vdst, GET_REGISTER(vsrc1));
   1233     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1234     FINISH(1);
   1235 OP_END
   1236 
   1237 
   1238 /* File: c/OP_MOVE_OBJECT_FROM16.cpp */
   1239 /* File: c/OP_MOVE_FROM16.cpp */
   1240 HANDLE_OPCODE(OP_MOVE_OBJECT_FROM16 /*vAA, vBBBB*/)
   1241     vdst = INST_AA(inst);
   1242     vsrc1 = FETCH(1);
   1243     ILOGV("|move%s/from16 v%d,v%d %s(v%d=0x%08x)",
   1244         (INST_INST(inst) == OP_MOVE_FROM16) ? "" : "-object", vdst, vsrc1,
   1245         kSpacing, vdst, GET_REGISTER(vsrc1));
   1246     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1247     FINISH(2);
   1248 OP_END
   1249 
   1250 
   1251 /* File: c/OP_MOVE_OBJECT_16.cpp */
   1252 /* File: c/OP_MOVE_16.cpp */
   1253 HANDLE_OPCODE(OP_MOVE_OBJECT_16 /*vAAAA, vBBBB*/)
   1254     vdst = FETCH(1);
   1255     vsrc1 = FETCH(2);
   1256     ILOGV("|move%s/16 v%d,v%d %s(v%d=0x%08x)",
   1257         (INST_INST(inst) == OP_MOVE_16) ? "" : "-object", vdst, vsrc1,
   1258         kSpacing, vdst, GET_REGISTER(vsrc1));
   1259     SET_REGISTER(vdst, GET_REGISTER(vsrc1));
   1260     FINISH(3);
   1261 OP_END
   1262 
   1263 
   1264 /* File: c/OP_MOVE_RESULT.cpp */
   1265 HANDLE_OPCODE(OP_MOVE_RESULT /*vAA*/)
   1266     vdst = INST_AA(inst);
   1267     ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
   1268          (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
   1269          vdst, kSpacing+4, vdst,retval.i);
   1270     SET_REGISTER(vdst, retval.i);
   1271     FINISH(1);
   1272 OP_END
   1273 
   1274 /* File: c/OP_MOVE_RESULT_WIDE.cpp */
   1275 HANDLE_OPCODE(OP_MOVE_RESULT_WIDE /*vAA*/)
   1276     vdst = INST_AA(inst);
   1277     ILOGV("|move-result-wide v%d %s(0x%08llx)", vdst, kSpacing, retval.j);
   1278     SET_REGISTER_WIDE(vdst, retval.j);
   1279     FINISH(1);
   1280 OP_END
   1281 
   1282 /* File: c/OP_MOVE_RESULT_OBJECT.cpp */
   1283 /* File: c/OP_MOVE_RESULT.cpp */
   1284 HANDLE_OPCODE(OP_MOVE_RESULT_OBJECT /*vAA*/)
   1285     vdst = INST_AA(inst);
   1286     ILOGV("|move-result%s v%d %s(v%d=0x%08x)",
   1287          (INST_INST(inst) == OP_MOVE_RESULT) ? "" : "-object",
   1288          vdst, kSpacing+4, vdst,retval.i);
   1289     SET_REGISTER(vdst, retval.i);
   1290     FINISH(1);
   1291 OP_END
   1292 
   1293 
   1294 /* File: c/OP_MOVE_EXCEPTION.cpp */
   1295 HANDLE_OPCODE(OP_MOVE_EXCEPTION /*vAA*/)
   1296     vdst = INST_AA(inst);
   1297     ILOGV("|move-exception v%d", vdst);
   1298     assert(self->exception != NULL);
   1299     SET_REGISTER(vdst, (u4)self->exception);
   1300     dvmClearException(self);
   1301     FINISH(1);
   1302 OP_END
   1303 
   1304 /* File: c/OP_RETURN_VOID.cpp */
   1305 HANDLE_OPCODE(OP_RETURN_VOID /**/)
   1306     ILOGV("|return-void");
   1307 #ifndef NDEBUG
   1308     retval.j = 0xababababULL;    // placate valgrind
   1309 #endif
   1310     GOTO_returnFromMethod();
   1311 OP_END
   1312 
   1313 /* File: c/OP_RETURN.cpp */
   1314 HANDLE_OPCODE(OP_RETURN /*vAA*/)
   1315     vsrc1 = INST_AA(inst);
   1316     ILOGV("|return%s v%d",
   1317         (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
   1318     retval.i = GET_REGISTER(vsrc1);
   1319     GOTO_returnFromMethod();
   1320 OP_END
   1321 
   1322 /* File: c/OP_RETURN_WIDE.cpp */
   1323 HANDLE_OPCODE(OP_RETURN_WIDE /*vAA*/)
   1324     vsrc1 = INST_AA(inst);
   1325     ILOGV("|return-wide v%d", vsrc1);
   1326     retval.j = GET_REGISTER_WIDE(vsrc1);
   1327     GOTO_returnFromMethod();
   1328 OP_END
   1329 
   1330 /* File: c/OP_RETURN_OBJECT.cpp */
   1331 /* File: c/OP_RETURN.cpp */
   1332 HANDLE_OPCODE(OP_RETURN_OBJECT /*vAA*/)
   1333     vsrc1 = INST_AA(inst);
   1334     ILOGV("|return%s v%d",
   1335         (INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
   1336     retval.i = GET_REGISTER(vsrc1);
   1337     GOTO_returnFromMethod();
   1338 OP_END
   1339 
   1340 
   1341 /* File: c/OP_CONST_4.cpp */
   1342 HANDLE_OPCODE(OP_CONST_4 /*vA, #+B*/)
   1343     {
   1344         s4 tmp;
   1345 
   1346         vdst = INST_A(inst);
   1347         tmp = (s4) (INST_B(inst) << 28) >> 28;  // sign extend 4-bit value
   1348         ILOGV("|const/4 v%d,#0x%02x", vdst, (s4)tmp);
   1349         SET_REGISTER(vdst, tmp);
   1350     }
   1351     FINISH(1);
   1352 OP_END
   1353 
   1354 /* File: c/OP_CONST_16.cpp */
   1355 HANDLE_OPCODE(OP_CONST_16 /*vAA, #+BBBB*/)
   1356     vdst = INST_AA(inst);
   1357     vsrc1 = FETCH(1);
   1358     ILOGV("|const/16 v%d,#0x%04x", vdst, (s2)vsrc1);
   1359     SET_REGISTER(vdst, (s2) vsrc1);
   1360     FINISH(2);
   1361 OP_END
   1362 
   1363 /* File: c/OP_CONST.cpp */
   1364 HANDLE_OPCODE(OP_CONST /*vAA, #+BBBBBBBB*/)
   1365     {
   1366         u4 tmp;
   1367 
   1368         vdst = INST_AA(inst);
   1369         tmp = FETCH(1);
   1370         tmp |= (u4)FETCH(2) << 16;
   1371         ILOGV("|const v%d,#0x%08x", vdst, tmp);
   1372         SET_REGISTER(vdst, tmp);
   1373     }
   1374     FINISH(3);
   1375 OP_END
   1376 
   1377 /* File: c/OP_CONST_HIGH16.cpp */
   1378 HANDLE_OPCODE(OP_CONST_HIGH16 /*vAA, #+BBBB0000*/)
   1379     vdst = INST_AA(inst);
   1380     vsrc1 = FETCH(1);
   1381     ILOGV("|const/high16 v%d,#0x%04x0000", vdst, vsrc1);
   1382     SET_REGISTER(vdst, vsrc1 << 16);
   1383     FINISH(2);
   1384 OP_END
   1385 
   1386 /* File: c/OP_CONST_WIDE_16.cpp */
   1387 HANDLE_OPCODE(OP_CONST_WIDE_16 /*vAA, #+BBBB*/)
   1388     vdst = INST_AA(inst);
   1389     vsrc1 = FETCH(1);
   1390     ILOGV("|const-wide/16 v%d,#0x%04x", vdst, (s2)vsrc1);
   1391     SET_REGISTER_WIDE(vdst, (s2)vsrc1);
   1392     FINISH(2);
   1393 OP_END
   1394 
   1395 /* File: c/OP_CONST_WIDE_32.cpp */
   1396 HANDLE_OPCODE(OP_CONST_WIDE_32 /*vAA, #+BBBBBBBB*/)
   1397     {
   1398         u4 tmp;
   1399 
   1400         vdst = INST_AA(inst);
   1401         tmp = FETCH(1);
   1402         tmp |= (u4)FETCH(2) << 16;
   1403         ILOGV("|const-wide/32 v%d,#0x%08x", vdst, tmp);
   1404         SET_REGISTER_WIDE(vdst, (s4) tmp);
   1405     }
   1406     FINISH(3);
   1407 OP_END
   1408 
   1409 /* File: c/OP_CONST_WIDE.cpp */
   1410 HANDLE_OPCODE(OP_CONST_WIDE /*vAA, #+BBBBBBBBBBBBBBBB*/)
   1411     {
   1412         u8 tmp;
   1413 
   1414         vdst = INST_AA(inst);
   1415         tmp = FETCH(1);
   1416         tmp |= (u8)FETCH(2) << 16;
   1417         tmp |= (u8)FETCH(3) << 32;
   1418         tmp |= (u8)FETCH(4) << 48;
   1419         ILOGV("|const-wide v%d,#0x%08llx", vdst, tmp);
   1420         SET_REGISTER_WIDE(vdst, tmp);
   1421     }
   1422     FINISH(5);
   1423 OP_END
   1424 
   1425 /* File: c/OP_CONST_WIDE_HIGH16.cpp */
   1426 HANDLE_OPCODE(OP_CONST_WIDE_HIGH16 /*vAA, #+BBBB000000000000*/)
   1427     vdst = INST_AA(inst);
   1428     vsrc1 = FETCH(1);
   1429     ILOGV("|const-wide/high16 v%d,#0x%04x000000000000", vdst, vsrc1);
   1430     SET_REGISTER_WIDE(vdst, ((u8) vsrc1) << 48);
   1431     FINISH(2);
   1432 OP_END
   1433 
   1434 /* File: c/OP_CONST_STRING.cpp */
   1435 HANDLE_OPCODE(OP_CONST_STRING /*vAA, string@BBBB*/)
   1436     {
   1437         StringObject* strObj;
   1438 
   1439         vdst = INST_AA(inst);
   1440         ref = FETCH(1);
   1441         ILOGV("|const-string v%d string@0x%04x", vdst, ref);
   1442         strObj = dvmDexGetResolvedString(methodClassDex, ref);
   1443         if (strObj == NULL) {
   1444             EXPORT_PC();
   1445             strObj = dvmResolveString(curMethod->clazz, ref);
   1446             if (strObj == NULL)
   1447                 GOTO_exceptionThrown();
   1448         }
   1449         SET_REGISTER(vdst, (u4) strObj);
   1450     }
   1451     FINISH(2);
   1452 OP_END
   1453 
   1454 /* File: c/OP_CONST_STRING_JUMBO.cpp */
   1455 HANDLE_OPCODE(OP_CONST_STRING_JUMBO /*vAA, string@BBBBBBBB*/)
   1456     {
   1457         StringObject* strObj;
   1458         u4 tmp;
   1459 
   1460         vdst = INST_AA(inst);
   1461         tmp = FETCH(1);
   1462         tmp |= (u4)FETCH(2) << 16;
   1463         ILOGV("|const-string/jumbo v%d string@0x%08x", vdst, tmp);
   1464         strObj = dvmDexGetResolvedString(methodClassDex, tmp);
   1465         if (strObj == NULL) {
   1466             EXPORT_PC();
   1467             strObj = dvmResolveString(curMethod->clazz, tmp);
   1468             if (strObj == NULL)
   1469                 GOTO_exceptionThrown();
   1470         }
   1471         SET_REGISTER(vdst, (u4) strObj);
   1472     }
   1473     FINISH(3);
   1474 OP_END
   1475 
   1476 /* File: c/OP_CONST_CLASS.cpp */
   1477 HANDLE_OPCODE(OP_CONST_CLASS /*vAA, class@BBBB*/)
   1478     {
   1479         ClassObject* clazz;
   1480 
   1481         vdst = INST_AA(inst);
   1482         ref = FETCH(1);
   1483         ILOGV("|const-class v%d class@0x%04x", vdst, ref);
   1484         clazz = dvmDexGetResolvedClass(methodClassDex, ref);
   1485         if (clazz == NULL) {
   1486             EXPORT_PC();
   1487             clazz = dvmResolveClass(curMethod->clazz, ref, true);
   1488             if (clazz == NULL)
   1489                 GOTO_exceptionThrown();
   1490         }
   1491         SET_REGISTER(vdst, (u4) clazz);
   1492     }
   1493     FINISH(2);
   1494 OP_END
   1495 
   1496 /* File: c/OP_MONITOR_ENTER.cpp */
   1497 HANDLE_OPCODE(OP_MONITOR_ENTER /*vAA*/)
   1498     {
   1499         Object* obj;
   1500 
   1501         vsrc1 = INST_AA(inst);
   1502         ILOGV("|monitor-enter v%d %s(0x%08x)",
   1503             vsrc1, kSpacing+6, GET_REGISTER(vsrc1));
   1504         obj = (Object*)GET_REGISTER(vsrc1);
   1505         if (!checkForNullExportPC(obj, fp, pc))
   1506             GOTO_exceptionThrown();
   1507         ILOGV("+ locking %p %s", obj, obj->clazz->descriptor);
   1508         EXPORT_PC();    /* need for precise GC */
   1509         dvmLockObject(self, obj);
   1510     }
   1511     FINISH(1);
   1512 OP_END
   1513 
   1514 /* File: c/OP_MONITOR_EXIT.cpp */
   1515 HANDLE_OPCODE(OP_MONITOR_EXIT /*vAA*/)
   1516     {
   1517         Object* obj;
   1518 
   1519         EXPORT_PC();
   1520 
   1521         vsrc1 = INST_AA(inst);
   1522         ILOGV("|monitor-exit v%d %s(0x%08x)",
   1523             vsrc1, kSpacing+5, GET_REGISTER(vsrc1));
   1524         obj = (Object*)GET_REGISTER(vsrc1);
   1525         if (!checkForNull(obj)) {
   1526             /*
   1527              * The exception needs to be processed at the *following*
   1528              * instruction, not the current instruction (see the Dalvik
   1529              * spec).  Because we're jumping to an exception handler,
   1530              * we're not actually at risk of skipping an instruction
   1531              * by doing so.
   1532              */
   1533             ADJUST_PC(1);           /* monitor-exit width is 1 */
   1534             GOTO_exceptionThrown();
   1535         }
   1536         ILOGV("+ unlocking %p %s", obj, obj->clazz->descriptor);
   1537         if (!dvmUnlockObject(self, obj)) {
   1538             assert(dvmCheckException(self));
   1539             ADJUST_PC(1);
   1540             GOTO_exceptionThrown();
   1541         }
   1542     }
   1543     FINISH(1);
   1544 OP_END
   1545 
   1546 /* File: c/OP_CHECK_CAST.cpp */
   1547 HANDLE_OPCODE(OP_CHECK_CAST /*vAA, class@BBBB*/)
   1548     {
   1549         ClassObject* clazz;
   1550         Object* obj;
   1551 
   1552         EXPORT_PC();
   1553 
   1554         vsrc1 = INST_AA(inst);
   1555         ref = FETCH(1);         /* class to check against */
   1556         ILOGV("|check-cast v%d,class@0x%04x", vsrc1, ref);
   1557 
   1558         obj = (Object*)GET_REGISTER(vsrc1);
   1559         if (obj != NULL) {
   1560 #if defined(WITH_EXTRA_OBJECT_VALIDATION)
   1561             if (!checkForNull(obj))
   1562                 GOTO_exceptionThrown();
   1563 #endif
   1564             clazz = dvmDexGetResolvedClass(methodClassDex, ref);
   1565             if (clazz == NULL) {
   1566                 clazz = dvmResolveClass(curMethod->clazz, ref, false);
   1567                 if (clazz == NULL)
   1568                     GOTO_exceptionThrown();
   1569             }
   1570             if (!dvmInstanceof(obj->clazz, clazz)) {
   1571                 dvmThrowClassCastException(obj->clazz, clazz);
   1572                 GOTO_exceptionThrown();
   1573             }
   1574         }
   1575     }
   1576     FINISH(2);
   1577 OP_END
   1578 
   1579 /* File: c/OP_INSTANCE_OF.cpp */
   1580 HANDLE_OPCODE(OP_INSTANCE_OF /*vA, vB, class@CCCC*/)
   1581     {
   1582         ClassObject* clazz;
   1583         Object* obj;
   1584 
   1585         vdst = INST_A(inst);
   1586         vsrc1 = INST_B(inst);   /* object to check */
   1587         ref = FETCH(1);         /* class to check against */
   1588         ILOGV("|instance-of v%d,v%d,class@0x%04x", vdst, vsrc1, ref);
   1589 
   1590         obj = (Object*)GET_REGISTER(vsrc1);
   1591         if (obj == NULL) {
   1592             SET_REGISTER(vdst, 0);
   1593         } else {
   1594 #if defined(WITH_EXTRA_OBJECT_VALIDATION)
   1595             if (!checkForNullExportPC(obj, fp, pc))
   1596                 GOTO_exceptionThrown();
   1597 #endif
   1598             clazz = dvmDexGetResolvedClass(methodClassDex, ref);
   1599             if (clazz == NULL) {
   1600                 EXPORT_PC();
   1601                 clazz = dvmResolveClass(curMethod->clazz, ref, true);
   1602                 if (clazz == NULL)
   1603                     GOTO_exceptionThrown();
   1604             }
   1605             SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
   1606         }
   1607     }
   1608     FINISH(2);
   1609 OP_END
   1610 
   1611 /* File: c/OP_ARRAY_LENGTH.cpp */
   1612 HANDLE_OPCODE(OP_ARRAY_LENGTH /*vA, vB*/)
   1613     {
   1614         ArrayObject* arrayObj;
   1615 
   1616         vdst = INST_A(inst);
   1617         vsrc1 = INST_B(inst);
   1618         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
   1619         ILOGV("|array-length v%d,v%d  (%p)", vdst, vsrc1, arrayObj);
   1620         if (!checkForNullExportPC((Object*) arrayObj, fp, pc))
   1621             GOTO_exceptionThrown();
   1622         /* verifier guarantees this is an array reference */
   1623         SET_REGISTER(vdst, arrayObj->length);
   1624     }
   1625     FINISH(1);
   1626 OP_END
   1627 
   1628 /* File: c/OP_NEW_INSTANCE.cpp */
   1629 HANDLE_OPCODE(OP_NEW_INSTANCE /*vAA, class@BBBB*/)
   1630     {
   1631         ClassObject* clazz;
   1632         Object* newObj;
   1633 
   1634         EXPORT_PC();
   1635 
   1636         vdst = INST_AA(inst);
   1637         ref = FETCH(1);
   1638         ILOGV("|new-instance v%d,class@0x%04x", vdst, ref);
   1639         clazz = dvmDexGetResolvedClass(methodClassDex, ref);
   1640         if (clazz == NULL) {
   1641             clazz = dvmResolveClass(curMethod->clazz, ref, false);
   1642             if (clazz == NULL)
   1643                 GOTO_exceptionThrown();
   1644         }
   1645 
   1646         if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
   1647             GOTO_exceptionThrown();
   1648 
   1649 #if defined(WITH_JIT)
   1650         /*
   1651          * The JIT needs dvmDexGetResolvedClass() to return non-null.
   1652          * Since we use the portable interpreter to build the trace, this extra
   1653          * check is not needed for mterp.
   1654          */
   1655         if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
   1656             (!dvmDexGetResolvedClass(methodClassDex, ref))) {
   1657             /* Class initialization is still ongoing - end the trace */
   1658             dvmJitEndTraceSelect(self,pc);
   1659         }
   1660 #endif
   1661 
   1662         /*
   1663          * Verifier now tests for interface/abstract class.
   1664          */
   1665         //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
   1666         //    dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
   1667         //        clazz->descriptor);
   1668         //    GOTO_exceptionThrown();
   1669         //}
   1670         newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
   1671         if (newObj == NULL)
   1672             GOTO_exceptionThrown();
   1673         SET_REGISTER(vdst, (u4) newObj);
   1674     }
   1675     FINISH(2);
   1676 OP_END
   1677 
   1678 /* File: c/OP_NEW_ARRAY.cpp */
   1679 HANDLE_OPCODE(OP_NEW_ARRAY /*vA, vB, class@CCCC*/)
   1680     {
   1681         ClassObject* arrayClass;
   1682         ArrayObject* newArray;
   1683         s4 length;
   1684 
   1685         EXPORT_PC();
   1686 
   1687         vdst = INST_A(inst);
   1688         vsrc1 = INST_B(inst);       /* length reg */
   1689         ref = FETCH(1);
   1690         ILOGV("|new-array v%d,v%d,class@0x%04x  (%d elements)",
   1691             vdst, vsrc1, ref, (s4) GET_REGISTER(vsrc1));
   1692         length = (s4) GET_REGISTER(vsrc1);
   1693         if (length < 0) {
   1694             dvmThrowNegativeArraySizeException(length);
   1695             GOTO_exceptionThrown();
   1696         }
   1697         arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
   1698         if (arrayClass == NULL) {
   1699             arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
   1700             if (arrayClass == NULL)
   1701                 GOTO_exceptionThrown();
   1702         }
   1703         /* verifier guarantees this is an array class */
   1704         assert(dvmIsArrayClass(arrayClass));
   1705         assert(dvmIsClassInitialized(arrayClass));
   1706 
   1707         newArray = dvmAllocArrayByClass(arrayClass, length, ALLOC_DONT_TRACK);
   1708         if (newArray == NULL)
   1709             GOTO_exceptionThrown();
   1710         SET_REGISTER(vdst, (u4) newArray);
   1711     }
   1712     FINISH(2);
   1713 OP_END
   1714 
   1715 /* File: c/OP_FILLED_NEW_ARRAY.cpp */
   1716 HANDLE_OPCODE(OP_FILLED_NEW_ARRAY /*vB, {vD, vE, vF, vG, vA}, class@CCCC*/)
   1717     GOTO_invoke(filledNewArray, false);
   1718 OP_END
   1719 
   1720 /* File: c/OP_FILLED_NEW_ARRAY_RANGE.cpp */
   1721 HANDLE_OPCODE(OP_FILLED_NEW_ARRAY_RANGE /*{vCCCC..v(CCCC+AA-1)}, class@BBBB*/)
   1722     GOTO_invoke(filledNewArray, true);
   1723 OP_END
   1724 
   1725 /* File: c/OP_FILL_ARRAY_DATA.cpp */
   1726 HANDLE_OPCODE(OP_FILL_ARRAY_DATA)   /*vAA, +BBBBBBBB*/
   1727     {
   1728         const u2* arrayData;
   1729         s4 offset;
   1730         ArrayObject* arrayObj;
   1731 
   1732         EXPORT_PC();
   1733         vsrc1 = INST_AA(inst);
   1734         offset = FETCH(1) | (((s4) FETCH(2)) << 16);
   1735         ILOGV("|fill-array-data v%d +0x%04x", vsrc1, offset);
   1736         arrayData = pc + offset;       // offset in 16-bit units
   1737 #ifndef NDEBUG
   1738         if (arrayData < curMethod->insns ||
   1739             arrayData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
   1740         {
   1741             /* should have been caught in verifier */
   1742             dvmThrowInternalError("bad fill array data");
   1743             GOTO_exceptionThrown();
   1744         }
   1745 #endif
   1746         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
   1747         if (!dvmInterpHandleFillArrayData(arrayObj, arrayData)) {
   1748             GOTO_exceptionThrown();
   1749         }
   1750         FINISH(3);
   1751     }
   1752 OP_END
   1753 
   1754 /* File: c/OP_THROW.cpp */
   1755 HANDLE_OPCODE(OP_THROW /*vAA*/)
   1756     {
   1757         Object* obj;
   1758 
   1759         /*
   1760          * We don't create an exception here, but the process of searching
   1761          * for a catch block can do class lookups and throw exceptions.
   1762          * We need to update the saved PC.
   1763          */
   1764         EXPORT_PC();
   1765 
   1766         vsrc1 = INST_AA(inst);
   1767         ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
   1768         obj = (Object*) GET_REGISTER(vsrc1);
   1769         if (!checkForNull(obj)) {
   1770             /* will throw a null pointer exception */
   1771             LOGVV("Bad exception");
   1772         } else {
   1773             /* use the requested exception */
   1774             dvmSetException(self, obj);
   1775         }
   1776         GOTO_exceptionThrown();
   1777     }
   1778 OP_END
   1779 
   1780 /* File: c/OP_GOTO.cpp */
   1781 HANDLE_OPCODE(OP_GOTO /*+AA*/)
   1782     vdst = INST_AA(inst);
   1783     if ((s1)vdst < 0)
   1784         ILOGV("|goto -0x%02x", -((s1)vdst));
   1785     else
   1786         ILOGV("|goto +0x%02x", ((s1)vdst));
   1787     ILOGV("> branch taken");
   1788     if ((s1)vdst < 0)
   1789         PERIODIC_CHECKS((s1)vdst);
   1790     FINISH((s1)vdst);
   1791 OP_END
   1792 
   1793 /* File: c/OP_GOTO_16.cpp */
   1794 HANDLE_OPCODE(OP_GOTO_16 /*+AAAA*/)
   1795     {
   1796         s4 offset = (s2) FETCH(1);          /* sign-extend next code unit */
   1797 
   1798         if (offset < 0)
   1799             ILOGV("|goto/16 -0x%04x", -offset);
   1800         else
   1801             ILOGV("|goto/16 +0x%04x", offset);
   1802         ILOGV("> branch taken");
   1803         if (offset < 0)
   1804             PERIODIC_CHECKS(offset);
   1805         FINISH(offset);
   1806     }
   1807 OP_END
   1808 
   1809 /* File: c/OP_GOTO_32.cpp */
   1810 HANDLE_OPCODE(OP_GOTO_32 /*+AAAAAAAA*/)
   1811     {
   1812         s4 offset = FETCH(1);               /* low-order 16 bits */
   1813         offset |= ((s4) FETCH(2)) << 16;    /* high-order 16 bits */
   1814 
   1815         if (offset < 0)
   1816             ILOGV("|goto/32 -0x%08x", -offset);
   1817         else
   1818             ILOGV("|goto/32 +0x%08x", offset);
   1819         ILOGV("> branch taken");
   1820         if (offset <= 0)    /* allowed to branch to self */
   1821             PERIODIC_CHECKS(offset);
   1822         FINISH(offset);
   1823     }
   1824 OP_END
   1825 
   1826 /* File: c/OP_PACKED_SWITCH.cpp */
   1827 HANDLE_OPCODE(OP_PACKED_SWITCH /*vAA, +BBBB*/)
   1828     {
   1829         const u2* switchData;
   1830         u4 testVal;
   1831         s4 offset;
   1832 
   1833         vsrc1 = INST_AA(inst);
   1834         offset = FETCH(1) | (((s4) FETCH(2)) << 16);
   1835         ILOGV("|packed-switch v%d +0x%04x", vsrc1, vsrc2);
   1836         switchData = pc + offset;       // offset in 16-bit units
   1837 #ifndef NDEBUG
   1838         if (switchData < curMethod->insns ||
   1839             switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
   1840         {
   1841             /* should have been caught in verifier */
   1842             EXPORT_PC();
   1843             dvmThrowInternalError("bad packed switch");
   1844             GOTO_exceptionThrown();
   1845         }
   1846 #endif
   1847         testVal = GET_REGISTER(vsrc1);
   1848 
   1849         offset = dvmInterpHandlePackedSwitch(switchData, testVal);
   1850         ILOGV("> branch taken (0x%04x)", offset);
   1851         if (offset <= 0)  /* uncommon */
   1852             PERIODIC_CHECKS(offset);
   1853         FINISH(offset);
   1854     }
   1855 OP_END
   1856 
   1857 /* File: c/OP_SPARSE_SWITCH.cpp */
   1858 HANDLE_OPCODE(OP_SPARSE_SWITCH /*vAA, +BBBB*/)
   1859     {
   1860         const u2* switchData;
   1861         u4 testVal;
   1862         s4 offset;
   1863 
   1864         vsrc1 = INST_AA(inst);
   1865         offset = FETCH(1) | (((s4) FETCH(2)) << 16);
   1866         ILOGV("|sparse-switch v%d +0x%04x", vsrc1, vsrc2);
   1867         switchData = pc + offset;       // offset in 16-bit units
   1868 #ifndef NDEBUG
   1869         if (switchData < curMethod->insns ||
   1870             switchData >= curMethod->insns + dvmGetMethodInsnsSize(curMethod))
   1871         {
   1872             /* should have been caught in verifier */
   1873             EXPORT_PC();
   1874             dvmThrowInternalError("bad sparse switch");
   1875             GOTO_exceptionThrown();
   1876         }
   1877 #endif
   1878         testVal = GET_REGISTER(vsrc1);
   1879 
   1880         offset = dvmInterpHandleSparseSwitch(switchData, testVal);
   1881         ILOGV("> branch taken (0x%04x)", offset);
   1882         if (offset <= 0)  /* uncommon */
   1883             PERIODIC_CHECKS(offset);
   1884         FINISH(offset);
   1885     }
   1886 OP_END
   1887 
   1888 /* File: c/OP_CMPL_FLOAT.cpp */
   1889 HANDLE_OP_CMPX(OP_CMPL_FLOAT, "l-float", float, _FLOAT, -1)
   1890 OP_END
   1891 
   1892 /* File: c/OP_CMPG_FLOAT.cpp */
   1893 HANDLE_OP_CMPX(OP_CMPG_FLOAT, "g-float", float, _FLOAT, 1)
   1894 OP_END
   1895 
   1896 /* File: c/OP_CMPL_DOUBLE.cpp */
   1897 HANDLE_OP_CMPX(OP_CMPL_DOUBLE, "l-double", double, _DOUBLE, -1)
   1898 OP_END
   1899 
   1900 /* File: c/OP_CMPG_DOUBLE.cpp */
   1901 HANDLE_OP_CMPX(OP_CMPG_DOUBLE, "g-double", double, _DOUBLE, 1)
   1902 OP_END
   1903 
   1904 /* File: c/OP_CMP_LONG.cpp */
   1905 HANDLE_OP_CMPX(OP_CMP_LONG, "-long", s8, _WIDE, 0)
   1906 OP_END
   1907 
   1908 /* File: c/OP_IF_EQ.cpp */
   1909 HANDLE_OP_IF_XX(OP_IF_EQ, "eq", ==)
   1910 OP_END
   1911 
   1912 /* File: c/OP_IF_NE.cpp */
   1913 HANDLE_OP_IF_XX(OP_IF_NE, "ne", !=)
   1914 OP_END
   1915 
   1916 /* File: c/OP_IF_LT.cpp */
   1917 HANDLE_OP_IF_XX(OP_IF_LT, "lt", <)
   1918 OP_END
   1919 
   1920 /* File: c/OP_IF_GE.cpp */
   1921 HANDLE_OP_IF_XX(OP_IF_GE, "ge", >=)
   1922 OP_END
   1923 
   1924 /* File: c/OP_IF_GT.cpp */
   1925 HANDLE_OP_IF_XX(OP_IF_GT, "gt", >)
   1926 OP_END
   1927 
   1928 /* File: c/OP_IF_LE.cpp */
   1929 HANDLE_OP_IF_XX(OP_IF_LE, "le", <=)
   1930 OP_END
   1931 
   1932 /* File: c/OP_IF_EQZ.cpp */
   1933 HANDLE_OP_IF_XXZ(OP_IF_EQZ, "eqz", ==)
   1934 OP_END
   1935 
   1936 /* File: c/OP_IF_NEZ.cpp */
   1937 HANDLE_OP_IF_XXZ(OP_IF_NEZ, "nez", !=)
   1938 OP_END
   1939 
   1940 /* File: c/OP_IF_LTZ.cpp */
   1941 HANDLE_OP_IF_XXZ(OP_IF_LTZ, "ltz", <)
   1942 OP_END
   1943 
   1944 /* File: c/OP_IF_GEZ.cpp */
   1945 HANDLE_OP_IF_XXZ(OP_IF_GEZ, "gez", >=)
   1946 OP_END
   1947 
   1948 /* File: c/OP_IF_GTZ.cpp */
   1949 HANDLE_OP_IF_XXZ(OP_IF_GTZ, "gtz", >)
   1950 OP_END
   1951 
   1952 /* File: c/OP_IF_LEZ.cpp */
   1953 HANDLE_OP_IF_XXZ(OP_IF_LEZ, "lez", <=)
   1954 OP_END
   1955 
   1956 /* File: c/OP_UNUSED_3E.cpp */
   1957 HANDLE_OPCODE(OP_UNUSED_3E)
   1958 OP_END
   1959 
   1960 /* File: c/OP_UNUSED_3F.cpp */
   1961 HANDLE_OPCODE(OP_UNUSED_3F)
   1962 OP_END
   1963 
   1964 /* File: c/OP_UNUSED_40.cpp */
   1965 HANDLE_OPCODE(OP_UNUSED_40)
   1966 OP_END
   1967 
   1968 /* File: c/OP_UNUSED_41.cpp */
   1969 HANDLE_OPCODE(OP_UNUSED_41)
   1970 OP_END
   1971 
   1972 /* File: c/OP_UNUSED_42.cpp */
   1973 HANDLE_OPCODE(OP_UNUSED_42)
   1974 OP_END
   1975 
   1976 /* File: c/OP_UNUSED_43.cpp */
   1977 HANDLE_OPCODE(OP_UNUSED_43)
   1978 OP_END
   1979 
   1980 /* File: c/OP_AGET.cpp */
   1981 HANDLE_OP_AGET(OP_AGET, "", u4, )
   1982 OP_END
   1983 
   1984 /* File: c/OP_AGET_WIDE.cpp */
   1985 HANDLE_OP_AGET(OP_AGET_WIDE, "-wide", s8, _WIDE)
   1986 OP_END
   1987 
   1988 /* File: c/OP_AGET_OBJECT.cpp */
   1989 HANDLE_OP_AGET(OP_AGET_OBJECT, "-object", u4, )
   1990 OP_END
   1991 
   1992 /* File: c/OP_AGET_BOOLEAN.cpp */
   1993 HANDLE_OP_AGET(OP_AGET_BOOLEAN, "-boolean", u1, )
   1994 OP_END
   1995 
   1996 /* File: c/OP_AGET_BYTE.cpp */
   1997 HANDLE_OP_AGET(OP_AGET_BYTE, "-byte", s1, )
   1998 OP_END
   1999 
   2000 /* File: c/OP_AGET_CHAR.cpp */
   2001 HANDLE_OP_AGET(OP_AGET_CHAR, "-char", u2, )
   2002 OP_END
   2003 
   2004 /* File: c/OP_AGET_SHORT.cpp */
   2005 HANDLE_OP_AGET(OP_AGET_SHORT, "-short", s2, )
   2006 OP_END
   2007 
   2008 /* File: c/OP_APUT.cpp */
   2009 HANDLE_OP_APUT(OP_APUT, "", u4, )
   2010 OP_END
   2011 
   2012 /* File: c/OP_APUT_WIDE.cpp */
   2013 HANDLE_OP_APUT(OP_APUT_WIDE, "-wide", s8, _WIDE)
   2014 OP_END
   2015 
   2016 /* File: c/OP_APUT_OBJECT.cpp */
   2017 HANDLE_OPCODE(OP_APUT_OBJECT /*vAA, vBB, vCC*/)
   2018     {
   2019         ArrayObject* arrayObj;
   2020         Object* obj;
   2021         u2 arrayInfo;
   2022         EXPORT_PC();
   2023         vdst = INST_AA(inst);       /* AA: source value */
   2024         arrayInfo = FETCH(1);
   2025         vsrc1 = arrayInfo & 0xff;   /* BB: array ptr */
   2026         vsrc2 = arrayInfo >> 8;     /* CC: index */
   2027         ILOGV("|aput%s v%d,v%d,v%d", "-object", vdst, vsrc1, vsrc2);
   2028         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);
   2029         if (!checkForNull((Object*) arrayObj))
   2030             GOTO_exceptionThrown();
   2031         if (GET_REGISTER(vsrc2) >= arrayObj->length) {
   2032             dvmThrowArrayIndexOutOfBoundsException(
   2033                 arrayObj->length, GET_REGISTER(vsrc2));
   2034             GOTO_exceptionThrown();
   2035         }
   2036         obj = (Object*) GET_REGISTER(vdst);
   2037         if (obj != NULL) {
   2038             if (!checkForNull(obj))
   2039                 GOTO_exceptionThrown();
   2040             if (!dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
   2041                 ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
   2042                     obj->clazz->descriptor, obj,
   2043                     arrayObj->obj.clazz->descriptor, arrayObj);
   2044                 dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
   2045                 GOTO_exceptionThrown();
   2046             }
   2047         }
   2048         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));
   2049         dvmSetObjectArrayElement(arrayObj,
   2050                                  GET_REGISTER(vsrc2),
   2051                                  (Object *)GET_REGISTER(vdst));
   2052     }
   2053     FINISH(2);
   2054 OP_END
   2055 
   2056 /* File: c/OP_APUT_BOOLEAN.cpp */
   2057 HANDLE_OP_APUT(OP_APUT_BOOLEAN, "-boolean", u1, )
   2058 OP_END
   2059 
   2060 /* File: c/OP_APUT_BYTE.cpp */
   2061 HANDLE_OP_APUT(OP_APUT_BYTE, "-byte", s1, )
   2062 OP_END
   2063 
   2064 /* File: c/OP_APUT_CHAR.cpp */
   2065 HANDLE_OP_APUT(OP_APUT_CHAR, "-char", u2, )
   2066 OP_END
   2067 
   2068 /* File: c/OP_APUT_SHORT.cpp */
   2069 HANDLE_OP_APUT(OP_APUT_SHORT, "-short", s2, )
   2070 OP_END
   2071 
   2072 /* File: c/OP_IGET.cpp */
   2073 HANDLE_IGET_X(OP_IGET,                  "", Int, )
   2074 OP_END
   2075 
   2076 /* File: c/OP_IGET_WIDE.cpp */
   2077 HANDLE_IGET_X(OP_IGET_WIDE,             "-wide", Long, _WIDE)
   2078 OP_END
   2079 
   2080 /* File: c/OP_IGET_OBJECT.cpp */
   2081 HANDLE_IGET_X(OP_IGET_OBJECT,           "-object", Object, _AS_OBJECT)
   2082 OP_END
   2083 
   2084 /* File: c/OP_IGET_BOOLEAN.cpp */
   2085 HANDLE_IGET_X(OP_IGET_BOOLEAN,          "", Int, )
   2086 OP_END
   2087 
   2088 /* File: c/OP_IGET_BYTE.cpp */
   2089 HANDLE_IGET_X(OP_IGET_BYTE,             "", Int, )
   2090 OP_END
   2091 
   2092 /* File: c/OP_IGET_CHAR.cpp */
   2093 HANDLE_IGET_X(OP_IGET_CHAR,             "", Int, )
   2094 OP_END
   2095 
   2096 /* File: c/OP_IGET_SHORT.cpp */
   2097 HANDLE_IGET_X(OP_IGET_SHORT,            "", Int, )
   2098 OP_END
   2099 
   2100 /* File: c/OP_IPUT.cpp */
   2101 HANDLE_IPUT_X(OP_IPUT,                  "", Int, )
   2102 OP_END
   2103 
   2104 /* File: c/OP_IPUT_WIDE.cpp */
   2105 HANDLE_IPUT_X(OP_IPUT_WIDE,             "-wide", Long, _WIDE)
   2106 OP_END
   2107 
   2108 /* File: c/OP_IPUT_OBJECT.cpp */
   2109 /*
   2110  * The VM spec says we should verify that the reference being stored into
   2111  * the field is assignment compatible.  In practice, many popular VMs don't
   2112  * do this because it slows down a very common operation.  It's not so bad
   2113  * for us, since "dexopt" quickens it whenever possible, but it's still an
   2114  * issue.
   2115  *
   2116  * To make this spec-complaint, we'd need to add a ClassObject pointer to
   2117  * the Field struct, resolve the field's type descriptor at link or class
   2118  * init time, and then verify the type here.
   2119  */
   2120 HANDLE_IPUT_X(OP_IPUT_OBJECT,           "-object", Object, _AS_OBJECT)
   2121 OP_END
   2122 
   2123 /* File: c/OP_IPUT_BOOLEAN.cpp */
   2124 HANDLE_IPUT_X(OP_IPUT_BOOLEAN,          "", Int, )
   2125 OP_END
   2126 
   2127 /* File: c/OP_IPUT_BYTE.cpp */
   2128 HANDLE_IPUT_X(OP_IPUT_BYTE,             "", Int, )
   2129 OP_END
   2130 
   2131 /* File: c/OP_IPUT_CHAR.cpp */
   2132 HANDLE_IPUT_X(OP_IPUT_CHAR,             "", Int, )
   2133 OP_END
   2134 
   2135 /* File: c/OP_IPUT_SHORT.cpp */
   2136 HANDLE_IPUT_X(OP_IPUT_SHORT,            "", Int, )
   2137 OP_END
   2138 
   2139 /* File: c/OP_SGET.cpp */
   2140 HANDLE_SGET_X(OP_SGET,                  "", Int, )
   2141 OP_END
   2142 
   2143 /* File: c/OP_SGET_WIDE.cpp */
   2144 HANDLE_SGET_X(OP_SGET_WIDE,             "-wide", Long, _WIDE)
   2145 OP_END
   2146 
   2147 /* File: c/OP_SGET_OBJECT.cpp */
   2148 HANDLE_SGET_X(OP_SGET_OBJECT,           "-object", Object, _AS_OBJECT)
   2149 OP_END
   2150 
   2151 /* File: c/OP_SGET_BOOLEAN.cpp */
   2152 HANDLE_SGET_X(OP_SGET_BOOLEAN,          "", Int, )
   2153 OP_END
   2154 
   2155 /* File: c/OP_SGET_BYTE.cpp */
   2156 HANDLE_SGET_X(OP_SGET_BYTE,             "", Int, )
   2157 OP_END
   2158 
   2159 /* File: c/OP_SGET_CHAR.cpp */
   2160 HANDLE_SGET_X(OP_SGET_CHAR,             "", Int, )
   2161 OP_END
   2162 
   2163 /* File: c/OP_SGET_SHORT.cpp */
   2164 HANDLE_SGET_X(OP_SGET_SHORT,            "", Int, )
   2165 OP_END
   2166 
   2167 /* File: c/OP_SPUT.cpp */
   2168 HANDLE_SPUT_X(OP_SPUT,                  "", Int, )
   2169 OP_END
   2170 
   2171 /* File: c/OP_SPUT_WIDE.cpp */
   2172 HANDLE_SPUT_X(OP_SPUT_WIDE,             "-wide", Long, _WIDE)
   2173 OP_END
   2174 
   2175 /* File: c/OP_SPUT_OBJECT.cpp */
   2176 HANDLE_SPUT_X(OP_SPUT_OBJECT,           "-object", Object, _AS_OBJECT)
   2177 OP_END
   2178 
   2179 /* File: c/OP_SPUT_BOOLEAN.cpp */
   2180 HANDLE_SPUT_X(OP_SPUT_BOOLEAN,          "", Int, )
   2181 OP_END
   2182 
   2183 /* File: c/OP_SPUT_BYTE.cpp */
   2184 HANDLE_SPUT_X(OP_SPUT_BYTE,             "", Int, )
   2185 OP_END
   2186 
   2187 /* File: c/OP_SPUT_CHAR.cpp */
   2188 HANDLE_SPUT_X(OP_SPUT_CHAR,             "", Int, )
   2189 OP_END
   2190 
   2191 /* File: c/OP_SPUT_SHORT.cpp */
   2192 HANDLE_SPUT_X(OP_SPUT_SHORT,            "", Int, )
   2193 OP_END
   2194 
   2195 /* File: c/OP_INVOKE_VIRTUAL.cpp */
   2196 HANDLE_OPCODE(OP_INVOKE_VIRTUAL /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2197     GOTO_invoke(invokeVirtual, false);
   2198 OP_END
   2199 
   2200 /* File: c/OP_INVOKE_SUPER.cpp */
   2201 HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2202     GOTO_invoke(invokeSuper, false);
   2203 OP_END
   2204 
   2205 /* File: c/OP_INVOKE_DIRECT.cpp */
   2206 HANDLE_OPCODE(OP_INVOKE_DIRECT /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2207     GOTO_invoke(invokeDirect, false);
   2208 OP_END
   2209 
   2210 /* File: c/OP_INVOKE_STATIC.cpp */
   2211 HANDLE_OPCODE(OP_INVOKE_STATIC /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2212     GOTO_invoke(invokeStatic, false);
   2213 OP_END
   2214 
   2215 /* File: c/OP_INVOKE_INTERFACE.cpp */
   2216 HANDLE_OPCODE(OP_INVOKE_INTERFACE /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2217     GOTO_invoke(invokeInterface, false);
   2218 OP_END
   2219 
   2220 /* File: c/OP_UNUSED_73.cpp */
   2221 HANDLE_OPCODE(OP_UNUSED_73)
   2222 OP_END
   2223 
   2224 /* File: c/OP_INVOKE_VIRTUAL_RANGE.cpp */
   2225 HANDLE_OPCODE(OP_INVOKE_VIRTUAL_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2226     GOTO_invoke(invokeVirtual, true);
   2227 OP_END
   2228 
   2229 /* File: c/OP_INVOKE_SUPER_RANGE.cpp */
   2230 HANDLE_OPCODE(OP_INVOKE_SUPER_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2231     GOTO_invoke(invokeSuper, true);
   2232 OP_END
   2233 
   2234 /* File: c/OP_INVOKE_DIRECT_RANGE.cpp */
   2235 HANDLE_OPCODE(OP_INVOKE_DIRECT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2236     GOTO_invoke(invokeDirect, true);
   2237 OP_END
   2238 
   2239 /* File: c/OP_INVOKE_STATIC_RANGE.cpp */
   2240 HANDLE_OPCODE(OP_INVOKE_STATIC_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2241     GOTO_invoke(invokeStatic, true);
   2242 OP_END
   2243 
   2244 /* File: c/OP_INVOKE_INTERFACE_RANGE.cpp */
   2245 HANDLE_OPCODE(OP_INVOKE_INTERFACE_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2246     GOTO_invoke(invokeInterface, true);
   2247 OP_END
   2248 
   2249 /* File: c/OP_UNUSED_79.cpp */
   2250 HANDLE_OPCODE(OP_UNUSED_79)
   2251 OP_END
   2252 
   2253 /* File: c/OP_UNUSED_7A.cpp */
   2254 HANDLE_OPCODE(OP_UNUSED_7A)
   2255 OP_END
   2256 
   2257 /* File: c/OP_NEG_INT.cpp */
   2258 HANDLE_UNOP(OP_NEG_INT, "neg-int", -, , )
   2259 OP_END
   2260 
   2261 /* File: c/OP_NOT_INT.cpp */
   2262 HANDLE_UNOP(OP_NOT_INT, "not-int", , ^ 0xffffffff, )
   2263 OP_END
   2264 
   2265 /* File: c/OP_NEG_LONG.cpp */
   2266 HANDLE_UNOP(OP_NEG_LONG, "neg-long", -, , _WIDE)
   2267 OP_END
   2268 
   2269 /* File: c/OP_NOT_LONG.cpp */
   2270 HANDLE_UNOP(OP_NOT_LONG, "not-long", , ^ 0xffffffffffffffffULL, _WIDE)
   2271 OP_END
   2272 
   2273 /* File: c/OP_NEG_FLOAT.cpp */
   2274 HANDLE_UNOP(OP_NEG_FLOAT, "neg-float", -, , _FLOAT)
   2275 OP_END
   2276 
   2277 /* File: c/OP_NEG_DOUBLE.cpp */
   2278 HANDLE_UNOP(OP_NEG_DOUBLE, "neg-double", -, , _DOUBLE)
   2279 OP_END
   2280 
   2281 /* File: c/OP_INT_TO_LONG.cpp */
   2282 HANDLE_NUMCONV(OP_INT_TO_LONG,          "int-to-long", _INT, _WIDE)
   2283 OP_END
   2284 
   2285 /* File: c/OP_INT_TO_FLOAT.cpp */
   2286 HANDLE_NUMCONV(OP_INT_TO_FLOAT,         "int-to-float", _INT, _FLOAT)
   2287 OP_END
   2288 
   2289 /* File: c/OP_INT_TO_DOUBLE.cpp */
   2290 HANDLE_NUMCONV(OP_INT_TO_DOUBLE,        "int-to-double", _INT, _DOUBLE)
   2291 OP_END
   2292 
   2293 /* File: c/OP_LONG_TO_INT.cpp */
   2294 HANDLE_NUMCONV(OP_LONG_TO_INT,          "long-to-int", _WIDE, _INT)
   2295 OP_END
   2296 
   2297 /* File: c/OP_LONG_TO_FLOAT.cpp */
   2298 HANDLE_NUMCONV(OP_LONG_TO_FLOAT,        "long-to-float", _WIDE, _FLOAT)
   2299 OP_END
   2300 
   2301 /* File: c/OP_LONG_TO_DOUBLE.cpp */
   2302 HANDLE_NUMCONV(OP_LONG_TO_DOUBLE,       "long-to-double", _WIDE, _DOUBLE)
   2303 OP_END
   2304 
   2305 /* File: c/OP_FLOAT_TO_INT.cpp */
   2306 HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_INT,    "float-to-int",
   2307     float, _FLOAT, s4, _INT)
   2308 OP_END
   2309 
   2310 /* File: c/OP_FLOAT_TO_LONG.cpp */
   2311 HANDLE_FLOAT_TO_INT(OP_FLOAT_TO_LONG,   "float-to-long",
   2312     float, _FLOAT, s8, _WIDE)
   2313 OP_END
   2314 
   2315 /* File: c/OP_FLOAT_TO_DOUBLE.cpp */
   2316 HANDLE_NUMCONV(OP_FLOAT_TO_DOUBLE,      "float-to-double", _FLOAT, _DOUBLE)
   2317 OP_END
   2318 
   2319 /* File: c/OP_DOUBLE_TO_INT.cpp */
   2320 HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_INT,   "double-to-int",
   2321     double, _DOUBLE, s4, _INT)
   2322 OP_END
   2323 
   2324 /* File: c/OP_DOUBLE_TO_LONG.cpp */
   2325 HANDLE_FLOAT_TO_INT(OP_DOUBLE_TO_LONG,  "double-to-long",
   2326     double, _DOUBLE, s8, _WIDE)
   2327 OP_END
   2328 
   2329 /* File: c/OP_DOUBLE_TO_FLOAT.cpp */
   2330 HANDLE_NUMCONV(OP_DOUBLE_TO_FLOAT,      "double-to-float", _DOUBLE, _FLOAT)
   2331 OP_END
   2332 
   2333 /* File: c/OP_INT_TO_BYTE.cpp */
   2334 HANDLE_INT_TO_SMALL(OP_INT_TO_BYTE,     "byte", s1)
   2335 OP_END
   2336 
   2337 /* File: c/OP_INT_TO_CHAR.cpp */
   2338 HANDLE_INT_TO_SMALL(OP_INT_TO_CHAR,     "char", u2)
   2339 OP_END
   2340 
   2341 /* File: c/OP_INT_TO_SHORT.cpp */
   2342 HANDLE_INT_TO_SMALL(OP_INT_TO_SHORT,    "short", s2)    /* want sign bit */
   2343 OP_END
   2344 
   2345 /* File: c/OP_ADD_INT.cpp */
   2346 HANDLE_OP_X_INT(OP_ADD_INT, "add", +, 0)
   2347 OP_END
   2348 
   2349 /* File: c/OP_SUB_INT.cpp */
   2350 HANDLE_OP_X_INT(OP_SUB_INT, "sub", -, 0)
   2351 OP_END
   2352 
   2353 /* File: c/OP_MUL_INT.cpp */
   2354 HANDLE_OP_X_INT(OP_MUL_INT, "mul", *, 0)
   2355 OP_END
   2356 
   2357 /* File: c/OP_DIV_INT.cpp */
   2358 HANDLE_OP_X_INT(OP_DIV_INT, "div", /, 1)
   2359 OP_END
   2360 
   2361 /* File: c/OP_REM_INT.cpp */
   2362 HANDLE_OP_X_INT(OP_REM_INT, "rem", %, 2)
   2363 OP_END
   2364 
   2365 /* File: c/OP_AND_INT.cpp */
   2366 HANDLE_OP_X_INT(OP_AND_INT, "and", &, 0)
   2367 OP_END
   2368 
   2369 /* File: c/OP_OR_INT.cpp */
   2370 HANDLE_OP_X_INT(OP_OR_INT,  "or",  |, 0)
   2371 OP_END
   2372 
   2373 /* File: c/OP_XOR_INT.cpp */
   2374 HANDLE_OP_X_INT(OP_XOR_INT, "xor", ^, 0)
   2375 OP_END
   2376 
   2377 /* File: c/OP_SHL_INT.cpp */
   2378 HANDLE_OP_SHX_INT(OP_SHL_INT, "shl", (s4), <<)
   2379 OP_END
   2380 
   2381 /* File: c/OP_SHR_INT.cpp */
   2382 HANDLE_OP_SHX_INT(OP_SHR_INT, "shr", (s4), >>)
   2383 OP_END
   2384 
   2385 /* File: c/OP_USHR_INT.cpp */
   2386 HANDLE_OP_SHX_INT(OP_USHR_INT, "ushr", (u4), >>)
   2387 OP_END
   2388 
   2389 /* File: c/OP_ADD_LONG.cpp */
   2390 HANDLE_OP_X_LONG(OP_ADD_LONG, "add", +, 0)
   2391 OP_END
   2392 
   2393 /* File: c/OP_SUB_LONG.cpp */
   2394 HANDLE_OP_X_LONG(OP_SUB_LONG, "sub", -, 0)
   2395 OP_END
   2396 
   2397 /* File: c/OP_MUL_LONG.cpp */
   2398 HANDLE_OP_X_LONG(OP_MUL_LONG, "mul", *, 0)
   2399 OP_END
   2400 
   2401 /* File: c/OP_DIV_LONG.cpp */
   2402 HANDLE_OP_X_LONG(OP_DIV_LONG, "div", /, 1)
   2403 OP_END
   2404 
   2405 /* File: c/OP_REM_LONG.cpp */
   2406 HANDLE_OP_X_LONG(OP_REM_LONG, "rem", %, 2)
   2407 OP_END
   2408 
   2409 /* File: c/OP_AND_LONG.cpp */
   2410 HANDLE_OP_X_LONG(OP_AND_LONG, "and", &, 0)
   2411 OP_END
   2412 
   2413 /* File: c/OP_OR_LONG.cpp */
   2414 HANDLE_OP_X_LONG(OP_OR_LONG,  "or", |, 0)
   2415 OP_END
   2416 
   2417 /* File: c/OP_XOR_LONG.cpp */
   2418 HANDLE_OP_X_LONG(OP_XOR_LONG, "xor", ^, 0)
   2419 OP_END
   2420 
   2421 /* File: c/OP_SHL_LONG.cpp */
   2422 HANDLE_OP_SHX_LONG(OP_SHL_LONG, "shl", (s8), <<)
   2423 OP_END
   2424 
   2425 /* File: c/OP_SHR_LONG.cpp */
   2426 HANDLE_OP_SHX_LONG(OP_SHR_LONG, "shr", (s8), >>)
   2427 OP_END
   2428 
   2429 /* File: c/OP_USHR_LONG.cpp */
   2430 HANDLE_OP_SHX_LONG(OP_USHR_LONG, "ushr", (u8), >>)
   2431 OP_END
   2432 
   2433 /* File: c/OP_ADD_FLOAT.cpp */
   2434 HANDLE_OP_X_FLOAT(OP_ADD_FLOAT, "add", +)
   2435 OP_END
   2436 
   2437 /* File: c/OP_SUB_FLOAT.cpp */
   2438 HANDLE_OP_X_FLOAT(OP_SUB_FLOAT, "sub", -)
   2439 OP_END
   2440 
   2441 /* File: c/OP_MUL_FLOAT.cpp */
   2442 HANDLE_OP_X_FLOAT(OP_MUL_FLOAT, "mul", *)
   2443 OP_END
   2444 
   2445 /* File: c/OP_DIV_FLOAT.cpp */
   2446 HANDLE_OP_X_FLOAT(OP_DIV_FLOAT, "div", /)
   2447 OP_END
   2448 
   2449 /* File: c/OP_REM_FLOAT.cpp */
   2450 HANDLE_OPCODE(OP_REM_FLOAT /*vAA, vBB, vCC*/)
   2451     {
   2452         u2 srcRegs;
   2453         vdst = INST_AA(inst);
   2454         srcRegs = FETCH(1);
   2455         vsrc1 = srcRegs & 0xff;
   2456         vsrc2 = srcRegs >> 8;
   2457         ILOGV("|%s-float v%d,v%d,v%d", "mod", vdst, vsrc1, vsrc2);
   2458         SET_REGISTER_FLOAT(vdst,
   2459             fmodf(GET_REGISTER_FLOAT(vsrc1), GET_REGISTER_FLOAT(vsrc2)));
   2460     }
   2461     FINISH(2);
   2462 OP_END
   2463 
   2464 /* File: c/OP_ADD_DOUBLE.cpp */
   2465 HANDLE_OP_X_DOUBLE(OP_ADD_DOUBLE, "add", +)
   2466 OP_END
   2467 
   2468 /* File: c/OP_SUB_DOUBLE.cpp */
   2469 HANDLE_OP_X_DOUBLE(OP_SUB_DOUBLE, "sub", -)
   2470 OP_END
   2471 
   2472 /* File: c/OP_MUL_DOUBLE.cpp */
   2473 HANDLE_OP_X_DOUBLE(OP_MUL_DOUBLE, "mul", *)
   2474 OP_END
   2475 
   2476 /* File: c/OP_DIV_DOUBLE.cpp */
   2477 HANDLE_OP_X_DOUBLE(OP_DIV_DOUBLE, "div", /)
   2478 OP_END
   2479 
   2480 /* File: c/OP_REM_DOUBLE.cpp */
   2481 HANDLE_OPCODE(OP_REM_DOUBLE /*vAA, vBB, vCC*/)
   2482     {
   2483         u2 srcRegs;
   2484         vdst = INST_AA(inst);
   2485         srcRegs = FETCH(1);
   2486         vsrc1 = srcRegs & 0xff;
   2487         vsrc2 = srcRegs >> 8;
   2488         ILOGV("|%s-double v%d,v%d,v%d", "mod", vdst, vsrc1, vsrc2);
   2489         SET_REGISTER_DOUBLE(vdst,
   2490             fmod(GET_REGISTER_DOUBLE(vsrc1), GET_REGISTER_DOUBLE(vsrc2)));
   2491     }
   2492     FINISH(2);
   2493 OP_END
   2494 
   2495 /* File: c/OP_ADD_INT_2ADDR.cpp */
   2496 HANDLE_OP_X_INT_2ADDR(OP_ADD_INT_2ADDR, "add", +, 0)
   2497 OP_END
   2498 
   2499 /* File: c/OP_SUB_INT_2ADDR.cpp */
   2500 HANDLE_OP_X_INT_2ADDR(OP_SUB_INT_2ADDR, "sub", -, 0)
   2501 OP_END
   2502 
   2503 /* File: c/OP_MUL_INT_2ADDR.cpp */
   2504 HANDLE_OP_X_INT_2ADDR(OP_MUL_INT_2ADDR, "mul", *, 0)
   2505 OP_END
   2506 
   2507 /* File: c/OP_DIV_INT_2ADDR.cpp */
   2508 HANDLE_OP_X_INT_2ADDR(OP_DIV_INT_2ADDR, "div", /, 1)
   2509 OP_END
   2510 
   2511 /* File: c/OP_REM_INT_2ADDR.cpp */
   2512 HANDLE_OP_X_INT_2ADDR(OP_REM_INT_2ADDR, "rem", %, 2)
   2513 OP_END
   2514 
   2515 /* File: c/OP_AND_INT_2ADDR.cpp */
   2516 HANDLE_OP_X_INT_2ADDR(OP_AND_INT_2ADDR, "and", &, 0)
   2517 OP_END
   2518 
   2519 /* File: c/OP_OR_INT_2ADDR.cpp */
   2520 HANDLE_OP_X_INT_2ADDR(OP_OR_INT_2ADDR,  "or", |, 0)
   2521 OP_END
   2522 
   2523 /* File: c/OP_XOR_INT_2ADDR.cpp */
   2524 HANDLE_OP_X_INT_2ADDR(OP_XOR_INT_2ADDR, "xor", ^, 0)
   2525 OP_END
   2526 
   2527 /* File: c/OP_SHL_INT_2ADDR.cpp */
   2528 HANDLE_OP_SHX_INT_2ADDR(OP_SHL_INT_2ADDR, "shl", (s4), <<)
   2529 OP_END
   2530 
   2531 /* File: c/OP_SHR_INT_2ADDR.cpp */
   2532 HANDLE_OP_SHX_INT_2ADDR(OP_SHR_INT_2ADDR, "shr", (s4), >>)
   2533 OP_END
   2534 
   2535 /* File: c/OP_USHR_INT_2ADDR.cpp */
   2536 HANDLE_OP_SHX_INT_2ADDR(OP_USHR_INT_2ADDR, "ushr", (u4), >>)
   2537 OP_END
   2538 
   2539 /* File: c/OP_ADD_LONG_2ADDR.cpp */
   2540 HANDLE_OP_X_LONG_2ADDR(OP_ADD_LONG_2ADDR, "add", +, 0)
   2541 OP_END
   2542 
   2543 /* File: c/OP_SUB_LONG_2ADDR.cpp */
   2544 HANDLE_OP_X_LONG_2ADDR(OP_SUB_LONG_2ADDR, "sub", -, 0)
   2545 OP_END
   2546 
   2547 /* File: c/OP_MUL_LONG_2ADDR.cpp */
   2548 HANDLE_OP_X_LONG_2ADDR(OP_MUL_LONG_2ADDR, "mul", *, 0)
   2549 OP_END
   2550 
   2551 /* File: c/OP_DIV_LONG_2ADDR.cpp */
   2552 HANDLE_OP_X_LONG_2ADDR(OP_DIV_LONG_2ADDR, "div", /, 1)
   2553 OP_END
   2554 
   2555 /* File: c/OP_REM_LONG_2ADDR.cpp */
   2556 HANDLE_OP_X_LONG_2ADDR(OP_REM_LONG_2ADDR, "rem", %, 2)
   2557 OP_END
   2558 
   2559 /* File: c/OP_AND_LONG_2ADDR.cpp */
   2560 HANDLE_OP_X_LONG_2ADDR(OP_AND_LONG_2ADDR, "and", &, 0)
   2561 OP_END
   2562 
   2563 /* File: c/OP_OR_LONG_2ADDR.cpp */
   2564 HANDLE_OP_X_LONG_2ADDR(OP_OR_LONG_2ADDR,  "or", |, 0)
   2565 OP_END
   2566 
   2567 /* File: c/OP_XOR_LONG_2ADDR.cpp */
   2568 HANDLE_OP_X_LONG_2ADDR(OP_XOR_LONG_2ADDR, "xor", ^, 0)
   2569 OP_END
   2570 
   2571 /* File: c/OP_SHL_LONG_2ADDR.cpp */
   2572 HANDLE_OP_SHX_LONG_2ADDR(OP_SHL_LONG_2ADDR, "shl", (s8), <<)
   2573 OP_END
   2574 
   2575 /* File: c/OP_SHR_LONG_2ADDR.cpp */
   2576 HANDLE_OP_SHX_LONG_2ADDR(OP_SHR_LONG_2ADDR, "shr", (s8), >>)
   2577 OP_END
   2578 
   2579 /* File: c/OP_USHR_LONG_2ADDR.cpp */
   2580 HANDLE_OP_SHX_LONG_2ADDR(OP_USHR_LONG_2ADDR, "ushr", (u8), >>)
   2581 OP_END
   2582 
   2583 /* File: c/OP_ADD_FLOAT_2ADDR.cpp */
   2584 HANDLE_OP_X_FLOAT_2ADDR(OP_ADD_FLOAT_2ADDR, "add", +)
   2585 OP_END
   2586 
   2587 /* File: c/OP_SUB_FLOAT_2ADDR.cpp */
   2588 HANDLE_OP_X_FLOAT_2ADDR(OP_SUB_FLOAT_2ADDR, "sub", -)
   2589 OP_END
   2590 
   2591 /* File: c/OP_MUL_FLOAT_2ADDR.cpp */
   2592 HANDLE_OP_X_FLOAT_2ADDR(OP_MUL_FLOAT_2ADDR, "mul", *)
   2593 OP_END
   2594 
   2595 /* File: c/OP_DIV_FLOAT_2ADDR.cpp */
   2596 HANDLE_OP_X_FLOAT_2ADDR(OP_DIV_FLOAT_2ADDR, "div", /)
   2597 OP_END
   2598 
   2599 /* File: c/OP_REM_FLOAT_2ADDR.cpp */
   2600 HANDLE_OPCODE(OP_REM_FLOAT_2ADDR /*vA, vB*/)
   2601     vdst = INST_A(inst);
   2602     vsrc1 = INST_B(inst);
   2603     ILOGV("|%s-float-2addr v%d,v%d", "mod", vdst, vsrc1);
   2604     SET_REGISTER_FLOAT(vdst,
   2605         fmodf(GET_REGISTER_FLOAT(vdst), GET_REGISTER_FLOAT(vsrc1)));
   2606     FINISH(1);
   2607 OP_END
   2608 
   2609 /* File: c/OP_ADD_DOUBLE_2ADDR.cpp */
   2610 HANDLE_OP_X_DOUBLE_2ADDR(OP_ADD_DOUBLE_2ADDR, "add", +)
   2611 OP_END
   2612 
   2613 /* File: c/OP_SUB_DOUBLE_2ADDR.cpp */
   2614 HANDLE_OP_X_DOUBLE_2ADDR(OP_SUB_DOUBLE_2ADDR, "sub", -)
   2615 OP_END
   2616 
   2617 /* File: c/OP_MUL_DOUBLE_2ADDR.cpp */
   2618 HANDLE_OP_X_DOUBLE_2ADDR(OP_MUL_DOUBLE_2ADDR, "mul", *)
   2619 OP_END
   2620 
   2621 /* File: c/OP_DIV_DOUBLE_2ADDR.cpp */
   2622 HANDLE_OP_X_DOUBLE_2ADDR(OP_DIV_DOUBLE_2ADDR, "div", /)
   2623 OP_END
   2624 
   2625 /* File: c/OP_REM_DOUBLE_2ADDR.cpp */
   2626 HANDLE_OPCODE(OP_REM_DOUBLE_2ADDR /*vA, vB*/)
   2627     vdst = INST_A(inst);
   2628     vsrc1 = INST_B(inst);
   2629     ILOGV("|%s-double-2addr v%d,v%d", "mod", vdst, vsrc1);
   2630     SET_REGISTER_DOUBLE(vdst,
   2631         fmod(GET_REGISTER_DOUBLE(vdst), GET_REGISTER_DOUBLE(vsrc1)));
   2632     FINISH(1);
   2633 OP_END
   2634 
   2635 /* File: c/OP_ADD_INT_LIT16.cpp */
   2636 HANDLE_OP_X_INT_LIT16(OP_ADD_INT_LIT16, "add", +, 0)
   2637 OP_END
   2638 
   2639 /* File: c/OP_RSUB_INT.cpp */
   2640 HANDLE_OPCODE(OP_RSUB_INT /*vA, vB, #+CCCC*/)
   2641     {
   2642         vdst = INST_A(inst);
   2643         vsrc1 = INST_B(inst);
   2644         vsrc2 = FETCH(1);
   2645         ILOGV("|rsub-int v%d,v%d,#+0x%04x", vdst, vsrc1, vsrc2);
   2646         SET_REGISTER(vdst, (s2) vsrc2 - (s4) GET_REGISTER(vsrc1));
   2647     }
   2648     FINISH(2);
   2649 OP_END
   2650 
   2651 /* File: c/OP_MUL_INT_LIT16.cpp */
   2652 HANDLE_OP_X_INT_LIT16(OP_MUL_INT_LIT16, "mul", *, 0)
   2653 OP_END
   2654 
   2655 /* File: c/OP_DIV_INT_LIT16.cpp */
   2656 HANDLE_OP_X_INT_LIT16(OP_DIV_INT_LIT16, "div", /, 1)
   2657 OP_END
   2658 
   2659 /* File: c/OP_REM_INT_LIT16.cpp */
   2660 HANDLE_OP_X_INT_LIT16(OP_REM_INT_LIT16, "rem", %, 2)
   2661 OP_END
   2662 
   2663 /* File: c/OP_AND_INT_LIT16.cpp */
   2664 HANDLE_OP_X_INT_LIT16(OP_AND_INT_LIT16, "and", &, 0)
   2665 OP_END
   2666 
   2667 /* File: c/OP_OR_INT_LIT16.cpp */
   2668 HANDLE_OP_X_INT_LIT16(OP_OR_INT_LIT16,  "or",  |, 0)
   2669 OP_END
   2670 
   2671 /* File: c/OP_XOR_INT_LIT16.cpp */
   2672 HANDLE_OP_X_INT_LIT16(OP_XOR_INT_LIT16, "xor", ^, 0)
   2673 OP_END
   2674 
   2675 /* File: c/OP_ADD_INT_LIT8.cpp */
   2676 HANDLE_OP_X_INT_LIT8(OP_ADD_INT_LIT8,   "add", +, 0)
   2677 OP_END
   2678 
   2679 /* File: c/OP_RSUB_INT_LIT8.cpp */
   2680 HANDLE_OPCODE(OP_RSUB_INT_LIT8 /*vAA, vBB, #+CC*/)
   2681     {
   2682         u2 litInfo;
   2683         vdst = INST_AA(inst);
   2684         litInfo = FETCH(1);
   2685         vsrc1 = litInfo & 0xff;
   2686         vsrc2 = litInfo >> 8;
   2687         ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", "rsub", vdst, vsrc1, vsrc2);
   2688         SET_REGISTER(vdst, (s1) vsrc2 - (s4) GET_REGISTER(vsrc1));
   2689     }
   2690     FINISH(2);
   2691 OP_END
   2692 
   2693 /* File: c/OP_MUL_INT_LIT8.cpp */
   2694 HANDLE_OP_X_INT_LIT8(OP_MUL_INT_LIT8,   "mul", *, 0)
   2695 OP_END
   2696 
   2697 /* File: c/OP_DIV_INT_LIT8.cpp */
   2698 HANDLE_OP_X_INT_LIT8(OP_DIV_INT_LIT8,   "div", /, 1)
   2699 OP_END
   2700 
   2701 /* File: c/OP_REM_INT_LIT8.cpp */
   2702 HANDLE_OP_X_INT_LIT8(OP_REM_INT_LIT8,   "rem", %, 2)
   2703 OP_END
   2704 
   2705 /* File: c/OP_AND_INT_LIT8.cpp */
   2706 HANDLE_OP_X_INT_LIT8(OP_AND_INT_LIT8,   "and", &, 0)
   2707 OP_END
   2708 
   2709 /* File: c/OP_OR_INT_LIT8.cpp */
   2710 HANDLE_OP_X_INT_LIT8(OP_OR_INT_LIT8,    "or",  |, 0)
   2711 OP_END
   2712 
   2713 /* File: c/OP_XOR_INT_LIT8.cpp */
   2714 HANDLE_OP_X_INT_LIT8(OP_XOR_INT_LIT8,   "xor", ^, 0)
   2715 OP_END
   2716 
   2717 /* File: c/OP_SHL_INT_LIT8.cpp */
   2718 HANDLE_OP_SHX_INT_LIT8(OP_SHL_INT_LIT8,   "shl", (s4), <<)
   2719 OP_END
   2720 
   2721 /* File: c/OP_SHR_INT_LIT8.cpp */
   2722 HANDLE_OP_SHX_INT_LIT8(OP_SHR_INT_LIT8,   "shr", (s4), >>)
   2723 OP_END
   2724 
   2725 /* File: c/OP_USHR_INT_LIT8.cpp */
   2726 HANDLE_OP_SHX_INT_LIT8(OP_USHR_INT_LIT8,  "ushr", (u4), >>)
   2727 OP_END
   2728 
   2729 /* File: c/OP_IGET_VOLATILE.cpp */
   2730 HANDLE_IGET_X(OP_IGET_VOLATILE,         "-volatile", IntVolatile, )
   2731 OP_END
   2732 
   2733 /* File: c/OP_IPUT_VOLATILE.cpp */
   2734 HANDLE_IPUT_X(OP_IPUT_VOLATILE,         "-volatile", IntVolatile, )
   2735 OP_END
   2736 
   2737 /* File: c/OP_SGET_VOLATILE.cpp */
   2738 HANDLE_SGET_X(OP_SGET_VOLATILE,         "-volatile", IntVolatile, )
   2739 OP_END
   2740 
   2741 /* File: c/OP_SPUT_VOLATILE.cpp */
   2742 HANDLE_SPUT_X(OP_SPUT_VOLATILE,         "-volatile", IntVolatile, )
   2743 OP_END
   2744 
   2745 /* File: c/OP_IGET_OBJECT_VOLATILE.cpp */
   2746 HANDLE_IGET_X(OP_IGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
   2747 OP_END
   2748 
   2749 /* File: c/OP_IGET_WIDE_VOLATILE.cpp */
   2750 HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
   2751 OP_END
   2752 
   2753 /* File: c/OP_IPUT_WIDE_VOLATILE.cpp */
   2754 HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
   2755 OP_END
   2756 
   2757 /* File: c/OP_SGET_WIDE_VOLATILE.cpp */
   2758 HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
   2759 OP_END
   2760 
   2761 /* File: c/OP_SPUT_WIDE_VOLATILE.cpp */
   2762 HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE,    "-wide-volatile", LongVolatile, _WIDE)
   2763 OP_END
   2764 
   2765 /* File: c/OP_BREAKPOINT.cpp */
   2766 HANDLE_OPCODE(OP_BREAKPOINT)
   2767     {
   2768         /*
   2769          * Restart this instruction with the original opcode.  We do
   2770          * this by simply jumping to the handler.
   2771          *
   2772          * It's probably not necessary to update "inst", but we do it
   2773          * for the sake of anything that needs to do disambiguation in a
   2774          * common handler with INST_INST.
   2775          *
   2776          * The breakpoint itself is handled over in updateDebugger(),
   2777          * because we need to detect other events (method entry, single
   2778          * step) and report them in the same event packet, and we're not
   2779          * yet handling those through breakpoint instructions.  By the
   2780          * time we get here, the breakpoint has already been handled and
   2781          * the thread resumed.
   2782          */
   2783         u1 originalOpcode = dvmGetOriginalOpcode(pc);
   2784         ALOGV("+++ break 0x%02x (0x%04x -> 0x%04x)", originalOpcode, inst,
   2785             INST_REPLACE_OP(inst, originalOpcode));
   2786         inst = INST_REPLACE_OP(inst, originalOpcode);
   2787         FINISH_BKPT(originalOpcode);
   2788     }
   2789 OP_END
   2790 
   2791 /* File: c/OP_THROW_VERIFICATION_ERROR.cpp */
   2792 HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
   2793     EXPORT_PC();
   2794     vsrc1 = INST_AA(inst);
   2795     ref = FETCH(1);             /* class/field/method ref */
   2796     dvmThrowVerificationError(curMethod, vsrc1, ref);
   2797     GOTO_exceptionThrown();
   2798 OP_END
   2799 
   2800 /* File: c/OP_EXECUTE_INLINE.cpp */
   2801 HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/)
   2802     {
   2803         /*
   2804          * This has the same form as other method calls, but we ignore
   2805          * the 5th argument (vA).  This is chiefly because the first four
   2806          * arguments to a function on ARM are in registers.
   2807          *
   2808          * We only set the arguments that are actually used, leaving
   2809          * the rest uninitialized.  We're assuming that, if the method
   2810          * needs them, they'll be specified in the call.
   2811          *
   2812          * However, this annoys gcc when optimizations are enabled,
   2813          * causing a "may be used uninitialized" warning.  Quieting
   2814          * the warnings incurs a slight penalty (5%: 373ns vs. 393ns
   2815          * on empty method).  Note that valgrind is perfectly happy
   2816          * either way as the uninitialiezd values are never actually
   2817          * used.
   2818          */
   2819         u4 arg0, arg1, arg2, arg3;
   2820         arg0 = arg1 = arg2 = arg3 = 0;
   2821 
   2822         EXPORT_PC();
   2823 
   2824         vsrc1 = INST_B(inst);       /* #of args */
   2825         ref = FETCH(1);             /* inline call "ref" */
   2826         vdst = FETCH(2);            /* 0-4 register indices */
   2827         ILOGV("|execute-inline args=%d @%d {regs=0x%04x}",
   2828             vsrc1, ref, vdst);
   2829 
   2830         assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
   2831         assert(vsrc1 <= 4);
   2832 
   2833         switch (vsrc1) {
   2834         case 4:
   2835             arg3 = GET_REGISTER(vdst >> 12);
   2836             /* fall through */
   2837         case 3:
   2838             arg2 = GET_REGISTER((vdst & 0x0f00) >> 8);
   2839             /* fall through */
   2840         case 2:
   2841             arg1 = GET_REGISTER((vdst & 0x00f0) >> 4);
   2842             /* fall through */
   2843         case 1:
   2844             arg0 = GET_REGISTER(vdst & 0x0f);
   2845             /* fall through */
   2846         default:        // case 0
   2847             ;
   2848         }
   2849 
   2850         if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
   2851             if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
   2852                 GOTO_exceptionThrown();
   2853         } else {
   2854             if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
   2855                 GOTO_exceptionThrown();
   2856         }
   2857     }
   2858     FINISH(3);
   2859 OP_END
   2860 
   2861 /* File: c/OP_EXECUTE_INLINE_RANGE.cpp */
   2862 HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
   2863     {
   2864         u4 arg0, arg1, arg2, arg3;
   2865         arg0 = arg1 = arg2 = arg3 = 0;      /* placate gcc */
   2866 
   2867         EXPORT_PC();
   2868 
   2869         vsrc1 = INST_AA(inst);      /* #of args */
   2870         ref = FETCH(1);             /* inline call "ref" */
   2871         vdst = FETCH(2);            /* range base */
   2872         ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
   2873             vsrc1, ref, vdst, vdst+vsrc1-1);
   2874 
   2875         assert((vdst >> 16) == 0);  // 16-bit type -or- high 16 bits clear
   2876         assert(vsrc1 <= 4);
   2877 
   2878         switch (vsrc1) {
   2879         case 4:
   2880             arg3 = GET_REGISTER(vdst+3);
   2881             /* fall through */
   2882         case 3:
   2883             arg2 = GET_REGISTER(vdst+2);
   2884             /* fall through */
   2885         case 2:
   2886             arg1 = GET_REGISTER(vdst+1);
   2887             /* fall through */
   2888         case 1:
   2889             arg0 = GET_REGISTER(vdst+0);
   2890             /* fall through */
   2891         default:        // case 0
   2892             ;
   2893         }
   2894 
   2895         if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
   2896             if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
   2897                 GOTO_exceptionThrown();
   2898         } else {
   2899             if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
   2900                 GOTO_exceptionThrown();
   2901         }
   2902     }
   2903     FINISH(3);
   2904 OP_END
   2905 
   2906 /* File: c/OP_INVOKE_OBJECT_INIT_RANGE.cpp */
   2907 HANDLE_OPCODE(OP_INVOKE_OBJECT_INIT_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2908     {
   2909         Object* obj;
   2910 
   2911         vsrc1 = FETCH(2);               /* reg number of "this" pointer */
   2912         obj = GET_REGISTER_AS_OBJECT(vsrc1);
   2913 
   2914         if (!checkForNullExportPC(obj, fp, pc))
   2915             GOTO_exceptionThrown();
   2916 
   2917         /*
   2918          * The object should be marked "finalizable" when Object.<init>
   2919          * completes normally.  We're going to assume it does complete
   2920          * (by virtue of being nothing but a return-void) and set it now.
   2921          */
   2922         if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE)) {
   2923             EXPORT_PC();
   2924             dvmSetFinalizable(obj);
   2925             if (dvmGetException(self))
   2926                 GOTO_exceptionThrown();
   2927         }
   2928 
   2929         if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
   2930             /* behave like OP_INVOKE_DIRECT_RANGE */
   2931             GOTO_invoke(invokeDirect, true);
   2932         }
   2933         FINISH(3);
   2934     }
   2935 OP_END
   2936 
   2937 /* File: c/OP_RETURN_VOID_BARRIER.cpp */
   2938 HANDLE_OPCODE(OP_RETURN_VOID_BARRIER /**/)
   2939     ILOGV("|return-void");
   2940 #ifndef NDEBUG
   2941     retval.j = 0xababababULL;   /* placate valgrind */
   2942 #endif
   2943     ANDROID_MEMBAR_STORE();
   2944     GOTO_returnFromMethod();
   2945 OP_END
   2946 
   2947 /* File: c/OP_IGET_QUICK.cpp */
   2948 HANDLE_IGET_X_QUICK(OP_IGET_QUICK,          "", Int, )
   2949 OP_END
   2950 
   2951 /* File: c/OP_IGET_WIDE_QUICK.cpp */
   2952 HANDLE_IGET_X_QUICK(OP_IGET_WIDE_QUICK,     "-wide", Long, _WIDE)
   2953 OP_END
   2954 
   2955 /* File: c/OP_IGET_OBJECT_QUICK.cpp */
   2956 HANDLE_IGET_X_QUICK(OP_IGET_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
   2957 OP_END
   2958 
   2959 /* File: c/OP_IPUT_QUICK.cpp */
   2960 HANDLE_IPUT_X_QUICK(OP_IPUT_QUICK,          "", Int, )
   2961 OP_END
   2962 
   2963 /* File: c/OP_IPUT_WIDE_QUICK.cpp */
   2964 HANDLE_IPUT_X_QUICK(OP_IPUT_WIDE_QUICK,     "-wide", Long, _WIDE)
   2965 OP_END
   2966 
   2967 /* File: c/OP_IPUT_OBJECT_QUICK.cpp */
   2968 HANDLE_IPUT_X_QUICK(OP_IPUT_OBJECT_QUICK,   "-object", Object, _AS_OBJECT)
   2969 OP_END
   2970 
   2971 /* File: c/OP_INVOKE_VIRTUAL_QUICK.cpp */
   2972 HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2973     GOTO_invoke(invokeVirtualQuick, false);
   2974 OP_END
   2975 
   2976 /* File: c/OP_INVOKE_VIRTUAL_QUICK_RANGE.cpp */
   2977 HANDLE_OPCODE(OP_INVOKE_VIRTUAL_QUICK_RANGE/*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2978     GOTO_invoke(invokeVirtualQuick, true);
   2979 OP_END
   2980 
   2981 /* File: c/OP_INVOKE_SUPER_QUICK.cpp */
   2982 HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
   2983     GOTO_invoke(invokeSuperQuick, false);
   2984 OP_END
   2985 
   2986 /* File: c/OP_INVOKE_SUPER_QUICK_RANGE.cpp */
   2987 HANDLE_OPCODE(OP_INVOKE_SUPER_QUICK_RANGE /*{vCCCC..v(CCCC+AA-1)}, meth@BBBB*/)
   2988     GOTO_invoke(invokeSuperQuick, true);
   2989 OP_END
   2990 
   2991 /* File: c/OP_IPUT_OBJECT_VOLATILE.cpp */
   2992 HANDLE_IPUT_X(OP_IPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
   2993 OP_END
   2994 
   2995 /* File: c/OP_SGET_OBJECT_VOLATILE.cpp */
   2996 HANDLE_SGET_X(OP_SGET_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
   2997 OP_END
   2998 
   2999 /* File: c/OP_SPUT_OBJECT_VOLATILE.cpp */
   3000 HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE,  "-object-volatile", ObjectVolatile, _AS_OBJECT)
   3001 OP_END
   3002 
   3003 /* File: c/OP_UNUSED_FF.cpp */
   3004 HANDLE_OPCODE(OP_UNUSED_FF)
   3005     /*
   3006      * In portable interp, most unused opcodes will fall through to here.
   3007      */
   3008     ALOGE("unknown opcode 0x%02x\n", INST_INST(inst));
   3009     dvmAbort();
   3010     FINISH(1);
   3011 OP_END
   3012 
   3013 /* File: cstubs/entry.cpp */
   3014 /*
   3015  * Handler function table, one entry per opcode.
   3016  */
   3017 #undef H
   3018 #define H(_op) dvmMterp_##_op
   3019 DEFINE_GOTO_TABLE(gDvmMterpHandlers)
   3020 
   3021 #undef H
   3022 #define H(_op) #_op
   3023 DEFINE_GOTO_TABLE(gDvmMterpHandlerNames)
   3024 
   3025 #include <setjmp.h>
   3026 
   3027 /*
   3028  * C mterp entry point.  This just calls the various C fallbacks, making
   3029  * this a slow but portable interpeter.
   3030  *
   3031  * This is only used for the "allstubs" variant.
   3032  */
   3033 void dvmMterpStdRun(Thread* self)
   3034 {
   3035     jmp_buf jmpBuf;
   3036 
   3037     self->bailPtr = &jmpBuf;
   3038 
   3039     /* We exit via a longjmp */
   3040     if (setjmp(jmpBuf)) {
   3041         LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
   3042         return
   3043     }
   3044 
   3045     /* run until somebody longjmp()s out */
   3046     while (true) {
   3047         typedef void (*Handler)(Thread* self);
   3048 
   3049         u2 inst = /*self->interpSave.*/pc[0];
   3050         /*
   3051          * In mterp, dvmCheckBefore is handled via the altHandlerTable,
   3052          * while in the portable interpreter it is part of the handler
   3053          * FINISH code.  For allstubs, we must do an explicit check
   3054          * in the interpretation loop.
   3055          */
   3056         if (self-interpBreak.ctl.subMode) {
   3057             dvmCheckBefore(pc, fp, self, curMethod);
   3058         }
   3059         Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
   3060         (void) gDvmMterpHandlerNames;   /* avoid gcc "defined but not used" */
   3061         LOGVV("handler %p %s",
   3062             handler, (const char*) gDvmMterpHandlerNames[inst & 0xff]);
   3063         (*handler)(self);
   3064     }
   3065 }
   3066 
   3067 /*
   3068  * C mterp exit point.  Call here to bail out of the interpreter.
   3069  */
   3070 void dvmMterpStdBail(Thread* self)
   3071 {
   3072     jmp_buf* pJmpBuf = self->bailPtr;
   3073     longjmp(*pJmpBuf, 1);
   3074 }
   3075 
   3076 /* File: c/gotoTargets.cpp */
   3077 /*
   3078  * C footer.  This has some common code shared by the various targets.
   3079  */
   3080 
   3081 /*
   3082  * Everything from here on is a "goto target".  In the basic interpreter
   3083  * we jump into these targets and then jump directly to the handler for
   3084  * next instruction.  Here, these are subroutines that return to the caller.
   3085  */
   3086 
   3087 GOTO_TARGET(filledNewArray, bool methodCallRange, bool)
   3088     {
   3089         ClassObject* arrayClass;
   3090         ArrayObject* newArray;
   3091         u4* contents;
   3092         char typeCh;
   3093         int i;
   3094         u4 arg5;
   3095 
   3096         EXPORT_PC();
   3097 
   3098         ref = FETCH(1);             /* class ref */
   3099         vdst = FETCH(2);            /* first 4 regs -or- range base */
   3100 
   3101         if (methodCallRange) {
   3102             vsrc1 = INST_AA(inst);  /* #of elements */
   3103             arg5 = -1;              /* silence compiler warning */
   3104             ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}",
   3105                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3106         } else {
   3107             arg5 = INST_A(inst);
   3108             vsrc1 = INST_B(inst);   /* #of elements */
   3109             ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}",
   3110                vsrc1, ref, vdst, arg5);
   3111         }
   3112 
   3113         /*
   3114          * Resolve the array class.
   3115          */
   3116         arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
   3117         if (arrayClass == NULL) {
   3118             arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
   3119             if (arrayClass == NULL)
   3120                 GOTO_exceptionThrown();
   3121         }
   3122         /*
   3123         if (!dvmIsArrayClass(arrayClass)) {
   3124             dvmThrowRuntimeException(
   3125                 "filled-new-array needs array class");
   3126             GOTO_exceptionThrown();
   3127         }
   3128         */
   3129         /* verifier guarantees this is an array class */
   3130         assert(dvmIsArrayClass(arrayClass));
   3131         assert(dvmIsClassInitialized(arrayClass));
   3132 
   3133         /*
   3134          * Create an array of the specified type.
   3135          */
   3136         LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor);
   3137         typeCh = arrayClass->descriptor[1];
   3138         if (typeCh == 'D' || typeCh == 'J') {
   3139             /* category 2 primitives not allowed */
   3140             dvmThrowRuntimeException("bad filled array req");
   3141             GOTO_exceptionThrown();
   3142         } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') {
   3143             /* TODO: requires multiple "fill in" loops with different widths */
   3144             ALOGE("non-int primitives not implemented");
   3145             dvmThrowInternalError(
   3146                 "filled-new-array not implemented for anything but 'int'");
   3147             GOTO_exceptionThrown();
   3148         }
   3149 
   3150         newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
   3151         if (newArray == NULL)
   3152             GOTO_exceptionThrown();
   3153 
   3154         /*
   3155          * Fill in the elements.  It's legal for vsrc1 to be zero.
   3156          */
   3157         contents = (u4*)(void*)newArray->contents;
   3158         if (methodCallRange) {
   3159             for (i = 0; i < vsrc1; i++)
   3160                 contents[i] = GET_REGISTER(vdst+i);
   3161         } else {
   3162             assert(vsrc1 <= 5);
   3163             if (vsrc1 == 5) {
   3164                 contents[4] = GET_REGISTER(arg5);
   3165                 vsrc1--;
   3166             }
   3167             for (i = 0; i < vsrc1; i++) {
   3168                 contents[i] = GET_REGISTER(vdst & 0x0f);
   3169                 vdst >>= 4;
   3170             }
   3171         }
   3172         if (typeCh == 'L' || typeCh == '[') {
   3173             dvmWriteBarrierArray(newArray, 0, newArray->length);
   3174         }
   3175 
   3176         retval.l = (Object*)newArray;
   3177     }
   3178     FINISH(3);
   3179 GOTO_TARGET_END
   3180 
   3181 
   3182 GOTO_TARGET(invokeVirtual, bool methodCallRange, bool)
   3183     {
   3184         Method* baseMethod;
   3185         Object* thisPtr;
   3186 
   3187         EXPORT_PC();
   3188 
   3189         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3190         ref = FETCH(1);             /* method ref */
   3191         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3192 
   3193         /*
   3194          * The object against which we are executing a method is always
   3195          * in the first argument.
   3196          */
   3197         if (methodCallRange) {
   3198             assert(vsrc1 > 0);
   3199             ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}",
   3200                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3201             thisPtr = (Object*) GET_REGISTER(vdst);
   3202         } else {
   3203             assert((vsrc1>>4) > 0);
   3204             ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}",
   3205                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3206             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
   3207         }
   3208 
   3209         if (!checkForNull(thisPtr))
   3210             GOTO_exceptionThrown();
   3211 
   3212         /*
   3213          * Resolve the method.  This is the correct method for the static
   3214          * type of the object.  We also verify access permissions here.
   3215          */
   3216         baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
   3217         if (baseMethod == NULL) {
   3218             baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
   3219             if (baseMethod == NULL) {
   3220                 ILOGV("+ unknown method or access denied");
   3221                 GOTO_exceptionThrown();
   3222             }
   3223         }
   3224 
   3225         /*
   3226          * Combine the object we found with the vtable offset in the
   3227          * method.
   3228          */
   3229         assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
   3230         methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
   3231 
   3232 #if defined(WITH_JIT) && defined(MTERP_STUB)
   3233         self->methodToCall = methodToCall;
   3234         self->callsiteClass = thisPtr->clazz;
   3235 #endif
   3236 
   3237 #if 0
   3238         if (dvmIsAbstractMethod(methodToCall)) {
   3239             /*
   3240              * This can happen if you create two classes, Base and Sub, where
   3241              * Sub is a sub-class of Base.  Declare a protected abstract
   3242              * method foo() in Base, and invoke foo() from a method in Base.
   3243              * Base is an "abstract base class" and is never instantiated
   3244              * directly.  Now, Override foo() in Sub, and use Sub.  This
   3245              * Works fine unless Sub stops providing an implementation of
   3246              * the method.
   3247              */
   3248             dvmThrowAbstractMethodError("abstract method not implemented");
   3249             GOTO_exceptionThrown();
   3250         }
   3251 #else
   3252         assert(!dvmIsAbstractMethod(methodToCall) ||
   3253             methodToCall->nativeFunc != NULL);
   3254 #endif
   3255 
   3256         LOGVV("+++ base=%s.%s virtual[%d]=%s.%s",
   3257             baseMethod->clazz->descriptor, baseMethod->name,
   3258             (u4) baseMethod->methodIndex,
   3259             methodToCall->clazz->descriptor, methodToCall->name);
   3260         assert(methodToCall != NULL);
   3261 
   3262 #if 0
   3263         if (vsrc1 != methodToCall->insSize) {
   3264             ALOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s",
   3265                 baseMethod->clazz->descriptor, baseMethod->name,
   3266                 (u4) baseMethod->methodIndex,
   3267                 methodToCall->clazz->descriptor, methodToCall->name);
   3268             //dvmDumpClass(baseMethod->clazz);
   3269             //dvmDumpClass(methodToCall->clazz);
   3270             dvmDumpAllClasses(0);
   3271         }
   3272 #endif
   3273 
   3274         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3275     }
   3276 GOTO_TARGET_END
   3277 
   3278 GOTO_TARGET(invokeSuper, bool methodCallRange)
   3279     {
   3280         Method* baseMethod;
   3281         u2 thisReg;
   3282 
   3283         EXPORT_PC();
   3284 
   3285         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3286         ref = FETCH(1);             /* method ref */
   3287         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3288 
   3289         if (methodCallRange) {
   3290             ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
   3291                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3292             thisReg = vdst;
   3293         } else {
   3294             ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
   3295                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3296             thisReg = vdst & 0x0f;
   3297         }
   3298 
   3299         /* impossible in well-formed code, but we must check nevertheless */
   3300         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
   3301             GOTO_exceptionThrown();
   3302 
   3303         /*
   3304          * Resolve the method.  This is the correct method for the static
   3305          * type of the object.  We also verify access permissions here.
   3306          * The first arg to dvmResolveMethod() is just the referring class
   3307          * (used for class loaders and such), so we don't want to pass
   3308          * the superclass into the resolution call.
   3309          */
   3310         baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
   3311         if (baseMethod == NULL) {
   3312             baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
   3313             if (baseMethod == NULL) {
   3314                 ILOGV("+ unknown method or access denied");
   3315                 GOTO_exceptionThrown();
   3316             }
   3317         }
   3318 
   3319         /*
   3320          * Combine the object we found with the vtable offset in the
   3321          * method's class.
   3322          *
   3323          * We're using the current method's class' superclass, not the
   3324          * superclass of "this".  This is because we might be executing
   3325          * in a method inherited from a superclass, and we want to run
   3326          * in that class' superclass.
   3327          */
   3328         if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
   3329             /*
   3330              * Method does not exist in the superclass.  Could happen if
   3331              * superclass gets updated.
   3332              */
   3333             dvmThrowNoSuchMethodError(baseMethod->name);
   3334             GOTO_exceptionThrown();
   3335         }
   3336         methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
   3337 
   3338 #if 0
   3339         if (dvmIsAbstractMethod(methodToCall)) {
   3340             dvmThrowAbstractMethodError("abstract method not implemented");
   3341             GOTO_exceptionThrown();
   3342         }
   3343 #else
   3344         assert(!dvmIsAbstractMethod(methodToCall) ||
   3345             methodToCall->nativeFunc != NULL);
   3346 #endif
   3347         LOGVV("+++ base=%s.%s super-virtual=%s.%s",
   3348             baseMethod->clazz->descriptor, baseMethod->name,
   3349             methodToCall->clazz->descriptor, methodToCall->name);
   3350         assert(methodToCall != NULL);
   3351 
   3352         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3353     }
   3354 GOTO_TARGET_END
   3355 
   3356 GOTO_TARGET(invokeInterface, bool methodCallRange)
   3357     {
   3358         Object* thisPtr;
   3359         ClassObject* thisClass;
   3360 
   3361         EXPORT_PC();
   3362 
   3363         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3364         ref = FETCH(1);             /* method ref */
   3365         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3366 
   3367         /*
   3368          * The object against which we are executing a method is always
   3369          * in the first argument.
   3370          */
   3371         if (methodCallRange) {
   3372             assert(vsrc1 > 0);
   3373             ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}",
   3374                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3375             thisPtr = (Object*) GET_REGISTER(vdst);
   3376         } else {
   3377             assert((vsrc1>>4) > 0);
   3378             ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}",
   3379                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3380             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
   3381         }
   3382 
   3383         if (!checkForNull(thisPtr))
   3384             GOTO_exceptionThrown();
   3385 
   3386         thisClass = thisPtr->clazz;
   3387 
   3388         /*
   3389          * Given a class and a method index, find the Method* with the
   3390          * actual code we want to execute.
   3391          */
   3392         methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
   3393                         methodClassDex);
   3394 #if defined(WITH_JIT) && defined(MTERP_STUB)
   3395         self->callsiteClass = thisClass;
   3396         self->methodToCall = methodToCall;
   3397 #endif
   3398         if (methodToCall == NULL) {
   3399             assert(dvmCheckException(self));
   3400             GOTO_exceptionThrown();
   3401         }
   3402 
   3403         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3404     }
   3405 GOTO_TARGET_END
   3406 
   3407 GOTO_TARGET(invokeDirect, bool methodCallRange)
   3408     {
   3409         u2 thisReg;
   3410 
   3411         EXPORT_PC();
   3412 
   3413         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3414         ref = FETCH(1);             /* method ref */
   3415         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3416 
   3417         if (methodCallRange) {
   3418             ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
   3419                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3420             thisReg = vdst;
   3421         } else {
   3422             ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
   3423                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3424             thisReg = vdst & 0x0f;
   3425         }
   3426 
   3427         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
   3428             GOTO_exceptionThrown();
   3429 
   3430         methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
   3431         if (methodToCall == NULL) {
   3432             methodToCall = dvmResolveMethod(curMethod->clazz, ref,
   3433                             METHOD_DIRECT);
   3434             if (methodToCall == NULL) {
   3435                 ILOGV("+ unknown direct method");     // should be impossible
   3436                 GOTO_exceptionThrown();
   3437             }
   3438         }
   3439         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3440     }
   3441 GOTO_TARGET_END
   3442 
   3443 GOTO_TARGET(invokeStatic, bool methodCallRange)
   3444     EXPORT_PC();
   3445 
   3446     vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3447     ref = FETCH(1);             /* method ref */
   3448     vdst = FETCH(2);            /* 4 regs -or- first reg */
   3449 
   3450     if (methodCallRange)
   3451         ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
   3452             vsrc1, ref, vdst, vdst+vsrc1-1);
   3453     else
   3454         ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
   3455             vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3456 
   3457     methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
   3458     if (methodToCall == NULL) {
   3459         methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC);
   3460         if (methodToCall == NULL) {
   3461             ILOGV("+ unknown method");
   3462             GOTO_exceptionThrown();
   3463         }
   3464 
   3465 #if defined(WITH_JIT) && defined(MTERP_STUB)
   3466         /*
   3467          * The JIT needs dvmDexGetResolvedMethod() to return non-null.
   3468          * Include the check if this code is being used as a stub
   3469          * called from the assembly interpreter.
   3470          */
   3471         if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
   3472             (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL)) {
   3473             /* Class initialization is still ongoing */
   3474             dvmJitEndTraceSelect(self,pc);
   3475         }
   3476 #endif
   3477     }
   3478     GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3479 GOTO_TARGET_END
   3480 
   3481 GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
   3482     {
   3483         Object* thisPtr;
   3484 
   3485         EXPORT_PC();
   3486 
   3487         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3488         ref = FETCH(1);             /* vtable index */
   3489         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3490 
   3491         /*
   3492          * The object against which we are executing a method is always
   3493          * in the first argument.
   3494          */
   3495         if (methodCallRange) {
   3496             assert(vsrc1 > 0);
   3497             ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}",
   3498                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3499             thisPtr = (Object*) GET_REGISTER(vdst);
   3500         } else {
   3501             assert((vsrc1>>4) > 0);
   3502             ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}",
   3503                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3504             thisPtr = (Object*) GET_REGISTER(vdst & 0x0f);
   3505         }
   3506 
   3507         if (!checkForNull(thisPtr))
   3508             GOTO_exceptionThrown();
   3509 
   3510 
   3511         /*
   3512          * Combine the object we found with the vtable offset in the
   3513          * method.
   3514          */
   3515         assert(ref < (unsigned int) thisPtr->clazz->vtableCount);
   3516         methodToCall = thisPtr->clazz->vtable[ref];
   3517 #if defined(WITH_JIT) && defined(MTERP_STUB)
   3518         self->callsiteClass = thisPtr->clazz;
   3519         self->methodToCall = methodToCall;
   3520 #endif
   3521 
   3522 #if 0
   3523         if (dvmIsAbstractMethod(methodToCall)) {
   3524             dvmThrowAbstractMethodError("abstract method not implemented");
   3525             GOTO_exceptionThrown();
   3526         }
   3527 #else
   3528         assert(!dvmIsAbstractMethod(methodToCall) ||
   3529             methodToCall->nativeFunc != NULL);
   3530 #endif
   3531 
   3532         LOGVV("+++ virtual[%d]=%s.%s",
   3533             ref, methodToCall->clazz->descriptor, methodToCall->name);
   3534         assert(methodToCall != NULL);
   3535 
   3536         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3537     }
   3538 GOTO_TARGET_END
   3539 
   3540 GOTO_TARGET(invokeSuperQuick, bool methodCallRange)
   3541     {
   3542         u2 thisReg;
   3543 
   3544         EXPORT_PC();
   3545 
   3546         vsrc1 = INST_AA(inst);      /* AA (count) or BA (count + arg 5) */
   3547         ref = FETCH(1);             /* vtable index */
   3548         vdst = FETCH(2);            /* 4 regs -or- first reg */
   3549 
   3550         if (methodCallRange) {
   3551             ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}",
   3552                 vsrc1, ref, vdst, vdst+vsrc1-1);
   3553             thisReg = vdst;
   3554         } else {
   3555             ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
   3556                 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
   3557             thisReg = vdst & 0x0f;
   3558         }
   3559         /* impossible in well-formed code, but we must check nevertheless */
   3560         if (!checkForNull((Object*) GET_REGISTER(thisReg)))
   3561             GOTO_exceptionThrown();
   3562 
   3563 #if 0   /* impossible in optimized + verified code */
   3564         if (ref >= curMethod->clazz->super->vtableCount) {
   3565             dvmThrowNoSuchMethodError(NULL);
   3566             GOTO_exceptionThrown();
   3567         }
   3568 #else
   3569         assert(ref < (unsigned int) curMethod->clazz->super->vtableCount);
   3570 #endif
   3571 
   3572         /*
   3573          * Combine the object we found with the vtable offset in the
   3574          * method's class.
   3575          *
   3576          * We're using the current method's class' superclass, not the
   3577          * superclass of "this".  This is because we might be executing
   3578          * in a method inherited from a superclass, and we want to run
   3579          * in the method's class' superclass.
   3580          */
   3581         methodToCall = curMethod->clazz->super->vtable[ref];
   3582 
   3583 #if 0
   3584         if (dvmIsAbstractMethod(methodToCall)) {
   3585             dvmThrowAbstractMethodError("abstract method not implemented");
   3586             GOTO_exceptionThrown();
   3587         }
   3588 #else
   3589         assert(!dvmIsAbstractMethod(methodToCall) ||
   3590             methodToCall->nativeFunc != NULL);
   3591 #endif
   3592         LOGVV("+++ super-virtual[%d]=%s.%s",
   3593             ref, methodToCall->clazz->descriptor, methodToCall->name);
   3594         assert(methodToCall != NULL);
   3595         GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
   3596     }
   3597 GOTO_TARGET_END
   3598 
   3599 
   3600     /*
   3601      * General handling for return-void, return, and return-wide.  Put the
   3602      * return value in "retval" before jumping here.
   3603      */
   3604 GOTO_TARGET(returnFromMethod)
   3605     {
   3606         StackSaveArea* saveArea;
   3607 
   3608         /*
   3609          * We must do this BEFORE we pop the previous stack frame off, so
   3610          * that the GC can see the return value (if any) in the local vars.
   3611          *
   3612          * Since this is now an interpreter switch point, we must do it before
   3613          * we do anything at all.
   3614          */
   3615         PERIODIC_CHECKS(0);
   3616 
   3617         ILOGV("> retval=0x%llx (leaving %s.%s %s)",
   3618             retval.j, curMethod->clazz->descriptor, curMethod->name,
   3619             curMethod->shorty);
   3620         //DUMP_REGS(curMethod, fp);
   3621 
   3622         saveArea = SAVEAREA_FROM_FP(fp);
   3623 
   3624 #ifdef EASY_GDB
   3625         debugSaveArea = saveArea;
   3626 #endif
   3627 
   3628         /* back up to previous frame and see if we hit a break */
   3629         fp = (u4*)saveArea->prevFrame;
   3630         assert(fp != NULL);
   3631 
   3632         /* Handle any special subMode requirements */
   3633         if (self->interpBreak.ctl.subMode != 0) {
   3634             PC_FP_TO_SELF();
   3635             dvmReportReturn(self);
   3636         }
   3637 
   3638         if (dvmIsBreakFrame(fp)) {
   3639             /* bail without popping the method frame from stack */
   3640             LOGVV("+++ returned into break frame");
   3641             GOTO_bail();
   3642         }
   3643 
   3644         /* update thread FP, and reset local variables */
   3645         self->interpSave.curFrame = fp;
   3646         curMethod = SAVEAREA_FROM_FP(fp)->method;
   3647         self->interpSave.method = curMethod;
   3648         //methodClass = curMethod->clazz;
   3649         methodClassDex = curMethod->clazz->pDvmDex;
   3650         pc = saveArea->savedPc;
   3651         ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor,
   3652             curMethod->name, curMethod->shorty);
   3653 
   3654         /* use FINISH on the caller's invoke instruction */
   3655         //u2 invokeInstr = INST_INST(FETCH(0));
   3656         if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
   3657             invokeInstr <= OP_INVOKE_INTERFACE*/)
   3658         {
   3659             FINISH(3);
   3660         } else {
   3661             //ALOGE("Unknown invoke instr %02x at %d",
   3662             //    invokeInstr, (int) (pc - curMethod->insns));
   3663             assert(false);
   3664         }
   3665     }
   3666 GOTO_TARGET_END
   3667 
   3668 
   3669     /*
   3670      * Jump here when the code throws an exception.
   3671      *
   3672      * By the time we get here, the Throwable has been created and the stack
   3673      * trace has been saved off.
   3674      */
   3675 GOTO_TARGET(exceptionThrown)
   3676     {
   3677         Object* exception;
   3678         int catchRelPc;
   3679 
   3680         PERIODIC_CHECKS(0);
   3681 
   3682         /*
   3683          * We save off the exception and clear the exception status.  While
   3684          * processing the exception we might need to load some Throwable
   3685          * classes, and we don't want class loader exceptions to get
   3686          * confused with this one.
   3687          */
   3688         assert(dvmCheckException(self));
   3689         exception = dvmGetException(self);
   3690         dvmAddTrackedAlloc(exception, self);
   3691         dvmClearException(self);
   3692 
   3693         ALOGV("Handling exception %s at %s:%d",
   3694             exception->clazz->descriptor, curMethod->name,
   3695             dvmLineNumFromPC(curMethod, pc - curMethod->insns));
   3696 
   3697         /*
   3698          * Report the exception throw to any "subMode" watchers.
   3699          *
   3700          * TODO: if the exception was thrown by interpreted code, control
   3701          * fell through native, and then back to us, we will report the
   3702          * exception at the point of the throw and again here.  We can avoid
   3703          * this by not reporting exceptions when we jump here directly from
   3704          * the native call code above, but then we won't report exceptions
   3705          * that were thrown *from* the JNI code (as opposed to *through* it).
   3706          *
   3707          * The correct solution is probably to ignore from-native exceptions
   3708          * here, and have the JNI exception code do the reporting to the
   3709          * debugger.
   3710          */
   3711         if (self->interpBreak.ctl.subMode != 0) {
   3712             PC_FP_TO_SELF();
   3713             dvmReportExceptionThrow(self, exception);
   3714         }
   3715 
   3716         /*
   3717          * We need to unroll to the catch block or the nearest "break"
   3718          * frame.
   3719          *
   3720          * A break frame could indicate that we have reached an intermediate
   3721          * native call, or have gone off the top of the stack and the thread
   3722          * needs to exit.  Either way, we return from here, leaving the
   3723          * exception raised.
   3724          *
   3725          * If we do find a catch block, we want to transfer execution to
   3726          * that point.
   3727          *
   3728          * Note this can cause an exception while resolving classes in
   3729          * the "catch" blocks.
   3730          */
   3731         catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
   3732                     exception, false, (void**)(void*)&fp);
   3733 
   3734         /*
   3735          * Restore the stack bounds after an overflow.  This isn't going to
   3736          * be correct in all circumstances, e.g. if JNI code devours the
   3737          * exception this won't happen until some other exception gets
   3738          * thrown.  If the code keeps pushing the stack bounds we'll end
   3739          * up aborting the VM.
   3740          *
   3741          * Note we want to do this *after* the call to dvmFindCatchBlock,
   3742          * because that may need extra stack space to resolve exception
   3743          * classes (e.g. through a class loader).
   3744          *
   3745          * It's possible for the stack overflow handling to cause an
   3746          * exception (specifically, class resolution in a "catch" block
   3747          * during the call above), so we could see the thread's overflow
   3748          * flag raised but actually be running in a "nested" interpreter
   3749          * frame.  We don't allow doubled-up StackOverflowErrors, so
   3750          * we can check for this by just looking at the exception type
   3751          * in the cleanup function.  Also, we won't unroll past the SOE
   3752          * point because the more-recent exception will hit a break frame
   3753          * as it unrolls to here.
   3754          */
   3755         if (self->stackOverflowed)
   3756             dvmCleanupStackOverflow(self, exception);
   3757 
   3758         if (catchRelPc < 0) {
   3759             /* falling through to JNI code or off the bottom of the stack */
   3760 #if DVM_SHOW_EXCEPTION >= 2
   3761             ALOGD("Exception %s from %s:%d not caught locally",
   3762                 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
   3763                 dvmLineNumFromPC(curMethod, pc - curMethod->insns));
   3764 #endif
   3765             dvmSetException(self, exception);
   3766             dvmReleaseTrackedAlloc(exception, self);
   3767             GOTO_bail();
   3768         }
   3769 
   3770 #if DVM_SHOW_EXCEPTION >= 3
   3771         {
   3772             const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
   3773             ALOGD("Exception %s thrown from %s:%d to %s:%d",
   3774                 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
   3775                 dvmLineNumFromPC(curMethod, pc - curMethod->insns),
   3776                 dvmGetMethodSourceFile(catchMethod),
   3777                 dvmLineNumFromPC(catchMethod, catchRelPc));
   3778         }
   3779 #endif
   3780 
   3781         /*
   3782          * Adjust local variables to match self->interpSave.curFrame and the
   3783          * updated PC.
   3784          */
   3785         //fp = (u4*) self->interpSave.curFrame;
   3786         curMethod = SAVEAREA_FROM_FP(fp)->method;
   3787         self->interpSave.method = curMethod;
   3788         //methodClass = curMethod->clazz;
   3789         methodClassDex = curMethod->clazz->pDvmDex;
   3790         pc = curMethod->insns + catchRelPc;
   3791         ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
   3792             curMethod->name, curMethod->shorty);
   3793         DUMP_REGS(curMethod, fp, false);            // show all regs
   3794 
   3795         /*
   3796          * Restore the exception if the handler wants it.
   3797          *
   3798          * The Dalvik spec mandates that, if an exception handler wants to
   3799          * do something with the exception, the first instruction executed
   3800          * must be "move-exception".  We can pass the exception along
   3801          * through the thread struct, and let the move-exception instruction
   3802          * clear it for us.
   3803          *
   3804          * If the handler doesn't call move-exception, we don't want to
   3805          * finish here with an exception still pending.
   3806          */
   3807         if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
   3808             dvmSetException(self, exception);
   3809 
   3810         dvmReleaseTrackedAlloc(exception, self);
   3811         FINISH(0);
   3812     }
   3813 GOTO_TARGET_END
   3814 
   3815 
   3816 
   3817     /*
   3818      * General handling for invoke-{virtual,super,direct,static,interface},
   3819      * including "quick" variants.
   3820      *
   3821      * Set "methodToCall" to the Method we're calling, and "methodCallRange"
   3822      * depending on whether this is a "/range" instruction.
   3823      *
   3824      * For a range call:
   3825      *  "vsrc1" holds the argument count (8 bits)
   3826      *  "vdst" holds the first argument in the range
   3827      * For a non-range call:
   3828      *  "vsrc1" holds the argument count (4 bits) and the 5th argument index
   3829      *  "vdst" holds four 4-bit register indices
   3830      *
   3831      * The caller must EXPORT_PC before jumping here, because any method
   3832      * call can throw a stack overflow exception.
   3833      */
   3834 GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
   3835     u2 count, u2 regs)
   3836     {
   3837         STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
   3838 
   3839         //printf("range=%d call=%p count=%d regs=0x%04x\n",
   3840         //    methodCallRange, methodToCall, count, regs);
   3841         //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
   3842         //    methodToCall->name, methodToCall->shorty);
   3843 
   3844         u4* outs;
   3845         int i;
   3846 
   3847         /*
   3848          * Copy args.  This may corrupt vsrc1/vdst.
   3849          */
   3850         if (methodCallRange) {
   3851             // could use memcpy or a "Duff's device"; most functions have
   3852             // so few args it won't matter much
   3853             assert(vsrc1 <= curMethod->outsSize);
   3854             assert(vsrc1 == methodToCall->insSize);
   3855             outs = OUTS_FROM_FP(fp, vsrc1);
   3856             for (i = 0; i < vsrc1; i++)
   3857                 outs[i] = GET_REGISTER(vdst+i);
   3858         } else {
   3859             u4 count = vsrc1 >> 4;
   3860 
   3861             assert(count <= curMethod->outsSize);
   3862             assert(count == methodToCall->insSize);
   3863             assert(count <= 5);
   3864 
   3865             outs = OUTS_FROM_FP(fp, count);
   3866 #if 0
   3867             if (count == 5) {
   3868                 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
   3869                 count--;
   3870             }
   3871             for (i = 0; i < (int) count; i++) {
   3872                 outs[i] = GET_REGISTER(vdst & 0x0f);
   3873                 vdst >>= 4;
   3874             }
   3875 #else
   3876             // This version executes fewer instructions but is larger
   3877             // overall.  Seems to be a teensy bit faster.
   3878             assert((vdst >> 16) == 0);  // 16 bits -or- high 16 bits clear
   3879             switch (count) {
   3880             case 5:
   3881                 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
   3882             case 4:
   3883                 outs[3] = GET_REGISTER(vdst >> 12);
   3884             case 3:
   3885                 outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
   3886             case 2:
   3887                 outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
   3888             case 1:
   3889                 outs[0] = GET_REGISTER(vdst & 0x0f);
   3890             default:
   3891                 ;
   3892             }
   3893 #endif
   3894         }
   3895     }
   3896 
   3897     /*
   3898      * (This was originally a "goto" target; I've kept it separate from the
   3899      * stuff above in case we want to refactor things again.)
   3900      *
   3901      * At this point, we have the arguments stored in the "outs" area of
   3902      * the current method's stack frame, and the method to call in
   3903      * "methodToCall".  Push a new stack frame.
   3904      */
   3905     {
   3906         StackSaveArea* newSaveArea;
   3907         u4* newFp;
   3908 
   3909         ILOGV("> %s%s.%s %s",
   3910             dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
   3911             methodToCall->clazz->descriptor, methodToCall->name,
   3912             methodToCall->shorty);
   3913 
   3914         newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
   3915         newSaveArea = SAVEAREA_FROM_FP(newFp);
   3916 
   3917         /* verify that we have enough space */
   3918         if (true) {
   3919             u1* bottom;
   3920             bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
   3921             if (bottom < self->interpStackEnd) {
   3922                 /* stack overflow */
   3923                 ALOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')",
   3924                     self->interpStackStart, self->interpStackEnd, bottom,
   3925                     (u1*) fp - bottom, self->interpStackSize,
   3926                     methodToCall->name);
   3927                 dvmHandleStackOverflow(self, methodToCall);
   3928                 assert(dvmCheckException(self));
   3929                 GOTO_exceptionThrown();
   3930             }
   3931             //ALOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p",
   3932             //    fp, newFp, newSaveArea, bottom);
   3933         }
   3934 
   3935 #ifdef LOG_INSTR
   3936         if (methodToCall->registersSize > methodToCall->insSize) {
   3937             /*
   3938              * This makes valgrind quiet when we print registers that
   3939              * haven't been initialized.  Turn it off when the debug
   3940              * messages are disabled -- we want valgrind to report any
   3941              * used-before-initialized issues.
   3942              */
   3943             memset(newFp, 0xcc,
   3944                 (methodToCall->registersSize - methodToCall->insSize) * 4);
   3945         }
   3946 #endif
   3947 
   3948 #ifdef EASY_GDB
   3949         newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
   3950 #endif
   3951         newSaveArea->prevFrame = fp;
   3952         newSaveArea->savedPc = pc;
   3953 #if defined(WITH_JIT) && defined(MTERP_STUB)
   3954         newSaveArea->returnAddr = 0;
   3955 #endif
   3956         newSaveArea->method = methodToCall;
   3957 
   3958         if (self->interpBreak.ctl.subMode != 0) {
   3959             /*
   3960              * We mark ENTER here for both native and non-native
   3961              * calls.  For native calls, we'll mark EXIT on return.
   3962              * For non-native calls, EXIT is marked in the RETURN op.
   3963              */
   3964             PC_TO_SELF();
   3965             dvmReportInvoke(self, methodToCall);
   3966         }
   3967 
   3968         if (!dvmIsNativeMethod(methodToCall)) {
   3969             /*
   3970              * "Call" interpreted code.  Reposition the PC, update the
   3971              * frame pointer and other local state, and continue.
   3972              */
   3973             curMethod = methodToCall;
   3974             self->interpSave.method = curMethod;
   3975             methodClassDex = curMethod->clazz->pDvmDex;
   3976             pc = methodToCall->insns;
   3977             fp = newFp;
   3978             self->interpSave.curFrame = fp;
   3979 #ifdef EASY_GDB
   3980             debugSaveArea = SAVEAREA_FROM_FP(newFp);
   3981 #endif
   3982             self->debugIsMethodEntry = true;        // profiling, debugging
   3983             ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
   3984                 curMethod->name, curMethod->shorty);
   3985             DUMP_REGS(curMethod, fp, true);         // show input args
   3986             FINISH(0);                              // jump to method start
   3987         } else {
   3988             /* set this up for JNI locals, even if not a JNI native */
   3989             newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
   3990 
   3991             self->interpSave.curFrame = newFp;
   3992 
   3993             DUMP_REGS(methodToCall, newFp, true);   // show input args
   3994 
   3995             if (self->interpBreak.ctl.subMode != 0) {
   3996                 dvmReportPreNativeInvoke(methodToCall, self, fp);
   3997             }
   3998 
   3999             ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
   4000                   methodToCall->name, methodToCall->shorty);
   4001 
   4002             /*
   4003              * Jump through native call bridge.  Because we leave no
   4004              * space for locals on native calls, "newFp" points directly
   4005              * to the method arguments.
   4006              */
   4007             (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
   4008 
   4009             if (self->interpBreak.ctl.subMode != 0) {
   4010                 dvmReportPostNativeInvoke(methodToCall, self, fp);
   4011             }
   4012 
   4013             /* pop frame off */
   4014             dvmPopJniLocals(self, newSaveArea);
   4015             self->interpSave.curFrame = fp;
   4016 
   4017             /*
   4018              * If the native code threw an exception, or interpreted code
   4019              * invoked by the native call threw one and nobody has cleared
   4020              * it, jump to our local exception handling.
   4021              */
   4022             if (dvmCheckException(self)) {
   4023                 ALOGV("Exception thrown by/below native code");
   4024                 GOTO_exceptionThrown();
   4025             }
   4026 
   4027             ILOGD("> retval=0x%llx (leaving native)", retval.j);
   4028             ILOGD("> (return from native %s.%s to %s.%s %s)",
   4029                 methodToCall->clazz->descriptor, methodToCall->name,
   4030                 curMethod->clazz->descriptor, curMethod->name,
   4031                 curMethod->shorty);
   4032 
   4033             //u2 invokeInstr = INST_INST(FETCH(0));
   4034             if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
   4035                 invokeInstr <= OP_INVOKE_INTERFACE*/)
   4036             {
   4037                 FINISH(3);
   4038             } else {
   4039                 //ALOGE("Unknown invoke instr %02x at %d",
   4040                 //    invokeInstr, (int) (pc - curMethod->insns));
   4041                 assert(false);
   4042             }
   4043         }
   4044     }
   4045     assert(false);      // should not get here
   4046 GOTO_TARGET_END
   4047 
   4048 /* File: cstubs/enddefs.cpp */
   4049 
   4050 /* undefine "magic" name remapping */
   4051 #undef retval
   4052 #undef pc
   4053 #undef fp
   4054 #undef curMethod
   4055 #undef methodClassDex
   4056 #undef self
   4057 #undef debugTrackedRefStart
   4058 
   4059