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