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