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