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