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