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