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