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