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