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