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