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