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