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