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