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