InterpC-x86-atom.c revision cbbd0bedb75b75b99c1112e1f433386a14661b0b
1/* 2 * This file was generated automatically by gen-mterp.py for 'x86-atom'. 3 * 4 * --> DO NOT EDIT <-- 5 */ 6 7/* File: c/header.c */ 8/* 9 * Copyright (C) 2008 The Android Open Source Project 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); 12 * you may not use this file except in compliance with the License. 13 * You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 */ 23 24/* common includes */ 25#include "Dalvik.h" 26#include "interp/InterpDefs.h" 27#include "mterp/Mterp.h" 28#include <math.h> // needed for fmod, fmodf 29#include "mterp/common/FindInterface.h" 30 31/* 32 * Configuration defines. These affect the C implementations, i.e. the 33 * portable interpreter(s) and C stubs. 34 * 35 * Some defines are controlled by the Makefile, e.g.: 36 * WITH_PROFILER 37 * WITH_DEBUGGER 38 * WITH_INSTR_CHECKS 39 * WITH_TRACKREF_CHECKS 40 * EASY_GDB 41 * NDEBUG 42 * 43 * If THREADED_INTERP is not defined, we use a classic "while true / switch" 44 * interpreter. If it is defined, then the tail end of each instruction 45 * handler fetches the next instruction and jumps directly to the handler. 46 * This increases the size of the "Std" interpreter by about 10%, but 47 * provides a speedup of about the same magnitude. 48 * 49 * There's a "hybrid" approach that uses a goto table instead of a switch 50 * statement, avoiding the "is the opcode in range" tests required for switch. 51 * The performance is close to the threaded version, and without the 10% 52 * size increase, but the benchmark results are off enough that it's not 53 * worth adding as a third option. 54 */ 55#define THREADED_INTERP /* threaded vs. while-loop interpreter */ 56 57#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */ 58# define CHECK_BRANCH_OFFSETS 59# define CHECK_REGISTER_INDICES 60#endif 61 62/* 63 * ARM EABI requires 64-bit alignment for access to 64-bit data types. We 64 * can't just use pointers to copy 64-bit values out of our interpreted 65 * register set, because gcc will generate ldrd/strd. 66 * 67 * The __UNION version copies data in and out of a union. The __MEMCPY 68 * version uses a memcpy() call to do the transfer; gcc is smart enough to 69 * not actually call memcpy(). The __UNION version is very bad on ARM; 70 * it only uses one more instruction than __MEMCPY, but for some reason 71 * gcc thinks it needs separate storage for every instance of the union. 72 * On top of that, it feels the need to zero them out at the start of the 73 * method. Net result is we zero out ~700 bytes of stack space at the top 74 * of the interpreter using ARM STM instructions. 75 */ 76#if defined(__ARM_EABI__) 77//# define NO_UNALIGN_64__UNION 78# define NO_UNALIGN_64__MEMCPY 79#endif 80 81//#define LOG_INSTR /* verbose debugging */ 82/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */ 83 84/* 85 * Keep a tally of accesses to fields. Currently only works if full DEX 86 * optimization is disabled. 87 */ 88#ifdef PROFILE_FIELD_ACCESS 89# define UPDATE_FIELD_GET(_field) { (_field)->gets++; } 90# define UPDATE_FIELD_PUT(_field) { (_field)->puts++; } 91#else 92# define UPDATE_FIELD_GET(_field) ((void)0) 93# define UPDATE_FIELD_PUT(_field) ((void)0) 94#endif 95 96/* 97 * Export another copy of the PC on every instruction; this is largely 98 * redundant with EXPORT_PC and the debugger code. This value can be 99 * compared against what we have stored on the stack with EXPORT_PC to 100 * help ensure that we aren't missing any export calls. 101 */ 102#if WITH_EXTRA_GC_CHECKS > 1 103# define EXPORT_EXTRA_PC() (self->currentPc2 = pc) 104#else 105# define EXPORT_EXTRA_PC() 106#endif 107 108/* 109 * Adjust the program counter. "_offset" is a signed int, in 16-bit units. 110 * 111 * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns". 112 * 113 * We don't advance the program counter until we finish an instruction or 114 * branch, because we do want to have to unroll the PC if there's an 115 * exception. 116 */ 117#ifdef CHECK_BRANCH_OFFSETS 118# define ADJUST_PC(_offset) do { \ 119 int myoff = _offset; /* deref only once */ \ 120 if (pc + myoff < curMethod->insns || \ 121 pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \ 122 { \ 123 char* desc; \ 124 desc = dexProtoCopyMethodDescriptor(&curMethod->prototype); \ 125 LOGE("Invalid branch %d at 0x%04x in %s.%s %s\n", \ 126 myoff, (int) (pc - curMethod->insns), \ 127 curMethod->clazz->descriptor, curMethod->name, desc); \ 128 free(desc); \ 129 dvmAbort(); \ 130 } \ 131 pc += myoff; \ 132 EXPORT_EXTRA_PC(); \ 133 } while (false) 134#else 135# define ADJUST_PC(_offset) do { \ 136 pc += _offset; \ 137 EXPORT_EXTRA_PC(); \ 138 } while (false) 139#endif 140 141/* 142 * If enabled, log instructions as we execute them. 143 */ 144#ifdef LOG_INSTR 145# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__) 146# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__) 147# define ILOG(_level, ...) do { \ 148 char debugStrBuf[128]; \ 149 snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__); \ 150 if (curMethod != NULL) \ 151 LOG(_level, LOG_TAG"i", "%-2d|%04x%s\n", \ 152 self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \ 153 else \ 154 LOG(_level, LOG_TAG"i", "%-2d|####%s\n", \ 155 self->threadId, debugStrBuf); \ 156 } while(false) 157void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly); 158# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly) 159static const char kSpacing[] = " "; 160#else 161# define ILOGD(...) ((void)0) 162# define ILOGV(...) ((void)0) 163# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0) 164#endif 165 166/* get a long from an array of u4 */ 167static inline s8 getLongFromArray(const u4* ptr, int idx) 168{ 169#if defined(NO_UNALIGN_64__UNION) 170 union { s8 ll; u4 parts[2]; } conv; 171 172 ptr += idx; 173 conv.parts[0] = ptr[0]; 174 conv.parts[1] = ptr[1]; 175 return conv.ll; 176#elif defined(NO_UNALIGN_64__MEMCPY) 177 s8 val; 178 memcpy(&val, &ptr[idx], 8); 179 return val; 180#else 181 return *((s8*) &ptr[idx]); 182#endif 183} 184 185/* store a long into an array of u4 */ 186static inline void putLongToArray(u4* ptr, int idx, s8 val) 187{ 188#if defined(NO_UNALIGN_64__UNION) 189 union { s8 ll; u4 parts[2]; } conv; 190 191 ptr += idx; 192 conv.ll = val; 193 ptr[0] = conv.parts[0]; 194 ptr[1] = conv.parts[1]; 195#elif defined(NO_UNALIGN_64__MEMCPY) 196 memcpy(&ptr[idx], &val, 8); 197#else 198 *((s8*) &ptr[idx]) = val; 199#endif 200} 201 202/* get a double from an array of u4 */ 203static inline double getDoubleFromArray(const u4* ptr, int idx) 204{ 205#if defined(NO_UNALIGN_64__UNION) 206 union { double d; u4 parts[2]; } conv; 207 208 ptr += idx; 209 conv.parts[0] = ptr[0]; 210 conv.parts[1] = ptr[1]; 211 return conv.d; 212#elif defined(NO_UNALIGN_64__MEMCPY) 213 double dval; 214 memcpy(&dval, &ptr[idx], 8); 215 return dval; 216#else 217 return *((double*) &ptr[idx]); 218#endif 219} 220 221/* store a double into an array of u4 */ 222static inline void putDoubleToArray(u4* ptr, int idx, double dval) 223{ 224#if defined(NO_UNALIGN_64__UNION) 225 union { double d; u4 parts[2]; } conv; 226 227 ptr += idx; 228 conv.d = dval; 229 ptr[0] = conv.parts[0]; 230 ptr[1] = conv.parts[1]; 231#elif defined(NO_UNALIGN_64__MEMCPY) 232 memcpy(&ptr[idx], &dval, 8); 233#else 234 *((double*) &ptr[idx]) = dval; 235#endif 236} 237 238/* 239 * If enabled, validate the register number on every access. Otherwise, 240 * just do an array access. 241 * 242 * Assumes the existence of "u4* fp". 243 * 244 * "_idx" may be referenced more than once. 245 */ 246#ifdef CHECK_REGISTER_INDICES 247# define GET_REGISTER(_idx) \ 248 ( (_idx) < curMethod->registersSize ? \ 249 (fp[(_idx)]) : (assert(!"bad reg"),1969) ) 250# define SET_REGISTER(_idx, _val) \ 251 ( (_idx) < curMethod->registersSize ? \ 252 (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) ) 253# define GET_REGISTER_AS_OBJECT(_idx) ((Object *)GET_REGISTER(_idx)) 254# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val) 255# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx)) 256# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val) 257# define GET_REGISTER_WIDE(_idx) \ 258 ( (_idx) < curMethod->registersSize-1 ? \ 259 getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) ) 260# define SET_REGISTER_WIDE(_idx, _val) \ 261 ( (_idx) < curMethod->registersSize-1 ? \ 262 putLongToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969) ) 263# define GET_REGISTER_FLOAT(_idx) \ 264 ( (_idx) < curMethod->registersSize ? \ 265 (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) ) 266# define SET_REGISTER_FLOAT(_idx, _val) \ 267 ( (_idx) < curMethod->registersSize ? \ 268 (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) ) 269# define GET_REGISTER_DOUBLE(_idx) \ 270 ( (_idx) < curMethod->registersSize-1 ? \ 271 getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) ) 272# define SET_REGISTER_DOUBLE(_idx, _val) \ 273 ( (_idx) < curMethod->registersSize-1 ? \ 274 putDoubleToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969.0) ) 275#else 276# define GET_REGISTER(_idx) (fp[(_idx)]) 277# define SET_REGISTER(_idx, _val) (fp[(_idx)] = (_val)) 278# define GET_REGISTER_AS_OBJECT(_idx) ((Object*) fp[(_idx)]) 279# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val)) 280# define GET_REGISTER_INT(_idx) ((s4)GET_REGISTER(_idx)) 281# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val) 282# define GET_REGISTER_WIDE(_idx) getLongFromArray(fp, (_idx)) 283# define SET_REGISTER_WIDE(_idx, _val) putLongToArray(fp, (_idx), (_val)) 284# define GET_REGISTER_FLOAT(_idx) (*((float*) &fp[(_idx)])) 285# define SET_REGISTER_FLOAT(_idx, _val) (*((float*) &fp[(_idx)]) = (_val)) 286# define GET_REGISTER_DOUBLE(_idx) getDoubleFromArray(fp, (_idx)) 287# define SET_REGISTER_DOUBLE(_idx, _val) putDoubleToArray(fp, (_idx), (_val)) 288#endif 289 290/* 291 * Get 16 bits from the specified offset of the program counter. We always 292 * want to load 16 bits at a time from the instruction stream -- it's more 293 * efficient than 8 and won't have the alignment problems that 32 might. 294 * 295 * Assumes existence of "const u2* pc". 296 */ 297#define FETCH(_offset) (pc[(_offset)]) 298 299/* 300 * Extract instruction byte from 16-bit fetch (_inst is a u2). 301 */ 302#define INST_INST(_inst) ((_inst) & 0xff) 303 304/* 305 * Replace the opcode (used when handling breakpoints). _opcode is a u1. 306 */ 307#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode) 308 309/* 310 * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2). 311 */ 312#define INST_A(_inst) (((_inst) >> 8) & 0x0f) 313#define INST_B(_inst) ((_inst) >> 12) 314 315/* 316 * Get the 8-bit "vAA" 8-bit register index from the instruction word. 317 * (_inst is u2) 318 */ 319#define INST_AA(_inst) ((_inst) >> 8) 320 321/* 322 * The current PC must be available to Throwable constructors, e.g. 323 * those created by dvmThrowException(), so that the exception stack 324 * trace can be generated correctly. If we don't do this, the offset 325 * within the current method won't be shown correctly. See the notes 326 * in Exception.c. 327 * 328 * This is also used to determine the address for precise GC. 329 * 330 * Assumes existence of "u4* fp" and "const u2* pc". 331 */ 332#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc) 333 334/* 335 * Determine if we need to switch to a different interpreter. "_current" 336 * is either INTERP_STD or INTERP_DBG. It should be fixed for a given 337 * interpreter generation file, which should remove the outer conditional 338 * from the following. 339 * 340 * If we're building without debug and profiling support, we never switch. 341 */ 342#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) 343#if defined(WITH_JIT) 344# define NEED_INTERP_SWITCH(_current) ( \ 345 (_current == INTERP_STD) ? \ 346 dvmJitDebuggerOrProfilerActive() : !dvmJitDebuggerOrProfilerActive() ) 347#else 348# define NEED_INTERP_SWITCH(_current) ( \ 349 (_current == INTERP_STD) ? \ 350 dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() ) 351#endif 352#else 353# define NEED_INTERP_SWITCH(_current) (false) 354#endif 355 356/* 357 * Check to see if "obj" is NULL. If so, throw an exception. Assumes the 358 * pc has already been exported to the stack. 359 * 360 * Perform additional checks on debug builds. 361 * 362 * Use this to check for NULL when the instruction handler calls into 363 * something that could throw an exception (so we have already called 364 * EXPORT_PC at the top). 365 */ 366static inline bool checkForNull(Object* obj) 367{ 368 if (obj == NULL) { 369 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 370 return false; 371 } 372#ifdef WITH_EXTRA_OBJECT_VALIDATION 373 if (!dvmIsValidObject(obj)) { 374 LOGE("Invalid object %p\n", obj); 375 dvmAbort(); 376 } 377#endif 378#ifndef NDEBUG 379 if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) { 380 /* probable heap corruption */ 381 LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj); 382 dvmAbort(); 383 } 384#endif 385 return true; 386} 387 388/* 389 * Check to see if "obj" is NULL. If so, export the PC into the stack 390 * frame and throw an exception. 391 * 392 * Perform additional checks on debug builds. 393 * 394 * Use this to check for NULL when the instruction handler doesn't do 395 * anything else that can throw an exception. 396 */ 397static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc) 398{ 399 if (obj == NULL) { 400 EXPORT_PC(); 401 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 402 return false; 403 } 404#ifdef WITH_EXTRA_OBJECT_VALIDATION 405 if (!dvmIsValidObject(obj)) { 406 LOGE("Invalid object %p\n", obj); 407 dvmAbort(); 408 } 409#endif 410#ifndef NDEBUG 411 if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) { 412 /* probable heap corruption */ 413 LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj); 414 dvmAbort(); 415 } 416#endif 417 return true; 418} 419 420/* File: cstubs/stubdefs.c */ 421/* this is a standard (no debug support) interpreter */ 422#define INTERP_TYPE INTERP_STD 423#define CHECK_DEBUG_AND_PROF() ((void)0) 424# define CHECK_TRACKED_REFS() ((void)0) 425#define CHECK_JIT() (0) 426#define ABORT_JIT_TSELECT() ((void)0) 427 428/* 429 * In the C mterp stubs, "goto" is a function call followed immediately 430 * by a return. 431 */ 432 433#define GOTO_TARGET_DECL(_target, ...) \ 434 void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__); 435 436#define GOTO_TARGET(_target, ...) \ 437 void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) { \ 438 u2 ref, vsrc1, vsrc2, vdst; \ 439 u2 inst = FETCH(0); \ 440 const Method* methodToCall; \ 441 StackSaveArea* debugSaveArea; 442 443#define GOTO_TARGET_END } 444 445/* 446 * Redefine what used to be local variable accesses into MterpGlue struct 447 * references. (These are undefined down in "footer.c".) 448 */ 449#define retval glue->retval 450#define pc glue->pc 451#define fp glue->fp 452#define curMethod glue->method 453#define methodClassDex glue->methodClassDex 454#define self glue->self 455#define debugTrackedRefStart glue->debugTrackedRefStart 456 457/* ugh */ 458#define STUB_HACK(x) x 459 460 461/* 462 * Opcode handler framing macros. Here, each opcode is a separate function 463 * that takes a "glue" argument and returns void. We can't declare 464 * these "static" because they may be called from an assembly stub. 465 */ 466#define HANDLE_OPCODE(_op) \ 467 void dvmMterp_##_op(MterpGlue* glue) { \ 468 u2 ref, vsrc1, vsrc2, vdst; \ 469 u2 inst = FETCH(0); 470 471#define OP_END } 472 473/* 474 * Like the "portable" FINISH, but don't reload "inst", and return to caller 475 * when done. 476 */ 477#define FINISH(_offset) { \ 478 ADJUST_PC(_offset); \ 479 CHECK_DEBUG_AND_PROF(); \ 480 CHECK_TRACKED_REFS(); \ 481 return; \ 482 } 483 484 485/* 486 * The "goto label" statements turn into function calls followed by 487 * return statements. Some of the functions take arguments, which in the 488 * portable interpreter are handled by assigning values to globals. 489 */ 490 491#define GOTO_exceptionThrown() \ 492 do { \ 493 dvmMterp_exceptionThrown(glue); \ 494 return; \ 495 } while(false) 496 497#define GOTO_returnFromMethod() \ 498 do { \ 499 dvmMterp_returnFromMethod(glue); \ 500 return; \ 501 } while(false) 502 503#define GOTO_invoke(_target, _methodCallRange) \ 504 do { \ 505 dvmMterp_##_target(glue, _methodCallRange); \ 506 return; \ 507 } while(false) 508 509#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \ 510 do { \ 511 dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall, \ 512 _vsrc1, _vdst); \ 513 return; \ 514 } while(false) 515 516/* 517 * As a special case, "goto bail" turns into a longjmp. Use "bail_switch" 518 * if we need to switch to the other interpreter upon our return. 519 */ 520#define GOTO_bail() \ 521 dvmMterpStdBail(glue, false); 522#define GOTO_bail_switch() \ 523 dvmMterpStdBail(glue, true); 524 525/* 526 * Periodically check for thread suspension. 527 * 528 * While we're at it, see if a debugger has attached or the profiler has 529 * started. If so, switch to a different "goto" table. 530 */ 531#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \ 532 if (dvmCheckSuspendQuick(self)) { \ 533 EXPORT_PC(); /* need for precise GC */ \ 534 dvmCheckSuspendPending(self); \ 535 } \ 536 if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \ 537 ADJUST_PC(_pcadj); \ 538 glue->entryPoint = _entryPoint; \ 539 LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n", \ 540 self->threadId, (_entryPoint), (_pcadj)); \ 541 GOTO_bail_switch(); \ 542 } \ 543 } 544 545/* File: c/opcommon.c */ 546/* forward declarations of goto targets */ 547GOTO_TARGET_DECL(filledNewArray, bool methodCallRange); 548GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange); 549GOTO_TARGET_DECL(invokeSuper, bool methodCallRange); 550GOTO_TARGET_DECL(invokeInterface, bool methodCallRange); 551GOTO_TARGET_DECL(invokeDirect, bool methodCallRange); 552GOTO_TARGET_DECL(invokeStatic, bool methodCallRange); 553GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange); 554GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange); 555GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall, 556 u2 count, u2 regs); 557GOTO_TARGET_DECL(returnFromMethod); 558GOTO_TARGET_DECL(exceptionThrown); 559 560/* 561 * =========================================================================== 562 * 563 * What follows are opcode definitions shared between multiple opcodes with 564 * minor substitutions handled by the C pre-processor. These should probably 565 * use the mterp substitution mechanism instead, with the code here moved 566 * into common fragment files (like the asm "binop.S"), although it's hard 567 * to give up the C preprocessor in favor of the much simpler text subst. 568 * 569 * =========================================================================== 570 */ 571 572#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \ 573 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 574 vdst = INST_A(inst); \ 575 vsrc1 = INST_B(inst); \ 576 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 577 SET_REGISTER##_totype(vdst, \ 578 GET_REGISTER##_fromtype(vsrc1)); \ 579 FINISH(1); 580 581#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \ 582 _tovtype, _tortype) \ 583 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 584 { \ 585 /* spec defines specific handling for +/- inf and NaN values */ \ 586 _fromvtype val; \ 587 _tovtype intMin, intMax, result; \ 588 vdst = INST_A(inst); \ 589 vsrc1 = INST_B(inst); \ 590 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 591 val = GET_REGISTER##_fromrtype(vsrc1); \ 592 intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \ 593 intMax = ~intMin; \ 594 result = (_tovtype) val; \ 595 if (val >= intMax) /* +inf */ \ 596 result = intMax; \ 597 else if (val <= intMin) /* -inf */ \ 598 result = intMin; \ 599 else if (val != val) /* NaN */ \ 600 result = 0; \ 601 else \ 602 result = (_tovtype) val; \ 603 SET_REGISTER##_tortype(vdst, result); \ 604 } \ 605 FINISH(1); 606 607#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \ 608 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 609 vdst = INST_A(inst); \ 610 vsrc1 = INST_B(inst); \ 611 ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \ 612 SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \ 613 FINISH(1); 614 615/* NOTE: the comparison result is always a signed 4-byte integer */ 616#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \ 617 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 618 { \ 619 int result; \ 620 u2 regs; \ 621 _varType val1, val2; \ 622 vdst = INST_AA(inst); \ 623 regs = FETCH(1); \ 624 vsrc1 = regs & 0xff; \ 625 vsrc2 = regs >> 8; \ 626 ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 627 val1 = GET_REGISTER##_type(vsrc1); \ 628 val2 = GET_REGISTER##_type(vsrc2); \ 629 if (val1 == val2) \ 630 result = 0; \ 631 else if (val1 < val2) \ 632 result = -1; \ 633 else if (val1 > val2) \ 634 result = 1; \ 635 else \ 636 result = (_nanVal); \ 637 ILOGV("+ result=%d\n", result); \ 638 SET_REGISTER(vdst, result); \ 639 } \ 640 FINISH(2); 641 642#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \ 643 HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \ 644 vsrc1 = INST_A(inst); \ 645 vsrc2 = INST_B(inst); \ 646 if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \ 647 int branchOffset = (s2)FETCH(1); /* sign-extended */ \ 648 ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \ 649 branchOffset); \ 650 ILOGV("> branch taken"); \ 651 if (branchOffset < 0) \ 652 PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \ 653 FINISH(branchOffset); \ 654 } else { \ 655 ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \ 656 FINISH(2); \ 657 } 658 659#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \ 660 HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \ 661 vsrc1 = INST_AA(inst); \ 662 if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \ 663 int branchOffset = (s2)FETCH(1); /* sign-extended */ \ 664 ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \ 665 ILOGV("> branch taken"); \ 666 if (branchOffset < 0) \ 667 PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \ 668 FINISH(branchOffset); \ 669 } else { \ 670 ILOGV("|if-%s v%d,-", (_opname), vsrc1); \ 671 FINISH(2); \ 672 } 673 674#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \ 675 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 676 vdst = INST_A(inst); \ 677 vsrc1 = INST_B(inst); \ 678 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 679 SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \ 680 FINISH(1); 681 682#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \ 683 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 684 { \ 685 u2 srcRegs; \ 686 vdst = INST_AA(inst); \ 687 srcRegs = FETCH(1); \ 688 vsrc1 = srcRegs & 0xff; \ 689 vsrc2 = srcRegs >> 8; \ 690 ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \ 691 if (_chkdiv != 0) { \ 692 s4 firstVal, secondVal, result; \ 693 firstVal = GET_REGISTER(vsrc1); \ 694 secondVal = GET_REGISTER(vsrc2); \ 695 if (secondVal == 0) { \ 696 EXPORT_PC(); \ 697 dvmThrowException("Ljava/lang/ArithmeticException;", \ 698 "divide by zero"); \ 699 GOTO_exceptionThrown(); \ 700 } \ 701 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 702 if (_chkdiv == 1) \ 703 result = firstVal; /* division */ \ 704 else \ 705 result = 0; /* remainder */ \ 706 } else { \ 707 result = firstVal _op secondVal; \ 708 } \ 709 SET_REGISTER(vdst, result); \ 710 } else { \ 711 /* non-div/rem case */ \ 712 SET_REGISTER(vdst, \ 713 (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \ 714 } \ 715 } \ 716 FINISH(2); 717 718#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \ 719 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 720 { \ 721 u2 srcRegs; \ 722 vdst = INST_AA(inst); \ 723 srcRegs = FETCH(1); \ 724 vsrc1 = srcRegs & 0xff; \ 725 vsrc2 = srcRegs >> 8; \ 726 ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \ 727 SET_REGISTER(vdst, \ 728 _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \ 729 } \ 730 FINISH(2); 731 732#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \ 733 HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \ 734 vdst = INST_A(inst); \ 735 vsrc1 = INST_B(inst); \ 736 vsrc2 = FETCH(1); \ 737 ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \ 738 (_opname), vdst, vsrc1, vsrc2); \ 739 if (_chkdiv != 0) { \ 740 s4 firstVal, result; \ 741 firstVal = GET_REGISTER(vsrc1); \ 742 if ((s2) vsrc2 == 0) { \ 743 EXPORT_PC(); \ 744 dvmThrowException("Ljava/lang/ArithmeticException;", \ 745 "divide by zero"); \ 746 GOTO_exceptionThrown(); \ 747 } \ 748 if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \ 749 /* won't generate /lit16 instr for this; check anyway */ \ 750 if (_chkdiv == 1) \ 751 result = firstVal; /* division */ \ 752 else \ 753 result = 0; /* remainder */ \ 754 } else { \ 755 result = firstVal _op (s2) vsrc2; \ 756 } \ 757 SET_REGISTER(vdst, result); \ 758 } else { \ 759 /* non-div/rem case */ \ 760 SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \ 761 } \ 762 FINISH(2); 763 764#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \ 765 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 766 { \ 767 u2 litInfo; \ 768 vdst = INST_AA(inst); \ 769 litInfo = FETCH(1); \ 770 vsrc1 = litInfo & 0xff; \ 771 vsrc2 = litInfo >> 8; /* constant */ \ 772 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 773 (_opname), vdst, vsrc1, vsrc2); \ 774 if (_chkdiv != 0) { \ 775 s4 firstVal, result; \ 776 firstVal = GET_REGISTER(vsrc1); \ 777 if ((s1) vsrc2 == 0) { \ 778 EXPORT_PC(); \ 779 dvmThrowException("Ljava/lang/ArithmeticException;", \ 780 "divide by zero"); \ 781 GOTO_exceptionThrown(); \ 782 } \ 783 if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \ 784 if (_chkdiv == 1) \ 785 result = firstVal; /* division */ \ 786 else \ 787 result = 0; /* remainder */ \ 788 } else { \ 789 result = firstVal _op ((s1) vsrc2); \ 790 } \ 791 SET_REGISTER(vdst, result); \ 792 } else { \ 793 SET_REGISTER(vdst, \ 794 (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \ 795 } \ 796 } \ 797 FINISH(2); 798 799#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \ 800 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 801 { \ 802 u2 litInfo; \ 803 vdst = INST_AA(inst); \ 804 litInfo = FETCH(1); \ 805 vsrc1 = litInfo & 0xff; \ 806 vsrc2 = litInfo >> 8; /* constant */ \ 807 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 808 (_opname), vdst, vsrc1, vsrc2); \ 809 SET_REGISTER(vdst, \ 810 _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \ 811 } \ 812 FINISH(2); 813 814#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \ 815 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 816 vdst = INST_A(inst); \ 817 vsrc1 = INST_B(inst); \ 818 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 819 if (_chkdiv != 0) { \ 820 s4 firstVal, secondVal, result; \ 821 firstVal = GET_REGISTER(vdst); \ 822 secondVal = GET_REGISTER(vsrc1); \ 823 if (secondVal == 0) { \ 824 EXPORT_PC(); \ 825 dvmThrowException("Ljava/lang/ArithmeticException;", \ 826 "divide by zero"); \ 827 GOTO_exceptionThrown(); \ 828 } \ 829 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 830 if (_chkdiv == 1) \ 831 result = firstVal; /* division */ \ 832 else \ 833 result = 0; /* remainder */ \ 834 } else { \ 835 result = firstVal _op secondVal; \ 836 } \ 837 SET_REGISTER(vdst, result); \ 838 } else { \ 839 SET_REGISTER(vdst, \ 840 (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \ 841 } \ 842 FINISH(1); 843 844#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \ 845 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 846 vdst = INST_A(inst); \ 847 vsrc1 = INST_B(inst); \ 848 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 849 SET_REGISTER(vdst, \ 850 _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \ 851 FINISH(1); 852 853#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \ 854 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 855 { \ 856 u2 srcRegs; \ 857 vdst = INST_AA(inst); \ 858 srcRegs = FETCH(1); \ 859 vsrc1 = srcRegs & 0xff; \ 860 vsrc2 = srcRegs >> 8; \ 861 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 862 if (_chkdiv != 0) { \ 863 s8 firstVal, secondVal, result; \ 864 firstVal = GET_REGISTER_WIDE(vsrc1); \ 865 secondVal = GET_REGISTER_WIDE(vsrc2); \ 866 if (secondVal == 0LL) { \ 867 EXPORT_PC(); \ 868 dvmThrowException("Ljava/lang/ArithmeticException;", \ 869 "divide by zero"); \ 870 GOTO_exceptionThrown(); \ 871 } \ 872 if ((u8)firstVal == 0x8000000000000000ULL && \ 873 secondVal == -1LL) \ 874 { \ 875 if (_chkdiv == 1) \ 876 result = firstVal; /* division */ \ 877 else \ 878 result = 0; /* remainder */ \ 879 } else { \ 880 result = firstVal _op secondVal; \ 881 } \ 882 SET_REGISTER_WIDE(vdst, result); \ 883 } else { \ 884 SET_REGISTER_WIDE(vdst, \ 885 (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \ 886 } \ 887 } \ 888 FINISH(2); 889 890#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \ 891 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 892 { \ 893 u2 srcRegs; \ 894 vdst = INST_AA(inst); \ 895 srcRegs = FETCH(1); \ 896 vsrc1 = srcRegs & 0xff; \ 897 vsrc2 = srcRegs >> 8; \ 898 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 899 SET_REGISTER_WIDE(vdst, \ 900 _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \ 901 } \ 902 FINISH(2); 903 904#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \ 905 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 906 vdst = INST_A(inst); \ 907 vsrc1 = INST_B(inst); \ 908 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 909 if (_chkdiv != 0) { \ 910 s8 firstVal, secondVal, result; \ 911 firstVal = GET_REGISTER_WIDE(vdst); \ 912 secondVal = GET_REGISTER_WIDE(vsrc1); \ 913 if (secondVal == 0LL) { \ 914 EXPORT_PC(); \ 915 dvmThrowException("Ljava/lang/ArithmeticException;", \ 916 "divide by zero"); \ 917 GOTO_exceptionThrown(); \ 918 } \ 919 if ((u8)firstVal == 0x8000000000000000ULL && \ 920 secondVal == -1LL) \ 921 { \ 922 if (_chkdiv == 1) \ 923 result = firstVal; /* division */ \ 924 else \ 925 result = 0; /* remainder */ \ 926 } else { \ 927 result = firstVal _op secondVal; \ 928 } \ 929 SET_REGISTER_WIDE(vdst, result); \ 930 } else { \ 931 SET_REGISTER_WIDE(vdst, \ 932 (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\ 933 } \ 934 FINISH(1); 935 936#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \ 937 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 938 vdst = INST_A(inst); \ 939 vsrc1 = INST_B(inst); \ 940 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 941 SET_REGISTER_WIDE(vdst, \ 942 _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \ 943 FINISH(1); 944 945#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \ 946 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 947 { \ 948 u2 srcRegs; \ 949 vdst = INST_AA(inst); \ 950 srcRegs = FETCH(1); \ 951 vsrc1 = srcRegs & 0xff; \ 952 vsrc2 = srcRegs >> 8; \ 953 ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 954 SET_REGISTER_FLOAT(vdst, \ 955 GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \ 956 } \ 957 FINISH(2); 958 959#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \ 960 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 961 { \ 962 u2 srcRegs; \ 963 vdst = INST_AA(inst); \ 964 srcRegs = FETCH(1); \ 965 vsrc1 = srcRegs & 0xff; \ 966 vsrc2 = srcRegs >> 8; \ 967 ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 968 SET_REGISTER_DOUBLE(vdst, \ 969 GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \ 970 } \ 971 FINISH(2); 972 973#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \ 974 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 975 vdst = INST_A(inst); \ 976 vsrc1 = INST_B(inst); \ 977 ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 978 SET_REGISTER_FLOAT(vdst, \ 979 GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \ 980 FINISH(1); 981 982#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \ 983 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 984 vdst = INST_A(inst); \ 985 vsrc1 = INST_B(inst); \ 986 ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 987 SET_REGISTER_DOUBLE(vdst, \ 988 GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \ 989 FINISH(1); 990 991#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \ 992 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 993 { \ 994 ArrayObject* arrayObj; \ 995 u2 arrayInfo; \ 996 EXPORT_PC(); \ 997 vdst = INST_AA(inst); \ 998 arrayInfo = FETCH(1); \ 999 vsrc1 = arrayInfo & 0xff; /* array ptr */ \ 1000 vsrc2 = arrayInfo >> 8; /* index */ \ 1001 ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 1002 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 1003 if (!checkForNull((Object*) arrayObj)) \ 1004 GOTO_exceptionThrown(); \ 1005 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 1006 LOGV("Invalid array access: %p %d (len=%d)\n", \ 1007 arrayObj, vsrc2, arrayObj->length); \ 1008 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \ 1009 NULL); \ 1010 GOTO_exceptionThrown(); \ 1011 } \ 1012 SET_REGISTER##_regsize(vdst, \ 1013 ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]); \ 1014 ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \ 1015 } \ 1016 FINISH(2); 1017 1018#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \ 1019 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 1020 { \ 1021 ArrayObject* arrayObj; \ 1022 u2 arrayInfo; \ 1023 EXPORT_PC(); \ 1024 vdst = INST_AA(inst); /* AA: source value */ \ 1025 arrayInfo = FETCH(1); \ 1026 vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \ 1027 vsrc2 = arrayInfo >> 8; /* CC: index */ \ 1028 ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 1029 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 1030 if (!checkForNull((Object*) arrayObj)) \ 1031 GOTO_exceptionThrown(); \ 1032 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 1033 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \ 1034 NULL); \ 1035 GOTO_exceptionThrown(); \ 1036 } \ 1037 ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\ 1038 ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] = \ 1039 GET_REGISTER##_regsize(vdst); \ 1040 } \ 1041 FINISH(2); 1042 1043/* 1044 * It's possible to get a bad value out of a field with sub-32-bit stores 1045 * because the -quick versions always operate on 32 bits. Consider: 1046 * short foo = -1 (sets a 32-bit register to 0xffffffff) 1047 * iput-quick foo (writes all 32 bits to the field) 1048 * short bar = 1 (sets a 32-bit register to 0x00000001) 1049 * iput-short (writes the low 16 bits to the field) 1050 * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001) 1051 * This can only happen when optimized and non-optimized code has interleaved 1052 * access to the same field. This is unlikely but possible. 1053 * 1054 * The easiest way to fix this is to always read/write 32 bits at a time. On 1055 * a device with a 16-bit data bus this is sub-optimal. (The alternative 1056 * approach is to have sub-int versions of iget-quick, but now we're wasting 1057 * Dalvik instruction space and making it less likely that handler code will 1058 * already be in the CPU i-cache.) 1059 */ 1060#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \ 1061 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 1062 { \ 1063 InstField* ifield; \ 1064 Object* obj; \ 1065 EXPORT_PC(); \ 1066 vdst = INST_A(inst); \ 1067 vsrc1 = INST_B(inst); /* object ptr */ \ 1068 ref = FETCH(1); /* field ref */ \ 1069 ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 1070 obj = (Object*) GET_REGISTER(vsrc1); \ 1071 if (!checkForNull(obj)) \ 1072 GOTO_exceptionThrown(); \ 1073 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 1074 if (ifield == NULL) { \ 1075 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 1076 if (ifield == NULL) \ 1077 GOTO_exceptionThrown(); \ 1078 } \ 1079 SET_REGISTER##_regsize(vdst, \ 1080 dvmGetField##_ftype(obj, ifield->byteOffset)); \ 1081 ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \ 1082 (u8) GET_REGISTER##_regsize(vdst)); \ 1083 UPDATE_FIELD_GET(&ifield->field); \ 1084 } \ 1085 FINISH(2); 1086 1087#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 1088 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 1089 { \ 1090 Object* obj; \ 1091 vdst = INST_A(inst); \ 1092 vsrc1 = INST_B(inst); /* object ptr */ \ 1093 ref = FETCH(1); /* field offset */ \ 1094 ILOGV("|iget%s-quick v%d,v%d,field@+%u", \ 1095 (_opname), vdst, vsrc1, ref); \ 1096 obj = (Object*) GET_REGISTER(vsrc1); \ 1097 if (!checkForNullExportPC(obj, fp, pc)) \ 1098 GOTO_exceptionThrown(); \ 1099 SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \ 1100 ILOGV("+ IGETQ %d=0x%08llx", ref, \ 1101 (u8) GET_REGISTER##_regsize(vdst)); \ 1102 } \ 1103 FINISH(2); 1104 1105#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \ 1106 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 1107 { \ 1108 InstField* ifield; \ 1109 Object* obj; \ 1110 EXPORT_PC(); \ 1111 vdst = INST_A(inst); \ 1112 vsrc1 = INST_B(inst); /* object ptr */ \ 1113 ref = FETCH(1); /* field ref */ \ 1114 ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 1115 obj = (Object*) GET_REGISTER(vsrc1); \ 1116 if (!checkForNull(obj)) \ 1117 GOTO_exceptionThrown(); \ 1118 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 1119 if (ifield == NULL) { \ 1120 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 1121 if (ifield == NULL) \ 1122 GOTO_exceptionThrown(); \ 1123 } \ 1124 dvmSetField##_ftype(obj, ifield->byteOffset, \ 1125 GET_REGISTER##_regsize(vdst)); \ 1126 ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \ 1127 (u8) GET_REGISTER##_regsize(vdst)); \ 1128 UPDATE_FIELD_PUT(&ifield->field); \ 1129 } \ 1130 FINISH(2); 1131 1132#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 1133 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 1134 { \ 1135 Object* obj; \ 1136 vdst = INST_A(inst); \ 1137 vsrc1 = INST_B(inst); /* object ptr */ \ 1138 ref = FETCH(1); /* field offset */ \ 1139 ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \ 1140 (_opname), vdst, vsrc1, ref); \ 1141 obj = (Object*) GET_REGISTER(vsrc1); \ 1142 if (!checkForNullExportPC(obj, fp, pc)) \ 1143 GOTO_exceptionThrown(); \ 1144 dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \ 1145 ILOGV("+ IPUTQ %d=0x%08llx", ref, \ 1146 (u8) GET_REGISTER##_regsize(vdst)); \ 1147 } \ 1148 FINISH(2); 1149 1150/* 1151 * The JIT needs dvmDexGetResolvedField() to return non-null. 1152 * Since we use the portable interpreter to build the trace, the extra 1153 * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp. 1154 */ 1155#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \ 1156 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 1157 { \ 1158 StaticField* sfield; \ 1159 vdst = INST_AA(inst); \ 1160 ref = FETCH(1); /* field ref */ \ 1161 ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 1162 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 1163 if (sfield == NULL) { \ 1164 EXPORT_PC(); \ 1165 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 1166 if (sfield == NULL) \ 1167 GOTO_exceptionThrown(); \ 1168 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 1169 ABORT_JIT_TSELECT(); \ 1170 } \ 1171 } \ 1172 SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \ 1173 ILOGV("+ SGET '%s'=0x%08llx", \ 1174 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 1175 UPDATE_FIELD_GET(&sfield->field); \ 1176 } \ 1177 FINISH(2); 1178 1179#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \ 1180 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 1181 { \ 1182 StaticField* sfield; \ 1183 vdst = INST_AA(inst); \ 1184 ref = FETCH(1); /* field ref */ \ 1185 ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 1186 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 1187 if (sfield == NULL) { \ 1188 EXPORT_PC(); \ 1189 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 1190 if (sfield == NULL) \ 1191 GOTO_exceptionThrown(); \ 1192 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 1193 ABORT_JIT_TSELECT(); \ 1194 } \ 1195 } \ 1196 dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \ 1197 ILOGV("+ SPUT '%s'=0x%08llx", \ 1198 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 1199 UPDATE_FIELD_PUT(&sfield->field); \ 1200 } \ 1201 FINISH(2); 1202 1203/* File: c/OP_IGET_WIDE_VOLATILE.c */ 1204HANDLE_IGET_X(OP_IGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE) 1205OP_END 1206 1207/* File: c/OP_IPUT_WIDE_VOLATILE.c */ 1208HANDLE_IPUT_X(OP_IPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE) 1209OP_END 1210 1211/* File: c/OP_SGET_WIDE_VOLATILE.c */ 1212HANDLE_SGET_X(OP_SGET_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE) 1213OP_END 1214 1215/* File: c/OP_SPUT_WIDE_VOLATILE.c */ 1216HANDLE_SPUT_X(OP_SPUT_WIDE_VOLATILE, "-wide-volatile", LongVolatile, _WIDE) 1217OP_END 1218 1219/* File: c/OP_BREAKPOINT.c */ 1220HANDLE_OPCODE(OP_BREAKPOINT) 1221#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER) 1222 { 1223 /* 1224 * Restart this instruction with the original opcode. We do 1225 * this by simply jumping to the handler. 1226 * 1227 * It's probably not necessary to update "inst", but we do it 1228 * for the sake of anything that needs to do disambiguation in a 1229 * common handler with INST_INST. 1230 * 1231 * The breakpoint itself is handled over in updateDebugger(), 1232 * because we need to detect other events (method entry, single 1233 * step) and report them in the same event packet, and we're not 1234 * yet handling those through breakpoint instructions. By the 1235 * time we get here, the breakpoint has already been handled and 1236 * the thread resumed. 1237 */ 1238 u1 originalOpCode = dvmGetOriginalOpCode(pc); 1239 LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)\n", originalOpCode, inst, 1240 INST_REPLACE_OP(inst, originalOpCode)); 1241 inst = INST_REPLACE_OP(inst, originalOpCode); 1242 FINISH_BKPT(originalOpCode); 1243 } 1244#else 1245 LOGE("Breakpoint hit in non-debug interpreter\n"); 1246 dvmAbort(); 1247#endif 1248OP_END 1249 1250/* File: c/OP_EXECUTE_INLINE_RANGE.c */ 1251HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) 1252 { 1253 u4 arg0, arg1, arg2, arg3; 1254 arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ 1255 1256 EXPORT_PC(); 1257 1258 vsrc1 = INST_AA(inst); /* #of args */ 1259 ref = FETCH(1); /* inline call "ref" */ 1260 vdst = FETCH(2); /* range base */ 1261 ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", 1262 vsrc1, ref, vdst, vdst+vsrc1-1); 1263 1264 assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear 1265 assert(vsrc1 <= 4); 1266 1267 switch (vsrc1) { 1268 case 4: 1269 arg3 = GET_REGISTER(vdst+3); 1270 /* fall through */ 1271 case 3: 1272 arg2 = GET_REGISTER(vdst+2); 1273 /* fall through */ 1274 case 2: 1275 arg1 = GET_REGISTER(vdst+1); 1276 /* fall through */ 1277 case 1: 1278 arg0 = GET_REGISTER(vdst+0); 1279 /* fall through */ 1280 default: // case 0 1281 ; 1282 } 1283 1284#if INTERP_TYPE == INTERP_DBG 1285 if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) 1286 GOTO_exceptionThrown(); 1287#else 1288 if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) 1289 GOTO_exceptionThrown(); 1290#endif 1291 } 1292 FINISH(3); 1293OP_END 1294 1295/* File: c/gotoTargets.c */ 1296/* 1297 * C footer. This has some common code shared by the various targets. 1298 */ 1299 1300/* 1301 * Everything from here on is a "goto target". In the basic interpreter 1302 * we jump into these targets and then jump directly to the handler for 1303 * next instruction. Here, these are subroutines that return to the caller. 1304 */ 1305 1306GOTO_TARGET(filledNewArray, bool methodCallRange) 1307 { 1308 ClassObject* arrayClass; 1309 ArrayObject* newArray; 1310 u4* contents; 1311 char typeCh; 1312 int i; 1313 u4 arg5; 1314 1315 EXPORT_PC(); 1316 1317 ref = FETCH(1); /* class ref */ 1318 vdst = FETCH(2); /* first 4 regs -or- range base */ 1319 1320 if (methodCallRange) { 1321 vsrc1 = INST_AA(inst); /* #of elements */ 1322 arg5 = -1; /* silence compiler warning */ 1323 ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}", 1324 vsrc1, ref, vdst, vdst+vsrc1-1); 1325 } else { 1326 arg5 = INST_A(inst); 1327 vsrc1 = INST_B(inst); /* #of elements */ 1328 ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}", 1329 vsrc1, ref, vdst, arg5); 1330 } 1331 1332 /* 1333 * Resolve the array class. 1334 */ 1335 arrayClass = dvmDexGetResolvedClass(methodClassDex, ref); 1336 if (arrayClass == NULL) { 1337 arrayClass = dvmResolveClass(curMethod->clazz, ref, false); 1338 if (arrayClass == NULL) 1339 GOTO_exceptionThrown(); 1340 } 1341 /* 1342 if (!dvmIsArrayClass(arrayClass)) { 1343 dvmThrowException("Ljava/lang/RuntimeError;", 1344 "filled-new-array needs array class"); 1345 GOTO_exceptionThrown(); 1346 } 1347 */ 1348 /* verifier guarantees this is an array class */ 1349 assert(dvmIsArrayClass(arrayClass)); 1350 assert(dvmIsClassInitialized(arrayClass)); 1351 1352 /* 1353 * Create an array of the specified type. 1354 */ 1355 LOGVV("+++ filled-new-array type is '%s'\n", arrayClass->descriptor); 1356 typeCh = arrayClass->descriptor[1]; 1357 if (typeCh == 'D' || typeCh == 'J') { 1358 /* category 2 primitives not allowed */ 1359 dvmThrowException("Ljava/lang/RuntimeError;", 1360 "bad filled array req"); 1361 GOTO_exceptionThrown(); 1362 } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') { 1363 /* TODO: requires multiple "fill in" loops with different widths */ 1364 LOGE("non-int primitives not implemented\n"); 1365 dvmThrowException("Ljava/lang/InternalError;", 1366 "filled-new-array not implemented for anything but 'int'"); 1367 GOTO_exceptionThrown(); 1368 } 1369 1370 newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK); 1371 if (newArray == NULL) 1372 GOTO_exceptionThrown(); 1373 1374 /* 1375 * Fill in the elements. It's legal for vsrc1 to be zero. 1376 */ 1377 contents = (u4*) newArray->contents; 1378 if (methodCallRange) { 1379 for (i = 0; i < vsrc1; i++) 1380 contents[i] = GET_REGISTER(vdst+i); 1381 } else { 1382 assert(vsrc1 <= 5); 1383 if (vsrc1 == 5) { 1384 contents[4] = GET_REGISTER(arg5); 1385 vsrc1--; 1386 } 1387 for (i = 0; i < vsrc1; i++) { 1388 contents[i] = GET_REGISTER(vdst & 0x0f); 1389 vdst >>= 4; 1390 } 1391 } 1392 1393 retval.l = newArray; 1394 } 1395 FINISH(3); 1396GOTO_TARGET_END 1397 1398 1399GOTO_TARGET(invokeVirtual, bool methodCallRange) 1400 { 1401 Method* baseMethod; 1402 Object* thisPtr; 1403 1404 EXPORT_PC(); 1405 1406 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1407 ref = FETCH(1); /* method ref */ 1408 vdst = FETCH(2); /* 4 regs -or- first reg */ 1409 1410 /* 1411 * The object against which we are executing a method is always 1412 * in the first argument. 1413 */ 1414 if (methodCallRange) { 1415 assert(vsrc1 > 0); 1416 ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}", 1417 vsrc1, ref, vdst, vdst+vsrc1-1); 1418 thisPtr = (Object*) GET_REGISTER(vdst); 1419 } else { 1420 assert((vsrc1>>4) > 0); 1421 ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}", 1422 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1423 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 1424 } 1425 1426 if (!checkForNull(thisPtr)) 1427 GOTO_exceptionThrown(); 1428 1429 /* 1430 * Resolve the method. This is the correct method for the static 1431 * type of the object. We also verify access permissions here. 1432 */ 1433 baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref); 1434 if (baseMethod == NULL) { 1435 baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL); 1436 if (baseMethod == NULL) { 1437 ILOGV("+ unknown method or access denied\n"); 1438 GOTO_exceptionThrown(); 1439 } 1440 } 1441 1442 /* 1443 * Combine the object we found with the vtable offset in the 1444 * method. 1445 */ 1446 assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount); 1447 methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex]; 1448 1449#if 0 1450 if (dvmIsAbstractMethod(methodToCall)) { 1451 /* 1452 * This can happen if you create two classes, Base and Sub, where 1453 * Sub is a sub-class of Base. Declare a protected abstract 1454 * method foo() in Base, and invoke foo() from a method in Base. 1455 * Base is an "abstract base class" and is never instantiated 1456 * directly. Now, Override foo() in Sub, and use Sub. This 1457 * Works fine unless Sub stops providing an implementation of 1458 * the method. 1459 */ 1460 dvmThrowException("Ljava/lang/AbstractMethodError;", 1461 "abstract method not implemented"); 1462 GOTO_exceptionThrown(); 1463 } 1464#else 1465 assert(!dvmIsAbstractMethod(methodToCall) || 1466 methodToCall->nativeFunc != NULL); 1467#endif 1468 1469 LOGVV("+++ base=%s.%s virtual[%d]=%s.%s\n", 1470 baseMethod->clazz->descriptor, baseMethod->name, 1471 (u4) baseMethod->methodIndex, 1472 methodToCall->clazz->descriptor, methodToCall->name); 1473 assert(methodToCall != NULL); 1474 1475#if 0 1476 if (vsrc1 != methodToCall->insSize) { 1477 LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s\n", 1478 baseMethod->clazz->descriptor, baseMethod->name, 1479 (u4) baseMethod->methodIndex, 1480 methodToCall->clazz->descriptor, methodToCall->name); 1481 //dvmDumpClass(baseMethod->clazz); 1482 //dvmDumpClass(methodToCall->clazz); 1483 dvmDumpAllClasses(0); 1484 } 1485#endif 1486 1487 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1488 } 1489GOTO_TARGET_END 1490 1491GOTO_TARGET(invokeSuper, bool methodCallRange) 1492 { 1493 Method* baseMethod; 1494 u2 thisReg; 1495 1496 EXPORT_PC(); 1497 1498 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1499 ref = FETCH(1); /* method ref */ 1500 vdst = FETCH(2); /* 4 regs -or- first reg */ 1501 1502 if (methodCallRange) { 1503 ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}", 1504 vsrc1, ref, vdst, vdst+vsrc1-1); 1505 thisReg = vdst; 1506 } else { 1507 ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}", 1508 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1509 thisReg = vdst & 0x0f; 1510 } 1511 /* impossible in well-formed code, but we must check nevertheless */ 1512 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 1513 GOTO_exceptionThrown(); 1514 1515 /* 1516 * Resolve the method. This is the correct method for the static 1517 * type of the object. We also verify access permissions here. 1518 * The first arg to dvmResolveMethod() is just the referring class 1519 * (used for class loaders and such), so we don't want to pass 1520 * the superclass into the resolution call. 1521 */ 1522 baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref); 1523 if (baseMethod == NULL) { 1524 baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL); 1525 if (baseMethod == NULL) { 1526 ILOGV("+ unknown method or access denied\n"); 1527 GOTO_exceptionThrown(); 1528 } 1529 } 1530 1531 /* 1532 * Combine the object we found with the vtable offset in the 1533 * method's class. 1534 * 1535 * We're using the current method's class' superclass, not the 1536 * superclass of "this". This is because we might be executing 1537 * in a method inherited from a superclass, and we want to run 1538 * in that class' superclass. 1539 */ 1540 if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) { 1541 /* 1542 * Method does not exist in the superclass. Could happen if 1543 * superclass gets updated. 1544 */ 1545 dvmThrowException("Ljava/lang/NoSuchMethodError;", 1546 baseMethod->name); 1547 GOTO_exceptionThrown(); 1548 } 1549 methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex]; 1550#if 0 1551 if (dvmIsAbstractMethod(methodToCall)) { 1552 dvmThrowException("Ljava/lang/AbstractMethodError;", 1553 "abstract method not implemented"); 1554 GOTO_exceptionThrown(); 1555 } 1556#else 1557 assert(!dvmIsAbstractMethod(methodToCall) || 1558 methodToCall->nativeFunc != NULL); 1559#endif 1560 LOGVV("+++ base=%s.%s super-virtual=%s.%s\n", 1561 baseMethod->clazz->descriptor, baseMethod->name, 1562 methodToCall->clazz->descriptor, methodToCall->name); 1563 assert(methodToCall != NULL); 1564 1565 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1566 } 1567GOTO_TARGET_END 1568 1569GOTO_TARGET(invokeInterface, bool methodCallRange) 1570 { 1571 Object* thisPtr; 1572 ClassObject* thisClass; 1573 1574 EXPORT_PC(); 1575 1576 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1577 ref = FETCH(1); /* method ref */ 1578 vdst = FETCH(2); /* 4 regs -or- first reg */ 1579 1580 /* 1581 * The object against which we are executing a method is always 1582 * in the first argument. 1583 */ 1584 if (methodCallRange) { 1585 assert(vsrc1 > 0); 1586 ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}", 1587 vsrc1, ref, vdst, vdst+vsrc1-1); 1588 thisPtr = (Object*) GET_REGISTER(vdst); 1589 } else { 1590 assert((vsrc1>>4) > 0); 1591 ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}", 1592 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1593 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 1594 } 1595 if (!checkForNull(thisPtr)) 1596 GOTO_exceptionThrown(); 1597 1598 thisClass = thisPtr->clazz; 1599 1600 /* 1601 * Given a class and a method index, find the Method* with the 1602 * actual code we want to execute. 1603 */ 1604 methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod, 1605 methodClassDex); 1606 if (methodToCall == NULL) { 1607 assert(dvmCheckException(self)); 1608 GOTO_exceptionThrown(); 1609 } 1610 1611 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1612 } 1613GOTO_TARGET_END 1614 1615GOTO_TARGET(invokeDirect, bool methodCallRange) 1616 { 1617 u2 thisReg; 1618 1619 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1620 ref = FETCH(1); /* method ref */ 1621 vdst = FETCH(2); /* 4 regs -or- first reg */ 1622 1623 EXPORT_PC(); 1624 1625 if (methodCallRange) { 1626 ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}", 1627 vsrc1, ref, vdst, vdst+vsrc1-1); 1628 thisReg = vdst; 1629 } else { 1630 ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}", 1631 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1632 thisReg = vdst & 0x0f; 1633 } 1634 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 1635 GOTO_exceptionThrown(); 1636 1637 methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref); 1638 if (methodToCall == NULL) { 1639 methodToCall = dvmResolveMethod(curMethod->clazz, ref, 1640 METHOD_DIRECT); 1641 if (methodToCall == NULL) { 1642 ILOGV("+ unknown direct method\n"); // should be impossible 1643 GOTO_exceptionThrown(); 1644 } 1645 } 1646 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1647 } 1648GOTO_TARGET_END 1649 1650GOTO_TARGET(invokeStatic, bool methodCallRange) 1651 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1652 ref = FETCH(1); /* method ref */ 1653 vdst = FETCH(2); /* 4 regs -or- first reg */ 1654 1655 EXPORT_PC(); 1656 1657 if (methodCallRange) 1658 ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}", 1659 vsrc1, ref, vdst, vdst+vsrc1-1); 1660 else 1661 ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}", 1662 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1663 1664 methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref); 1665 if (methodToCall == NULL) { 1666 methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC); 1667 if (methodToCall == NULL) { 1668 ILOGV("+ unknown method\n"); 1669 GOTO_exceptionThrown(); 1670 } 1671 1672 /* 1673 * The JIT needs dvmDexGetResolvedMethod() to return non-null. 1674 * Since we use the portable interpreter to build the trace, this extra 1675 * check is not needed for mterp. 1676 */ 1677 if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) { 1678 /* Class initialization is still ongoing */ 1679 ABORT_JIT_TSELECT(); 1680 } 1681 } 1682 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1683GOTO_TARGET_END 1684 1685GOTO_TARGET(invokeVirtualQuick, bool methodCallRange) 1686 { 1687 Object* thisPtr; 1688 1689 EXPORT_PC(); 1690 1691 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1692 ref = FETCH(1); /* vtable index */ 1693 vdst = FETCH(2); /* 4 regs -or- first reg */ 1694 1695 /* 1696 * The object against which we are executing a method is always 1697 * in the first argument. 1698 */ 1699 if (methodCallRange) { 1700 assert(vsrc1 > 0); 1701 ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}", 1702 vsrc1, ref, vdst, vdst+vsrc1-1); 1703 thisPtr = (Object*) GET_REGISTER(vdst); 1704 } else { 1705 assert((vsrc1>>4) > 0); 1706 ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}", 1707 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1708 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 1709 } 1710 1711 if (!checkForNull(thisPtr)) 1712 GOTO_exceptionThrown(); 1713 1714 /* 1715 * Combine the object we found with the vtable offset in the 1716 * method. 1717 */ 1718 assert(ref < thisPtr->clazz->vtableCount); 1719 methodToCall = thisPtr->clazz->vtable[ref]; 1720 1721#if 0 1722 if (dvmIsAbstractMethod(methodToCall)) { 1723 dvmThrowException("Ljava/lang/AbstractMethodError;", 1724 "abstract method not implemented"); 1725 GOTO_exceptionThrown(); 1726 } 1727#else 1728 assert(!dvmIsAbstractMethod(methodToCall) || 1729 methodToCall->nativeFunc != NULL); 1730#endif 1731 1732 LOGVV("+++ virtual[%d]=%s.%s\n", 1733 ref, methodToCall->clazz->descriptor, methodToCall->name); 1734 assert(methodToCall != NULL); 1735 1736 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1737 } 1738GOTO_TARGET_END 1739 1740GOTO_TARGET(invokeSuperQuick, bool methodCallRange) 1741 { 1742 u2 thisReg; 1743 1744 EXPORT_PC(); 1745 1746 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 1747 ref = FETCH(1); /* vtable index */ 1748 vdst = FETCH(2); /* 4 regs -or- first reg */ 1749 1750 if (methodCallRange) { 1751 ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}", 1752 vsrc1, ref, vdst, vdst+vsrc1-1); 1753 thisReg = vdst; 1754 } else { 1755 ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}", 1756 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 1757 thisReg = vdst & 0x0f; 1758 } 1759 /* impossible in well-formed code, but we must check nevertheless */ 1760 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 1761 GOTO_exceptionThrown(); 1762 1763#if 0 /* impossible in optimized + verified code */ 1764 if (ref >= curMethod->clazz->super->vtableCount) { 1765 dvmThrowException("Ljava/lang/NoSuchMethodError;", NULL); 1766 GOTO_exceptionThrown(); 1767 } 1768#else 1769 assert(ref < curMethod->clazz->super->vtableCount); 1770#endif 1771 1772 /* 1773 * Combine the object we found with the vtable offset in the 1774 * method's class. 1775 * 1776 * We're using the current method's class' superclass, not the 1777 * superclass of "this". This is because we might be executing 1778 * in a method inherited from a superclass, and we want to run 1779 * in the method's class' superclass. 1780 */ 1781 methodToCall = curMethod->clazz->super->vtable[ref]; 1782 1783#if 0 1784 if (dvmIsAbstractMethod(methodToCall)) { 1785 dvmThrowException("Ljava/lang/AbstractMethodError;", 1786 "abstract method not implemented"); 1787 GOTO_exceptionThrown(); 1788 } 1789#else 1790 assert(!dvmIsAbstractMethod(methodToCall) || 1791 methodToCall->nativeFunc != NULL); 1792#endif 1793 LOGVV("+++ super-virtual[%d]=%s.%s\n", 1794 ref, methodToCall->clazz->descriptor, methodToCall->name); 1795 assert(methodToCall != NULL); 1796 1797 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 1798 } 1799GOTO_TARGET_END 1800 1801 1802 1803 /* 1804 * General handling for return-void, return, and return-wide. Put the 1805 * return value in "retval" before jumping here. 1806 */ 1807GOTO_TARGET(returnFromMethod) 1808 { 1809 StackSaveArea* saveArea; 1810 1811 /* 1812 * We must do this BEFORE we pop the previous stack frame off, so 1813 * that the GC can see the return value (if any) in the local vars. 1814 * 1815 * Since this is now an interpreter switch point, we must do it before 1816 * we do anything at all. 1817 */ 1818 PERIODIC_CHECKS(kInterpEntryReturn, 0); 1819 1820 ILOGV("> retval=0x%llx (leaving %s.%s %s)", 1821 retval.j, curMethod->clazz->descriptor, curMethod->name, 1822 curMethod->shorty); 1823 //DUMP_REGS(curMethod, fp); 1824 1825 saveArea = SAVEAREA_FROM_FP(fp); 1826 1827#ifdef EASY_GDB 1828 debugSaveArea = saveArea; 1829#endif 1830#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER) 1831 TRACE_METHOD_EXIT(self, curMethod); 1832#endif 1833 1834 /* back up to previous frame and see if we hit a break */ 1835 fp = saveArea->prevFrame; 1836 assert(fp != NULL); 1837 if (dvmIsBreakFrame(fp)) { 1838 /* bail without popping the method frame from stack */ 1839 LOGVV("+++ returned into break frame\n"); 1840#if defined(WITH_JIT) 1841 /* Let the Jit know the return is terminating normally */ 1842 CHECK_JIT(); 1843#endif 1844 GOTO_bail(); 1845 } 1846 1847 /* update thread FP, and reset local variables */ 1848 self->curFrame = fp; 1849 curMethod = SAVEAREA_FROM_FP(fp)->method; 1850 //methodClass = curMethod->clazz; 1851 methodClassDex = curMethod->clazz->pDvmDex; 1852 pc = saveArea->savedPc; 1853 ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor, 1854 curMethod->name, curMethod->shorty); 1855 1856 /* use FINISH on the caller's invoke instruction */ 1857 //u2 invokeInstr = INST_INST(FETCH(0)); 1858 if (true /*invokeInstr >= OP_INVOKE_VIRTUAL && 1859 invokeInstr <= OP_INVOKE_INTERFACE*/) 1860 { 1861 FINISH(3); 1862 } else { 1863 //LOGE("Unknown invoke instr %02x at %d\n", 1864 // invokeInstr, (int) (pc - curMethod->insns)); 1865 assert(false); 1866 } 1867 } 1868GOTO_TARGET_END 1869 1870 1871 /* 1872 * Jump here when the code throws an exception. 1873 * 1874 * By the time we get here, the Throwable has been created and the stack 1875 * trace has been saved off. 1876 */ 1877GOTO_TARGET(exceptionThrown) 1878 { 1879 Object* exception; 1880 int catchRelPc; 1881 1882 /* 1883 * Since this is now an interpreter switch point, we must do it before 1884 * we do anything at all. 1885 */ 1886 PERIODIC_CHECKS(kInterpEntryThrow, 0); 1887 1888#if defined(WITH_JIT) 1889 // Something threw during trace selection - abort the current trace 1890 ABORT_JIT_TSELECT(); 1891#endif 1892 /* 1893 * We save off the exception and clear the exception status. While 1894 * processing the exception we might need to load some Throwable 1895 * classes, and we don't want class loader exceptions to get 1896 * confused with this one. 1897 */ 1898 assert(dvmCheckException(self)); 1899 exception = dvmGetException(self); 1900 dvmAddTrackedAlloc(exception, self); 1901 dvmClearException(self); 1902 1903 LOGV("Handling exception %s at %s:%d\n", 1904 exception->clazz->descriptor, curMethod->name, 1905 dvmLineNumFromPC(curMethod, pc - curMethod->insns)); 1906 1907#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER) 1908 /* 1909 * Tell the debugger about it. 1910 * 1911 * TODO: if the exception was thrown by interpreted code, control 1912 * fell through native, and then back to us, we will report the 1913 * exception at the point of the throw and again here. We can avoid 1914 * this by not reporting exceptions when we jump here directly from 1915 * the native call code above, but then we won't report exceptions 1916 * that were thrown *from* the JNI code (as opposed to *through* it). 1917 * 1918 * The correct solution is probably to ignore from-native exceptions 1919 * here, and have the JNI exception code do the reporting to the 1920 * debugger. 1921 */ 1922 if (gDvm.debuggerActive) { 1923 void* catchFrame; 1924 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, 1925 exception, true, &catchFrame); 1926 dvmDbgPostException(fp, pc - curMethod->insns, catchFrame, 1927 catchRelPc, exception); 1928 } 1929#endif 1930 1931 /* 1932 * We need to unroll to the catch block or the nearest "break" 1933 * frame. 1934 * 1935 * A break frame could indicate that we have reached an intermediate 1936 * native call, or have gone off the top of the stack and the thread 1937 * needs to exit. Either way, we return from here, leaving the 1938 * exception raised. 1939 * 1940 * If we do find a catch block, we want to transfer execution to 1941 * that point. 1942 * 1943 * Note this can cause an exception while resolving classes in 1944 * the "catch" blocks. 1945 */ 1946 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, 1947 exception, false, (void*)&fp); 1948 1949 /* 1950 * Restore the stack bounds after an overflow. This isn't going to 1951 * be correct in all circumstances, e.g. if JNI code devours the 1952 * exception this won't happen until some other exception gets 1953 * thrown. If the code keeps pushing the stack bounds we'll end 1954 * up aborting the VM. 1955 * 1956 * Note we want to do this *after* the call to dvmFindCatchBlock, 1957 * because that may need extra stack space to resolve exception 1958 * classes (e.g. through a class loader). 1959 * 1960 * It's possible for the stack overflow handling to cause an 1961 * exception (specifically, class resolution in a "catch" block 1962 * during the call above), so we could see the thread's overflow 1963 * flag raised but actually be running in a "nested" interpreter 1964 * frame. We don't allow doubled-up StackOverflowErrors, so 1965 * we can check for this by just looking at the exception type 1966 * in the cleanup function. Also, we won't unroll past the SOE 1967 * point because the more-recent exception will hit a break frame 1968 * as it unrolls to here. 1969 */ 1970 if (self->stackOverflowed) 1971 dvmCleanupStackOverflow(self, exception); 1972 1973 if (catchRelPc < 0) { 1974 /* falling through to JNI code or off the bottom of the stack */ 1975#if DVM_SHOW_EXCEPTION >= 2 1976 LOGD("Exception %s from %s:%d not caught locally\n", 1977 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod), 1978 dvmLineNumFromPC(curMethod, pc - curMethod->insns)); 1979#endif 1980 dvmSetException(self, exception); 1981 dvmReleaseTrackedAlloc(exception, self); 1982 GOTO_bail(); 1983 } 1984 1985#if DVM_SHOW_EXCEPTION >= 3 1986 { 1987 const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method; 1988 LOGD("Exception %s thrown from %s:%d to %s:%d\n", 1989 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod), 1990 dvmLineNumFromPC(curMethod, pc - curMethod->insns), 1991 dvmGetMethodSourceFile(catchMethod), 1992 dvmLineNumFromPC(catchMethod, catchRelPc)); 1993 } 1994#endif 1995 1996 /* 1997 * Adjust local variables to match self->curFrame and the 1998 * updated PC. 1999 */ 2000 //fp = (u4*) self->curFrame; 2001 curMethod = SAVEAREA_FROM_FP(fp)->method; 2002 //methodClass = curMethod->clazz; 2003 methodClassDex = curMethod->clazz->pDvmDex; 2004 pc = curMethod->insns + catchRelPc; 2005 ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor, 2006 curMethod->name, curMethod->shorty); 2007 DUMP_REGS(curMethod, fp, false); // show all regs 2008 2009 /* 2010 * Restore the exception if the handler wants it. 2011 * 2012 * The Dalvik spec mandates that, if an exception handler wants to 2013 * do something with the exception, the first instruction executed 2014 * must be "move-exception". We can pass the exception along 2015 * through the thread struct, and let the move-exception instruction 2016 * clear it for us. 2017 * 2018 * If the handler doesn't call move-exception, we don't want to 2019 * finish here with an exception still pending. 2020 */ 2021 if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION) 2022 dvmSetException(self, exception); 2023 2024 dvmReleaseTrackedAlloc(exception, self); 2025 FINISH(0); 2026 } 2027GOTO_TARGET_END 2028 2029 2030 /* 2031 * General handling for invoke-{virtual,super,direct,static,interface}, 2032 * including "quick" variants. 2033 * 2034 * Set "methodToCall" to the Method we're calling, and "methodCallRange" 2035 * depending on whether this is a "/range" instruction. 2036 * 2037 * For a range call: 2038 * "vsrc1" holds the argument count (8 bits) 2039 * "vdst" holds the first argument in the range 2040 * For a non-range call: 2041 * "vsrc1" holds the argument count (4 bits) and the 5th argument index 2042 * "vdst" holds four 4-bit register indices 2043 * 2044 * The caller must EXPORT_PC before jumping here, because any method 2045 * call can throw a stack overflow exception. 2046 */ 2047GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, 2048 u2 count, u2 regs) 2049 { 2050 STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;); 2051 2052 //printf("range=%d call=%p count=%d regs=0x%04x\n", 2053 // methodCallRange, methodToCall, count, regs); 2054 //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor, 2055 // methodToCall->name, methodToCall->shorty); 2056 2057 u4* outs; 2058 int i; 2059 2060 /* 2061 * Copy args. This may corrupt vsrc1/vdst. 2062 */ 2063 if (methodCallRange) { 2064 // could use memcpy or a "Duff's device"; most functions have 2065 // so few args it won't matter much 2066 assert(vsrc1 <= curMethod->outsSize); 2067 assert(vsrc1 == methodToCall->insSize); 2068 outs = OUTS_FROM_FP(fp, vsrc1); 2069 for (i = 0; i < vsrc1; i++) 2070 outs[i] = GET_REGISTER(vdst+i); 2071 } else { 2072 u4 count = vsrc1 >> 4; 2073 2074 assert(count <= curMethod->outsSize); 2075 assert(count == methodToCall->insSize); 2076 assert(count <= 5); 2077 2078 outs = OUTS_FROM_FP(fp, count); 2079#if 0 2080 if (count == 5) { 2081 outs[4] = GET_REGISTER(vsrc1 & 0x0f); 2082 count--; 2083 } 2084 for (i = 0; i < (int) count; i++) { 2085 outs[i] = GET_REGISTER(vdst & 0x0f); 2086 vdst >>= 4; 2087 } 2088#else 2089 // This version executes fewer instructions but is larger 2090 // overall. Seems to be a teensy bit faster. 2091 assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear 2092 switch (count) { 2093 case 5: 2094 outs[4] = GET_REGISTER(vsrc1 & 0x0f); 2095 case 4: 2096 outs[3] = GET_REGISTER(vdst >> 12); 2097 case 3: 2098 outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8); 2099 case 2: 2100 outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4); 2101 case 1: 2102 outs[0] = GET_REGISTER(vdst & 0x0f); 2103 default: 2104 ; 2105 } 2106#endif 2107 } 2108 } 2109 2110 /* 2111 * (This was originally a "goto" target; I've kept it separate from the 2112 * stuff above in case we want to refactor things again.) 2113 * 2114 * At this point, we have the arguments stored in the "outs" area of 2115 * the current method's stack frame, and the method to call in 2116 * "methodToCall". Push a new stack frame. 2117 */ 2118 { 2119 StackSaveArea* newSaveArea; 2120 u4* newFp; 2121 2122 ILOGV("> %s%s.%s %s", 2123 dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "", 2124 methodToCall->clazz->descriptor, methodToCall->name, 2125 methodToCall->shorty); 2126 2127 newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize; 2128 newSaveArea = SAVEAREA_FROM_FP(newFp); 2129 2130 /* verify that we have enough space */ 2131 if (true) { 2132 u1* bottom; 2133 bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4); 2134 if (bottom < self->interpStackEnd) { 2135 /* stack overflow */ 2136 LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')\n", 2137 self->interpStackStart, self->interpStackEnd, bottom, 2138 (u1*) fp - bottom, self->interpStackSize, 2139 methodToCall->name); 2140 dvmHandleStackOverflow(self, methodToCall); 2141 assert(dvmCheckException(self)); 2142 GOTO_exceptionThrown(); 2143 } 2144 //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p\n", 2145 // fp, newFp, newSaveArea, bottom); 2146 } 2147 2148#ifdef LOG_INSTR 2149 if (methodToCall->registersSize > methodToCall->insSize) { 2150 /* 2151 * This makes valgrind quiet when we print registers that 2152 * haven't been initialized. Turn it off when the debug 2153 * messages are disabled -- we want valgrind to report any 2154 * used-before-initialized issues. 2155 */ 2156 memset(newFp, 0xcc, 2157 (methodToCall->registersSize - methodToCall->insSize) * 4); 2158 } 2159#endif 2160 2161#ifdef EASY_GDB 2162 newSaveArea->prevSave = SAVEAREA_FROM_FP(fp); 2163#endif 2164 newSaveArea->prevFrame = fp; 2165 newSaveArea->savedPc = pc; 2166#if defined(WITH_JIT) 2167 newSaveArea->returnAddr = 0; 2168#endif 2169 newSaveArea->method = methodToCall; 2170 2171 if (!dvmIsNativeMethod(methodToCall)) { 2172 /* 2173 * "Call" interpreted code. Reposition the PC, update the 2174 * frame pointer and other local state, and continue. 2175 */ 2176 curMethod = methodToCall; 2177 methodClassDex = curMethod->clazz->pDvmDex; 2178 pc = methodToCall->insns; 2179 fp = self->curFrame = newFp; 2180#ifdef EASY_GDB 2181 debugSaveArea = SAVEAREA_FROM_FP(newFp); 2182#endif 2183#if INTERP_TYPE == INTERP_DBG 2184 debugIsMethodEntry = true; // profiling, debugging 2185#endif 2186 ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor, 2187 curMethod->name, curMethod->shorty); 2188 DUMP_REGS(curMethod, fp, true); // show input args 2189 FINISH(0); // jump to method start 2190 } else { 2191 /* set this up for JNI locals, even if not a JNI native */ 2192#ifdef USE_INDIRECT_REF 2193 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; 2194#else 2195 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry; 2196#endif 2197 2198 self->curFrame = newFp; 2199 2200 DUMP_REGS(methodToCall, newFp, true); // show input args 2201 2202#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER) 2203 if (gDvm.debuggerActive) { 2204 dvmDbgPostLocationEvent(methodToCall, -1, 2205 dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY); 2206 } 2207#endif 2208#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER) 2209 TRACE_METHOD_ENTER(self, methodToCall); 2210#endif 2211 2212 ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, 2213 methodToCall->name, methodToCall->shorty); 2214 2215#if defined(WITH_JIT) 2216 /* Allow the Jit to end any pending trace building */ 2217 CHECK_JIT(); 2218#endif 2219 2220 /* 2221 * Jump through native call bridge. Because we leave no 2222 * space for locals on native calls, "newFp" points directly 2223 * to the method arguments. 2224 */ 2225 (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self); 2226 2227#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER) 2228 if (gDvm.debuggerActive) { 2229 dvmDbgPostLocationEvent(methodToCall, -1, 2230 dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT); 2231 } 2232#endif 2233#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER) 2234 TRACE_METHOD_EXIT(self, methodToCall); 2235#endif 2236 2237 /* pop frame off */ 2238 dvmPopJniLocals(self, newSaveArea); 2239 self->curFrame = fp; 2240 2241 /* 2242 * If the native code threw an exception, or interpreted code 2243 * invoked by the native call threw one and nobody has cleared 2244 * it, jump to our local exception handling. 2245 */ 2246 if (dvmCheckException(self)) { 2247 LOGV("Exception thrown by/below native code\n"); 2248 GOTO_exceptionThrown(); 2249 } 2250 2251 ILOGD("> retval=0x%llx (leaving native)", retval.j); 2252 ILOGD("> (return from native %s.%s to %s.%s %s)", 2253 methodToCall->clazz->descriptor, methodToCall->name, 2254 curMethod->clazz->descriptor, curMethod->name, 2255 curMethod->shorty); 2256 2257 //u2 invokeInstr = INST_INST(FETCH(0)); 2258 if (true /*invokeInstr >= OP_INVOKE_VIRTUAL && 2259 invokeInstr <= OP_INVOKE_INTERFACE*/) 2260 { 2261 FINISH(3); 2262 } else { 2263 //LOGE("Unknown invoke instr %02x at %d\n", 2264 // invokeInstr, (int) (pc - curMethod->insns)); 2265 assert(false); 2266 } 2267 } 2268 } 2269 assert(false); // should not get here 2270GOTO_TARGET_END 2271 2272/* File: cstubs/enddefs.c */ 2273 2274/* undefine "magic" name remapping */ 2275#undef retval 2276#undef pc 2277#undef fp 2278#undef curMethod 2279#undef methodClassDex 2280#undef self 2281#undef debugTrackedRefStart 2282 2283