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