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