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