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