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