Interp.cpp revision cf2aac7e6a29e7e1e5f622fd6123e0d1a9a75bda
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* 18 * Main interpreter entry point and support functions. 19 * 20 * The entry point selects the "standard" or "debug" interpreter and 21 * facilitates switching between them. The standard interpreter may 22 * use the "fast" or "portable" implementation. 23 * 24 * Some debugger support functions are included here. 25 */ 26#include "Dalvik.h" 27#include "interp/InterpDefs.h" 28#if defined(WITH_JIT) 29#include "interp/Jit.h" 30#endif 31 32 33/* 34 * =========================================================================== 35 * Debugger support 36 * =========================================================================== 37 */ 38 39// fwd 40static BreakpointSet* dvmBreakpointSetAlloc(); 41static void dvmBreakpointSetFree(BreakpointSet* pSet); 42 43#if defined(WITH_JIT) 44/* Target-specific save/restore */ 45extern "C" void dvmJitCalleeSave(double *saveArea); 46extern "C" void dvmJitCalleeRestore(double *saveArea); 47/* Interpreter entry points from compiled code */ 48extern "C" void dvmJitToInterpNormal(); 49extern "C" void dvmJitToInterpNoChain(); 50extern "C" void dvmJitToInterpPunt(); 51extern "C" void dvmJitToInterpSingleStep(); 52extern "C" void dvmJitToInterpTraceSelect(); 53#if defined(WITH_SELF_VERIFICATION) 54extern "C" void dvmJitToInterpBackwardBranch(); 55#endif 56#endif 57 58/* 59 * Initialize global breakpoint structures. 60 */ 61bool dvmBreakpointStartup() 62{ 63 gDvm.breakpointSet = dvmBreakpointSetAlloc(); 64 return (gDvm.breakpointSet != NULL); 65} 66 67/* 68 * Free resources. 69 */ 70void dvmBreakpointShutdown() 71{ 72 dvmBreakpointSetFree(gDvm.breakpointSet); 73} 74 75 76/* 77 * This represents a breakpoint inserted in the instruction stream. 78 * 79 * The debugger may ask us to create the same breakpoint multiple times. 80 * We only remove the breakpoint when the last instance is cleared. 81 */ 82typedef struct { 83 Method* method; /* method we're associated with */ 84 u2* addr; /* absolute memory address */ 85 u1 originalOpcode; /* original 8-bit opcode value */ 86 int setCount; /* #of times this breakpoint was set */ 87} Breakpoint; 88 89/* 90 * Set of breakpoints. 91 */ 92struct BreakpointSet { 93 /* grab lock before reading or writing anything else in here */ 94 pthread_mutex_t lock; 95 96 /* vector of breakpoint structures */ 97 int alloc; 98 int count; 99 Breakpoint* breakpoints; 100}; 101 102/* 103 * Initialize a BreakpointSet. Initially empty. 104 */ 105static BreakpointSet* dvmBreakpointSetAlloc() 106{ 107 BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet)); 108 109 dvmInitMutex(&pSet->lock); 110 /* leave the rest zeroed -- will alloc on first use */ 111 112 return pSet; 113} 114 115/* 116 * Free storage associated with a BreakpointSet. 117 */ 118static void dvmBreakpointSetFree(BreakpointSet* pSet) 119{ 120 if (pSet == NULL) 121 return; 122 123 free(pSet->breakpoints); 124 free(pSet); 125} 126 127/* 128 * Lock the breakpoint set. 129 * 130 * It's not currently necessary to switch to VMWAIT in the event of 131 * contention, because nothing in here can block. However, it's possible 132 * that the bytecode-updater code could become fancier in the future, so 133 * we do the trylock dance as a bit of future-proofing. 134 */ 135static void dvmBreakpointSetLock(BreakpointSet* pSet) 136{ 137 if (dvmTryLockMutex(&pSet->lock) != 0) { 138 Thread* self = dvmThreadSelf(); 139 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); 140 dvmLockMutex(&pSet->lock); 141 dvmChangeStatus(self, oldStatus); 142 } 143} 144 145/* 146 * Unlock the breakpoint set. 147 */ 148static void dvmBreakpointSetUnlock(BreakpointSet* pSet) 149{ 150 dvmUnlockMutex(&pSet->lock); 151} 152 153/* 154 * Return the #of breakpoints. 155 */ 156static int dvmBreakpointSetCount(const BreakpointSet* pSet) 157{ 158 return pSet->count; 159} 160 161/* 162 * See if we already have an entry for this address. 163 * 164 * The BreakpointSet's lock must be acquired before calling here. 165 * 166 * Returns the index of the breakpoint entry, or -1 if not found. 167 */ 168static int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr) 169{ 170 int i; 171 172 for (i = 0; i < pSet->count; i++) { 173 Breakpoint* pBreak = &pSet->breakpoints[i]; 174 if (pBreak->addr == addr) 175 return i; 176 } 177 178 return -1; 179} 180 181/* 182 * Retrieve the opcode that was originally at the specified location. 183 * 184 * The BreakpointSet's lock must be acquired before calling here. 185 * 186 * Returns "true" with the opcode in *pOrig on success. 187 */ 188static bool dvmBreakpointSetOriginalOpcode(const BreakpointSet* pSet, 189 const u2* addr, u1* pOrig) 190{ 191 int idx = dvmBreakpointSetFind(pSet, addr); 192 if (idx < 0) 193 return false; 194 195 *pOrig = pSet->breakpoints[idx].originalOpcode; 196 return true; 197} 198 199/* 200 * Check the opcode. If it's a "magic" NOP, indicating the start of 201 * switch or array data in the instruction stream, we don't want to set 202 * a breakpoint. 203 * 204 * This can happen because the line number information dx generates 205 * associates the switch data with the switch statement's line number, 206 * and some debuggers put breakpoints at every address associated with 207 * a given line. The result is that the breakpoint stomps on the NOP 208 * instruction that doubles as a data table magic number, and an explicit 209 * check in the interpreter results in an exception being thrown. 210 * 211 * We don't want to simply refuse to add the breakpoint to the table, 212 * because that confuses the housekeeping. We don't want to reject the 213 * debugger's event request, and we want to be sure that there's exactly 214 * one un-set operation for every set op. 215 */ 216static bool instructionIsMagicNop(const u2* addr) 217{ 218 u2 curVal = *addr; 219 return ((GET_OPCODE(curVal)) == OP_NOP && (curVal >> 8) != 0); 220} 221 222/* 223 * Add a breakpoint at a specific address. If the address is already 224 * present in the table, this just increments the count. 225 * 226 * For a new entry, this will extract and preserve the current opcode from 227 * the instruction stream, and replace it with a breakpoint opcode. 228 * 229 * The BreakpointSet's lock must be acquired before calling here. 230 * 231 * Returns "true" on success. 232 */ 233static bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method, 234 unsigned int instrOffset) 235{ 236 const int kBreakpointGrowth = 10; 237 const u2* addr = method->insns + instrOffset; 238 int idx = dvmBreakpointSetFind(pSet, addr); 239 Breakpoint* pBreak; 240 241 if (idx < 0) { 242 if (pSet->count == pSet->alloc) { 243 int newSize = pSet->alloc + kBreakpointGrowth; 244 Breakpoint* newVec; 245 246 LOGV("+++ increasing breakpoint set size to %d\n", newSize); 247 248 /* pSet->breakpoints will be NULL on first entry */ 249 newVec = (Breakpoint*)realloc(pSet->breakpoints, newSize * sizeof(Breakpoint)); 250 if (newVec == NULL) 251 return false; 252 253 pSet->breakpoints = newVec; 254 pSet->alloc = newSize; 255 } 256 257 pBreak = &pSet->breakpoints[pSet->count++]; 258 pBreak->method = method; 259 pBreak->addr = (u2*)addr; 260 pBreak->originalOpcode = *(u1*)addr; 261 pBreak->setCount = 1; 262 263 /* 264 * Change the opcode. We must ensure that the BreakpointSet 265 * updates happen before we change the opcode. 266 * 267 * If the method has not been verified, we do NOT insert the 268 * breakpoint yet, since that will screw up the verifier. The 269 * debugger is allowed to insert breakpoints in unverified code, 270 * but since we don't execute unverified code we don't need to 271 * alter the bytecode yet. 272 * 273 * The class init code will "flush" all pending opcode writes 274 * before verification completes. 275 */ 276 assert(*(u1*)addr != OP_BREAKPOINT); 277 if (dvmIsClassVerified(method->clazz)) { 278 LOGV("Class %s verified, adding breakpoint at %p\n", 279 method->clazz->descriptor, addr); 280 if (instructionIsMagicNop(addr)) { 281 LOGV("Refusing to set breakpoint on %04x at %s.%s + 0x%x\n", 282 *addr, method->clazz->descriptor, method->name, 283 instrOffset); 284 } else { 285 ANDROID_MEMBAR_FULL(); 286 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 287 OP_BREAKPOINT); 288 } 289 } else { 290 LOGV("Class %s NOT verified, deferring breakpoint at %p\n", 291 method->clazz->descriptor, addr); 292 } 293 } else { 294 /* 295 * Breakpoint already exists, just increase the count. 296 */ 297 pBreak = &pSet->breakpoints[idx]; 298 pBreak->setCount++; 299 } 300 301 return true; 302} 303 304/* 305 * Remove one instance of the specified breakpoint. When the count 306 * reaches zero, the entry is removed from the table, and the original 307 * opcode is restored. 308 * 309 * The BreakpointSet's lock must be acquired before calling here. 310 */ 311static void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method, 312 unsigned int instrOffset) 313{ 314 const u2* addr = method->insns + instrOffset; 315 int idx = dvmBreakpointSetFind(pSet, addr); 316 317 if (idx < 0) { 318 /* breakpoint not found in set -- unexpected */ 319 if (*(u1*)addr == OP_BREAKPOINT) { 320 LOGE("Unable to restore breakpoint opcode (%s.%s +0x%x)\n", 321 method->clazz->descriptor, method->name, instrOffset); 322 dvmAbort(); 323 } else { 324 LOGW("Breakpoint was already restored? (%s.%s +0x%x)\n", 325 method->clazz->descriptor, method->name, instrOffset); 326 } 327 } else { 328 Breakpoint* pBreak = &pSet->breakpoints[idx]; 329 if (pBreak->setCount == 1) { 330 /* 331 * Must restore opcode before removing set entry. 332 * 333 * If the breakpoint was never flushed, we could be ovewriting 334 * a value with the same value. Not a problem, though we 335 * could end up causing a copy-on-write here when we didn't 336 * need to. (Not worth worrying about.) 337 */ 338 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 339 pBreak->originalOpcode); 340 ANDROID_MEMBAR_FULL(); 341 342 if (idx != pSet->count-1) { 343 /* shift down */ 344 memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1], 345 (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0])); 346 } 347 pSet->count--; 348 pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug 349 } else { 350 pBreak->setCount--; 351 assert(pBreak->setCount > 0); 352 } 353 } 354} 355 356/* 357 * Flush any breakpoints associated with methods in "clazz". We want to 358 * change the opcode, which might not have happened when the breakpoint 359 * was initially set because the class was in the process of being 360 * verified. 361 * 362 * The BreakpointSet's lock must be acquired before calling here. 363 */ 364static void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz) 365{ 366 int i; 367 for (i = 0; i < pSet->count; i++) { 368 Breakpoint* pBreak = &pSet->breakpoints[i]; 369 if (pBreak->method->clazz == clazz) { 370 /* 371 * The breakpoint is associated with a method in this class. 372 * It might already be there or it might not; either way, 373 * flush it out. 374 */ 375 LOGV("Flushing breakpoint at %p for %s\n", 376 pBreak->addr, clazz->descriptor); 377 if (instructionIsMagicNop(pBreak->addr)) { 378 LOGV("Refusing to flush breakpoint on %04x at %s.%s + 0x%x\n", 379 *pBreak->addr, pBreak->method->clazz->descriptor, 380 pBreak->method->name, pBreak->addr - pBreak->method->insns); 381 } else { 382 dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr, 383 OP_BREAKPOINT); 384 } 385 } 386 } 387} 388 389 390/* 391 * Do any debugger-attach-time initialization. 392 */ 393void dvmInitBreakpoints() 394{ 395 /* quick sanity check */ 396 BreakpointSet* pSet = gDvm.breakpointSet; 397 dvmBreakpointSetLock(pSet); 398 if (dvmBreakpointSetCount(pSet) != 0) { 399 LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet)); 400 /* generally not good, but we can keep going */ 401 } 402 dvmBreakpointSetUnlock(pSet); 403} 404 405/* 406 * Add an address to the list, putting it in the first non-empty slot. 407 * 408 * Sometimes the debugger likes to add two entries for one breakpoint. 409 * We add two entries here, so that we get the right behavior when it's 410 * removed twice. 411 * 412 * This will only be run from the JDWP thread, and it will happen while 413 * we are updating the event list, which is synchronized. We're guaranteed 414 * to be the only one adding entries, and the lock ensures that nobody 415 * will be trying to remove them while we're in here. 416 * 417 * "addr" is the absolute address of the breakpoint bytecode. 418 */ 419void dvmAddBreakAddr(Method* method, unsigned int instrOffset) 420{ 421 BreakpointSet* pSet = gDvm.breakpointSet; 422 dvmBreakpointSetLock(pSet); 423 dvmBreakpointSetAdd(pSet, method, instrOffset); 424 dvmBreakpointSetUnlock(pSet); 425} 426 427/* 428 * Remove an address from the list by setting the entry to NULL. 429 * 430 * This can be called from the JDWP thread (because the debugger has 431 * cancelled the breakpoint) or from an event thread (because it's a 432 * single-shot breakpoint, e.g. "run to line"). We only get here as 433 * the result of removing an entry from the event list, which is 434 * synchronized, so it should not be possible for two threads to be 435 * updating breakpoints at the same time. 436 */ 437void dvmClearBreakAddr(Method* method, unsigned int instrOffset) 438{ 439 BreakpointSet* pSet = gDvm.breakpointSet; 440 dvmBreakpointSetLock(pSet); 441 dvmBreakpointSetRemove(pSet, method, instrOffset); 442 dvmBreakpointSetUnlock(pSet); 443} 444 445/* 446 * Get the original opcode from under a breakpoint. 447 * 448 * On SMP hardware it's possible one core might try to execute a breakpoint 449 * after another core has cleared it. We need to handle the case where 450 * there's no entry in the breakpoint set. (The memory barriers in the 451 * locks and in the breakpoint update code should ensure that, once we've 452 * observed the absence of a breakpoint entry, we will also now observe 453 * the restoration of the original opcode. The fact that we're holding 454 * the lock prevents other threads from confusing things further.) 455 */ 456u1 dvmGetOriginalOpcode(const u2* addr) 457{ 458 BreakpointSet* pSet = gDvm.breakpointSet; 459 u1 orig = 0; 460 461 dvmBreakpointSetLock(pSet); 462 if (!dvmBreakpointSetOriginalOpcode(pSet, addr, &orig)) { 463 orig = *(u1*)addr; 464 if (orig == OP_BREAKPOINT) { 465 LOGE("GLITCH: can't find breakpoint, opcode is still set\n"); 466 dvmAbort(); 467 } 468 } 469 dvmBreakpointSetUnlock(pSet); 470 471 return orig; 472} 473 474/* 475 * Flush any breakpoints associated with methods in "clazz". 476 * 477 * We don't want to modify the bytecode of a method before the verifier 478 * gets a chance to look at it, so we postpone opcode replacement until 479 * after verification completes. 480 */ 481void dvmFlushBreakpoints(ClassObject* clazz) 482{ 483 BreakpointSet* pSet = gDvm.breakpointSet; 484 485 if (pSet == NULL) 486 return; 487 488 assert(dvmIsClassVerified(clazz)); 489 dvmBreakpointSetLock(pSet); 490 dvmBreakpointSetFlush(pSet, clazz); 491 dvmBreakpointSetUnlock(pSet); 492} 493 494/* 495 * Add a single step event. Currently this is a global item. 496 * 497 * We set up some initial values based on the thread's current state. This 498 * won't work well if the thread is running, so it's up to the caller to 499 * verify that it's suspended. 500 * 501 * This is only called from the JDWP thread. 502 */ 503bool dvmAddSingleStep(Thread* thread, int size, int depth) 504{ 505 StepControl* pCtrl = &gDvm.stepControl; 506 507 if (pCtrl->active && thread != pCtrl->thread) { 508 LOGW("WARNING: single-step active for %p; adding %p\n", 509 pCtrl->thread, thread); 510 511 /* 512 * Keep going, overwriting previous. This can happen if you 513 * suspend a thread in Object.wait, hit the single-step key, then 514 * switch to another thread and do the same thing again. 515 * The first thread's step is still pending. 516 * 517 * TODO: consider making single-step per-thread. Adds to the 518 * overhead, but could be useful in rare situations. 519 */ 520 } 521 522 pCtrl->size = static_cast<JdwpStepSize>(size); 523 pCtrl->depth = static_cast<JdwpStepDepth>(depth); 524 pCtrl->thread = thread; 525 526 /* 527 * We may be stepping into or over method calls, or running until we 528 * return from the current method. To make this work we need to track 529 * the current line, current method, and current stack depth. We need 530 * to be checking these after most instructions, notably those that 531 * call methods, return from methods, or are on a different line from the 532 * previous instruction. 533 * 534 * We have to start with a snapshot of the current state. If we're in 535 * an interpreted method, everything we need is in the current frame. If 536 * we're in a native method, possibly with some extra JNI frames pushed 537 * on by PushLocalFrame, we want to use the topmost native method. 538 */ 539 const StackSaveArea* saveArea; 540 u4* fp; 541 u4* prevFp = NULL; 542 543 for (fp = thread->interpSave.curFrame; fp != NULL; 544 fp = saveArea->prevFrame) { 545 const Method* method; 546 547 saveArea = SAVEAREA_FROM_FP(fp); 548 method = saveArea->method; 549 550 if (!dvmIsBreakFrame((u4*)fp) && !dvmIsNativeMethod(method)) 551 break; 552 prevFp = fp; 553 } 554 if (fp == NULL) { 555 LOGW("Unexpected: step req in native-only threadid=%d\n", 556 thread->threadId); 557 return false; 558 } 559 if (prevFp != NULL) { 560 /* 561 * First interpreted frame wasn't the one at the bottom. Break 562 * frames are only inserted when calling from native->interp, so we 563 * don't need to worry about one being here. 564 */ 565 LOGV("##### init step while in native method\n"); 566 fp = prevFp; 567 assert(!dvmIsBreakFrame((u4*)fp)); 568 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method)); 569 saveArea = SAVEAREA_FROM_FP(fp); 570 } 571 572 /* 573 * Pull the goodies out. "xtra.currentPc" should be accurate since 574 * we update it on every instruction while the debugger is connected. 575 */ 576 pCtrl->method = saveArea->method; 577 // Clear out any old address set 578 if (pCtrl->pAddressSet != NULL) { 579 // (discard const) 580 free((void *)pCtrl->pAddressSet); 581 pCtrl->pAddressSet = NULL; 582 } 583 if (dvmIsNativeMethod(pCtrl->method)) { 584 pCtrl->line = -1; 585 } else { 586 pCtrl->line = dvmLineNumFromPC(saveArea->method, 587 saveArea->xtra.currentPc - saveArea->method->insns); 588 pCtrl->pAddressSet 589 = dvmAddressSetForLine(saveArea->method, pCtrl->line); 590 } 591 pCtrl->frameDepth = 592 dvmComputeVagueFrameDepth(thread, thread->interpSave.curFrame); 593 pCtrl->active = true; 594 595 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n", 596 pCtrl->thread, pCtrl->method, pCtrl->method->name, 597 pCtrl->line, pCtrl->frameDepth, 598 dvmJdwpStepDepthStr(pCtrl->depth), 599 dvmJdwpStepSizeStr(pCtrl->size)); 600 601 return true; 602} 603 604/* 605 * Disable a single step event. 606 */ 607void dvmClearSingleStep(Thread* thread) 608{ 609 UNUSED_PARAMETER(thread); 610 611 gDvm.stepControl.active = false; 612} 613 614/* 615 * The interpreter just threw. Handle any special subMode requirements. 616 * All interpSave state must be valid on entry. 617 */ 618void dvmReportExceptionThrow(Thread* self, Object* exception) 619{ 620 const Method* curMethod = self->interpSave.method; 621#if defined(WITH_JIT) 622 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 623 dvmJitEndTraceSelect(self, self->interpSave.pc); 624 } 625 if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) { 626 /* Discard any single-step native returns to translation */ 627 self->jitResumeNPC = NULL; 628 } 629#endif 630 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 631 void *catchFrame; 632 int offset = self->interpSave.pc - curMethod->insns; 633 int catchRelPc = dvmFindCatchBlock(self, offset, exception, 634 true, &catchFrame); 635 dvmDbgPostException(self->interpSave.curFrame, offset, catchFrame, 636 catchRelPc, exception); 637 } 638} 639 640/* 641 * The interpreter is preparing to do an invoke (both native & normal). 642 * Handle any special subMode requirements. All interpSave state 643 * must be valid on entry. 644 */ 645void dvmReportInvoke(Thread* self, const Method* methodToCall) 646{ 647 TRACE_METHOD_ENTER(self, methodToCall); 648} 649 650/* 651 * The interpreter is preparing to do a native invoke. Handle any 652 * special subMode requirements. NOTE: for a native invoke, 653 * dvmReportInvoke() and dvmReportPreNativeInvoke() will both 654 * be called prior to the invoke. fp is the Dalvik FP of the calling 655 * method. 656 */ 657void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self, u4* fp) 658{ 659#if defined(WITH_JIT) 660 /* 661 * Actively building a trace? If so, end it now. The trace 662 * builder can't follow into or through a native method. 663 */ 664 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 665 dvmCheckJit(self->interpSave.pc, self); 666 } 667#endif 668 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 669 Object* thisPtr = dvmGetThisPtr(self->interpSave.method, fp); 670 assert(thisPtr == NULL || dvmIsValidObject(thisPtr)); 671 dvmDbgPostLocationEvent(methodToCall, -1, thisPtr, DBG_METHOD_ENTRY); 672 } 673} 674 675/* 676 * The interpreter has returned from a native invoke. Handle any 677 * special subMode requirements. fp is the Dalvik FP of the calling 678 * method. 679 */ 680void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self, u4* fp) 681{ 682 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 683 Object* thisPtr = dvmGetThisPtr(self->interpSave.method, fp); 684 assert(thisPtr == NULL || dvmIsValidObject(thisPtr)); 685 dvmDbgPostLocationEvent(methodToCall, -1, thisPtr, DBG_METHOD_EXIT); 686 } 687 if (self->interpBreak.ctl.subMode & kSubModeMethodTrace) { 688 dvmFastNativeMethodTraceExit(methodToCall, self); 689 } 690} 691 692/* 693 * The interpreter has returned from a normal method. Handle any special 694 * subMode requirements. All interpSave state must be valid on entry. 695 */ 696void dvmReportReturn(Thread* self) 697{ 698 TRACE_METHOD_EXIT(self, self->interpSave.method); 699#if defined(WITH_JIT) 700 if (dvmIsBreakFrame(self->interpSave.curFrame) && 701 (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild)) { 702 dvmCheckJit(self->interpSave.pc, self); 703 } 704#endif 705} 706 707/* 708 * Update the debugger on interesting events, such as hitting a breakpoint 709 * or a single-step point. This is called from the top of the interpreter 710 * loop, before the current instruction is processed. 711 * 712 * Set "methodEntry" if we've just entered the method. This detects 713 * method exit by checking to see if the next instruction is "return". 714 * 715 * This can't catch native method entry/exit, so we have to handle that 716 * at the point of invocation. We also need to catch it in dvmCallMethod 717 * if we want to capture native->native calls made through JNI. 718 * 719 * Notes to self: 720 * - Don't want to switch to VMWAIT while posting events to the debugger. 721 * Let the debugger code decide if we need to change state. 722 * - We may want to check for debugger-induced thread suspensions on 723 * every instruction. That would make a "suspend all" more responsive 724 * and reduce the chances of multiple simultaneous events occurring. 725 * However, it could change the behavior some. 726 * 727 * TODO: method entry/exit events are probably less common than location 728 * breakpoints. We may be able to speed things up a bit if we don't query 729 * the event list unless we know there's at least one lurking within. 730 */ 731static void updateDebugger(const Method* method, const u2* pc, const u4* fp, 732 Thread* self) 733{ 734 int eventFlags = 0; 735 736 /* 737 * Update xtra.currentPc on every instruction. We need to do this if 738 * there's a chance that we could get suspended. This can happen if 739 * eventFlags != 0 here, or somebody manually requests a suspend 740 * (which gets handled at PERIOD_CHECKS time). One place where this 741 * needs to be correct is in dvmAddSingleStep(). 742 */ 743 dvmExportPC(pc, fp); 744 745 if (self->debugIsMethodEntry) { 746 eventFlags |= DBG_METHOD_ENTRY; 747 self->debugIsMethodEntry = false; 748 } 749 750 /* 751 * See if we have a breakpoint here. 752 * 753 * Depending on the "mods" associated with event(s) on this address, 754 * we may or may not actually send a message to the debugger. 755 */ 756 if (GET_OPCODE(*pc) == OP_BREAKPOINT) { 757 LOGV("+++ breakpoint hit at %p\n", pc); 758 eventFlags |= DBG_BREAKPOINT; 759 } 760 761 /* 762 * If the debugger is single-stepping one of our threads, check to 763 * see if we're that thread and we've reached a step point. 764 */ 765 const StepControl* pCtrl = &gDvm.stepControl; 766 if (pCtrl->active && pCtrl->thread == self) { 767 int frameDepth; 768 bool doStop = false; 769 const char* msg = NULL; 770 771 assert(!dvmIsNativeMethod(method)); 772 773 if (pCtrl->depth == SD_INTO) { 774 /* 775 * Step into method calls. We break when the line number 776 * or method pointer changes. If we're in SS_MIN mode, we 777 * always stop. 778 */ 779 if (pCtrl->method != method) { 780 doStop = true; 781 msg = "new method"; 782 } else if (pCtrl->size == SS_MIN) { 783 doStop = true; 784 msg = "new instruction"; 785 } else if (!dvmAddressSetGet( 786 pCtrl->pAddressSet, pc - method->insns)) { 787 doStop = true; 788 msg = "new line"; 789 } 790 } else if (pCtrl->depth == SD_OVER) { 791 /* 792 * Step over method calls. We break when the line number is 793 * different and the frame depth is <= the original frame 794 * depth. (We can't just compare on the method, because we 795 * might get unrolled past it by an exception, and it's tricky 796 * to identify recursion.) 797 */ 798 frameDepth = dvmComputeVagueFrameDepth(self, fp); 799 if (frameDepth < pCtrl->frameDepth) { 800 /* popped up one or more frames, always trigger */ 801 doStop = true; 802 msg = "method pop"; 803 } else if (frameDepth == pCtrl->frameDepth) { 804 /* same depth, see if we moved */ 805 if (pCtrl->size == SS_MIN) { 806 doStop = true; 807 msg = "new instruction"; 808 } else if (!dvmAddressSetGet(pCtrl->pAddressSet, 809 pc - method->insns)) { 810 doStop = true; 811 msg = "new line"; 812 } 813 } 814 } else { 815 assert(pCtrl->depth == SD_OUT); 816 /* 817 * Return from the current method. We break when the frame 818 * depth pops up. 819 * 820 * This differs from the "method exit" break in that it stops 821 * with the PC at the next instruction in the returned-to 822 * function, rather than the end of the returning function. 823 */ 824 frameDepth = dvmComputeVagueFrameDepth(self, fp); 825 if (frameDepth < pCtrl->frameDepth) { 826 doStop = true; 827 msg = "method pop"; 828 } 829 } 830 831 if (doStop) { 832 LOGV("#####S %s\n", msg); 833 eventFlags |= DBG_SINGLE_STEP; 834 } 835 } 836 837 /* 838 * Check to see if this is a "return" instruction. JDWP says we should 839 * send the event *after* the code has been executed, but it also says 840 * the location we provide is the last instruction. Since the "return" 841 * instruction has no interesting side effects, we should be safe. 842 * (We can't just move this down to the returnFromMethod label because 843 * we potentially need to combine it with other events.) 844 * 845 * We're also not supposed to generate a method exit event if the method 846 * terminates "with a thrown exception". 847 */ 848 u2 opcode = GET_OPCODE(*pc); 849 if (opcode == OP_RETURN_VOID || opcode == OP_RETURN || 850 opcode == OP_RETURN_WIDE ||opcode == OP_RETURN_OBJECT) 851 { 852 eventFlags |= DBG_METHOD_EXIT; 853 } 854 855 /* 856 * If there's something interesting going on, see if it matches one 857 * of the debugger filters. 858 */ 859 if (eventFlags != 0) { 860 Object* thisPtr = dvmGetThisPtr(method, fp); 861 if (thisPtr != NULL && !dvmIsValidObject(thisPtr)) { 862 /* 863 * TODO: remove this check if we're confident that the "this" 864 * pointer is where it should be -- slows us down, especially 865 * during single-step. 866 */ 867 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 868 LOGE("HEY: invalid 'this' ptr %p (%s.%s %s)\n", thisPtr, 869 method->clazz->descriptor, method->name, desc); 870 free(desc); 871 dvmAbort(); 872 } 873 dvmDbgPostLocationEvent(method, pc - method->insns, thisPtr, 874 eventFlags); 875 } 876} 877 878/* 879 * Recover the "this" pointer from the current interpreted method. "this" 880 * is always in "in0" for non-static methods. 881 * 882 * The "ins" start at (#of registers - #of ins). Note in0 != v0. 883 * 884 * This works because "dx" guarantees that it will work. It's probably 885 * fairly common to have a virtual method that doesn't use its "this" 886 * pointer, in which case we're potentially wasting a register. However, 887 * the debugger doesn't treat "this" as just another argument. For 888 * example, events (such as breakpoints) can be enabled for specific 889 * values of "this". There is also a separate StackFrame.ThisObject call 890 * in JDWP that is expected to work for any non-native non-static method. 891 * 892 * Because we need it when setting up debugger event filters, we want to 893 * be able to do this quickly. 894 */ 895Object* dvmGetThisPtr(const Method* method, const u4* fp) 896{ 897 if (dvmIsStaticMethod(method)) 898 return NULL; 899 return (Object*)fp[method->registersSize - method->insSize]; 900} 901 902 903#if defined(WITH_TRACKREF_CHECKS) 904/* 905 * Verify that all internally-tracked references have been released. If 906 * they haven't, print them and abort the VM. 907 * 908 * "debugTrackedRefStart" indicates how many refs were on the list when 909 * we were first invoked. 910 */ 911void dvmInterpCheckTrackedRefs(Thread* self, const Method* method, 912 int debugTrackedRefStart) 913{ 914 if (dvmReferenceTableEntries(&self->internalLocalRefTable) 915 != (size_t) debugTrackedRefStart) 916 { 917 char* desc; 918 Object** top; 919 int count; 920 921 count = dvmReferenceTableEntries(&self->internalLocalRefTable); 922 923 LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n", 924 debugTrackedRefStart, count); 925 desc = dexProtoCopyMethodDescriptor(&method->prototype); 926 LOGE(" current method is %s.%s %s\n", method->clazz->descriptor, 927 method->name, desc); 928 free(desc); 929 top = self->internalLocalRefTable.table + debugTrackedRefStart; 930 while (top < self->internalLocalRefTable.nextEntry) { 931 LOGE(" %p (%s)\n", 932 *top, 933 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : ""); 934 top++; 935 } 936 dvmDumpThread(self, false); 937 938 dvmAbort(); 939 } 940 //LOGI("TRACK OK\n"); 941} 942#endif 943 944 945#ifdef LOG_INSTR 946/* 947 * Dump the v-registers. Sent to the ILOG log tag. 948 */ 949void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly) 950{ 951 int i, localCount; 952 953 localCount = method->registersSize - method->insSize; 954 955 LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr); 956 for (i = method->registersSize-1; i >= 0; i--) { 957 if (i >= localCount) { 958 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n", 959 i, i-localCount, framePtr[i]); 960 } else { 961 if (inOnly) { 962 LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n"); 963 break; 964 } 965 const char* name = ""; 966#if 0 // "locals" structure has changed -- need to rewrite this 967 int j; 968 DexFile* pDexFile = method->clazz->pDexFile; 969 const DexCode* pDexCode = dvmGetMethodCode(method); 970 int localsSize = dexGetLocalsSize(pDexFile, pDexCode); 971 const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode); 972 for (j = 0; j < localsSize, j++) { 973 if (locals[j].registerNum == (u4) i) { 974 name = dvmDexStringStr(locals[j].pName); 975 break; 976 } 977 } 978#endif 979 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n", 980 i, framePtr[i], name); 981 } 982 } 983} 984#endif 985 986 987/* 988 * =========================================================================== 989 * Entry point and general support functions 990 * =========================================================================== 991 */ 992 993/* 994 * Construct an s4 from two consecutive half-words of switch data. 995 * This needs to check endianness because the DEX optimizer only swaps 996 * half-words in instruction stream. 997 * 998 * "switchData" must be 32-bit aligned. 999 */ 1000#if __BYTE_ORDER == __LITTLE_ENDIAN 1001static inline s4 s4FromSwitchData(const void* switchData) { 1002 return *(s4*) switchData; 1003} 1004#else 1005static inline s4 s4FromSwitchData(const void* switchData) { 1006 u2* data = switchData; 1007 return data[0] | (((s4) data[1]) << 16); 1008} 1009#endif 1010 1011/* 1012 * Find the matching case. Returns the offset to the handler instructions. 1013 * 1014 * Returns 3 if we don't find a match (it's the size of the packed-switch 1015 * instruction). 1016 */ 1017s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal) 1018{ 1019 const int kInstrLen = 3; 1020 u2 size; 1021 s4 firstKey; 1022 const s4* entries; 1023 1024 /* 1025 * Packed switch data format: 1026 * ushort ident = 0x0100 magic value 1027 * ushort size number of entries in the table 1028 * int first_key first (and lowest) switch case value 1029 * int targets[size] branch targets, relative to switch opcode 1030 * 1031 * Total size is (4+size*2) 16-bit code units. 1032 */ 1033 if (*switchData++ != kPackedSwitchSignature) { 1034 /* should have been caught by verifier */ 1035 dvmThrowInternalError("bad packed switch magic"); 1036 return kInstrLen; 1037 } 1038 1039 size = *switchData++; 1040 assert(size > 0); 1041 1042 firstKey = *switchData++; 1043 firstKey |= (*switchData++) << 16; 1044 1045 if (testVal < firstKey || testVal >= firstKey + size) { 1046 LOGVV("Value %d not found in switch (%d-%d)\n", 1047 testVal, firstKey, firstKey+size-1); 1048 return kInstrLen; 1049 } 1050 1051 /* The entries are guaranteed to be aligned on a 32-bit boundary; 1052 * we can treat them as a native int array. 1053 */ 1054 entries = (const s4*) switchData; 1055 assert(((u4)entries & 0x3) == 0); 1056 1057 assert(testVal - firstKey >= 0 && testVal - firstKey < size); 1058 LOGVV("Value %d found in slot %d (goto 0x%02x)\n", 1059 testVal, testVal - firstKey, 1060 s4FromSwitchData(&entries[testVal - firstKey])); 1061 return s4FromSwitchData(&entries[testVal - firstKey]); 1062} 1063 1064/* 1065 * Find the matching case. Returns the offset to the handler instructions. 1066 * 1067 * Returns 3 if we don't find a match (it's the size of the sparse-switch 1068 * instruction). 1069 */ 1070s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal) 1071{ 1072 const int kInstrLen = 3; 1073 u2 size; 1074 const s4* keys; 1075 const s4* entries; 1076 1077 /* 1078 * Sparse switch data format: 1079 * ushort ident = 0x0200 magic value 1080 * ushort size number of entries in the table; > 0 1081 * int keys[size] keys, sorted low-to-high; 32-bit aligned 1082 * int targets[size] branch targets, relative to switch opcode 1083 * 1084 * Total size is (2+size*4) 16-bit code units. 1085 */ 1086 1087 if (*switchData++ != kSparseSwitchSignature) { 1088 /* should have been caught by verifier */ 1089 dvmThrowInternalError("bad sparse switch magic"); 1090 return kInstrLen; 1091 } 1092 1093 size = *switchData++; 1094 assert(size > 0); 1095 1096 /* The keys are guaranteed to be aligned on a 32-bit boundary; 1097 * we can treat them as a native int array. 1098 */ 1099 keys = (const s4*) switchData; 1100 assert(((u4)keys & 0x3) == 0); 1101 1102 /* The entries are guaranteed to be aligned on a 32-bit boundary; 1103 * we can treat them as a native int array. 1104 */ 1105 entries = keys + size; 1106 assert(((u4)entries & 0x3) == 0); 1107 1108 /* 1109 * Binary-search through the array of keys, which are guaranteed to 1110 * be sorted low-to-high. 1111 */ 1112 int lo = 0; 1113 int hi = size - 1; 1114 while (lo <= hi) { 1115 int mid = (lo + hi) >> 1; 1116 1117 s4 foundVal = s4FromSwitchData(&keys[mid]); 1118 if (testVal < foundVal) { 1119 hi = mid - 1; 1120 } else if (testVal > foundVal) { 1121 lo = mid + 1; 1122 } else { 1123 LOGVV("Value %d found in entry %d (goto 0x%02x)\n", 1124 testVal, mid, s4FromSwitchData(&entries[mid])); 1125 return s4FromSwitchData(&entries[mid]); 1126 } 1127 } 1128 1129 LOGVV("Value %d not found in switch\n", testVal); 1130 return kInstrLen; 1131} 1132 1133/* 1134 * Copy data for a fill-array-data instruction. On a little-endian machine 1135 * we can just do a memcpy(), on a big-endian system we have work to do. 1136 * 1137 * The trick here is that dexopt has byte-swapped each code unit, which is 1138 * exactly what we want for short/char data. For byte data we need to undo 1139 * the swap, and for 4- or 8-byte values we need to swap pieces within 1140 * each word. 1141 */ 1142static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width) 1143{ 1144#if __BYTE_ORDER == __LITTLE_ENDIAN 1145 memcpy(dest, src, size*width); 1146#else 1147 int i; 1148 1149 switch (width) { 1150 case 1: 1151 /* un-swap pairs of bytes as we go */ 1152 for (i = (size-1) & ~1; i >= 0; i -= 2) { 1153 ((u1*)dest)[i] = ((u1*)src)[i+1]; 1154 ((u1*)dest)[i+1] = ((u1*)src)[i]; 1155 } 1156 /* 1157 * "src" is padded to end on a two-byte boundary, but we don't want to 1158 * assume "dest" is, so we handle odd length specially. 1159 */ 1160 if ((size & 1) != 0) { 1161 ((u1*)dest)[size-1] = ((u1*)src)[size]; 1162 } 1163 break; 1164 case 2: 1165 /* already swapped correctly */ 1166 memcpy(dest, src, size*width); 1167 break; 1168 case 4: 1169 /* swap word halves */ 1170 for (i = 0; i < (int) size; i++) { 1171 ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1]; 1172 } 1173 break; 1174 case 8: 1175 /* swap word halves and words */ 1176 for (i = 0; i < (int) (size << 1); i += 2) { 1177 ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2]; 1178 ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1]; 1179 } 1180 break; 1181 default: 1182 LOGE("Unexpected width %d in copySwappedArrayData\n", width); 1183 dvmAbort(); 1184 break; 1185 } 1186#endif 1187} 1188 1189/* 1190 * Fill the array with predefined constant values. 1191 * 1192 * Returns true if job is completed, otherwise false to indicate that 1193 * an exception has been thrown. 1194 */ 1195bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData) 1196{ 1197 u2 width; 1198 u4 size; 1199 1200 if (arrayObj == NULL) { 1201 dvmThrowNullPointerException(NULL); 1202 return false; 1203 } 1204 assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz, 1205 CLASS_ISOBJECTARRAY)); 1206 1207 /* 1208 * Array data table format: 1209 * ushort ident = 0x0300 magic value 1210 * ushort width width of each element in the table 1211 * uint size number of elements in the table 1212 * ubyte data[size*width] table of data values (may contain a single-byte 1213 * padding at the end) 1214 * 1215 * Total size is 4+(width * size + 1)/2 16-bit code units. 1216 */ 1217 if (arrayData[0] != kArrayDataSignature) { 1218 dvmThrowInternalError("bad array data magic"); 1219 return false; 1220 } 1221 1222 width = arrayData[1]; 1223 size = arrayData[2] | (((u4)arrayData[3]) << 16); 1224 1225 if (size > arrayObj->length) { 1226 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, size); 1227 return false; 1228 } 1229 copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width); 1230 return true; 1231} 1232 1233/* 1234 * Find the concrete method that corresponds to "methodIdx". The code in 1235 * "method" is executing invoke-method with "thisClass" as its first argument. 1236 * 1237 * Returns NULL with an exception raised on failure. 1238 */ 1239Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx, 1240 const Method* method, DvmDex* methodClassDex) 1241{ 1242 Method* absMethod; 1243 Method* methodToCall; 1244 int i, vtableIndex; 1245 1246 /* 1247 * Resolve the method. This gives us the abstract method from the 1248 * interface class declaration. 1249 */ 1250 absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx); 1251 if (absMethod == NULL) { 1252 absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx); 1253 if (absMethod == NULL) { 1254 LOGV("+ unknown method\n"); 1255 return NULL; 1256 } 1257 } 1258 1259 /* make sure absMethod->methodIndex means what we think it means */ 1260 assert(dvmIsAbstractMethod(absMethod)); 1261 1262 /* 1263 * Run through the "this" object's iftable. Find the entry for 1264 * absMethod's class, then use absMethod->methodIndex to find 1265 * the method's entry. The value there is the offset into our 1266 * vtable of the actual method to execute. 1267 * 1268 * The verifier does not guarantee that objects stored into 1269 * interface references actually implement the interface, so this 1270 * check cannot be eliminated. 1271 */ 1272 for (i = 0; i < thisClass->iftableCount; i++) { 1273 if (thisClass->iftable[i].clazz == absMethod->clazz) 1274 break; 1275 } 1276 if (i == thisClass->iftableCount) { 1277 /* impossible in verified DEX, need to check for it in unverified */ 1278 dvmThrowIncompatibleClassChangeError("interface not implemented"); 1279 return NULL; 1280 } 1281 1282 assert(absMethod->methodIndex < 1283 thisClass->iftable[i].clazz->virtualMethodCount); 1284 1285 vtableIndex = 1286 thisClass->iftable[i].methodIndexArray[absMethod->methodIndex]; 1287 assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount); 1288 methodToCall = thisClass->vtable[vtableIndex]; 1289 1290#if 0 1291 /* this can happen when there's a stale class file */ 1292 if (dvmIsAbstractMethod(methodToCall)) { 1293 dvmThrowAbstractMethodError("interface method not implemented"); 1294 return NULL; 1295 } 1296#else 1297 assert(!dvmIsAbstractMethod(methodToCall) || 1298 methodToCall->nativeFunc != NULL); 1299#endif 1300 1301 LOGVV("+++ interface=%s.%s concrete=%s.%s\n", 1302 absMethod->clazz->descriptor, absMethod->name, 1303 methodToCall->clazz->descriptor, methodToCall->name); 1304 assert(methodToCall != NULL); 1305 1306 return methodToCall; 1307} 1308 1309 1310 1311/* 1312 * Helpers for dvmThrowVerificationError(). 1313 * 1314 * Each returns a newly-allocated string. 1315 */ 1316#define kThrowShow_accessFromClass 1 1317static char* classNameFromIndex(const Method* method, int ref, 1318 VerifyErrorRefType refType, int flags) 1319{ 1320 static const int kBufLen = 256; 1321 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1322 1323 if (refType == VERIFY_ERROR_REF_FIELD) { 1324 /* get class ID from field ID */ 1325 const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1326 ref = pFieldId->classIdx; 1327 } else if (refType == VERIFY_ERROR_REF_METHOD) { 1328 /* get class ID from method ID */ 1329 const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1330 ref = pMethodId->classIdx; 1331 } 1332 1333 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref); 1334 char* dotClassName = dvmHumanReadableDescriptor(className); 1335 if (flags == 0) 1336 return dotClassName; 1337 1338 char* result = (char*) malloc(kBufLen); 1339 1340 if ((flags & kThrowShow_accessFromClass) != 0) { 1341 char* dotFromName = 1342 dvmHumanReadableDescriptor(method->clazz->descriptor); 1343 snprintf(result, kBufLen, "tried to access class %s from class %s", 1344 dotClassName, dotFromName); 1345 free(dotFromName); 1346 } else { 1347 assert(false); // should've been caught above 1348 result[0] = '\0'; 1349 } 1350 1351 free(dotClassName); 1352 return result; 1353} 1354static char* fieldNameFromIndex(const Method* method, int ref, 1355 VerifyErrorRefType refType, int flags) 1356{ 1357 static const int kBufLen = 256; 1358 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1359 const DexFieldId* pFieldId; 1360 const char* className; 1361 const char* fieldName; 1362 1363 if (refType != VERIFY_ERROR_REF_FIELD) { 1364 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType); 1365 return NULL; /* no message */ 1366 } 1367 1368 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1369 className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx); 1370 fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); 1371 1372 char* dotName = dvmHumanReadableDescriptor(className); 1373 char* result = (char*) malloc(kBufLen); 1374 1375 if ((flags & kThrowShow_accessFromClass) != 0) { 1376 char* dotFromName = 1377 dvmHumanReadableDescriptor(method->clazz->descriptor); 1378 snprintf(result, kBufLen, "tried to access field %s.%s from class %s", 1379 dotName, fieldName, dotFromName); 1380 free(dotFromName); 1381 } else { 1382 snprintf(result, kBufLen, "%s.%s", dotName, fieldName); 1383 } 1384 1385 free(dotName); 1386 return result; 1387} 1388static char* methodNameFromIndex(const Method* method, int ref, 1389 VerifyErrorRefType refType, int flags) 1390{ 1391 static const int kBufLen = 384; 1392 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1393 const DexMethodId* pMethodId; 1394 const char* className; 1395 const char* methodName; 1396 1397 if (refType != VERIFY_ERROR_REF_METHOD) { 1398 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType); 1399 return NULL; /* no message */ 1400 } 1401 1402 pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1403 className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx); 1404 methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 1405 1406 char* dotName = dvmHumanReadableDescriptor(className); 1407 char* result = (char*) malloc(kBufLen); 1408 1409 if ((flags & kThrowShow_accessFromClass) != 0) { 1410 char* dotFromName = 1411 dvmHumanReadableDescriptor(method->clazz->descriptor); 1412 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1413 snprintf(result, kBufLen, 1414 "tried to access method %s.%s:%s from class %s", 1415 dotName, methodName, desc, dotFromName); 1416 free(dotFromName); 1417 free(desc); 1418 } else { 1419 snprintf(result, kBufLen, "%s.%s", dotName, methodName); 1420 } 1421 1422 free(dotName); 1423 return result; 1424} 1425 1426/* 1427 * Throw an exception for a problem identified by the verifier. 1428 * 1429 * This is used by the invoke-verification-error instruction. It always 1430 * throws an exception. 1431 * 1432 * "kind" indicates the kind of failure encountered by the verifier. It 1433 * has two parts, an error code and an indication of the reference type. 1434 */ 1435void dvmThrowVerificationError(const Method* method, int kind, int ref) 1436{ 1437 int errorPart = kind & ~(0xff << kVerifyErrorRefTypeShift); 1438 int errorRefPart = kind >> kVerifyErrorRefTypeShift; 1439 VerifyError errorKind = static_cast<VerifyError>(errorPart); 1440 VerifyErrorRefType refType = static_cast<VerifyErrorRefType>(errorRefPart); 1441 ClassObject* exceptionClass = gDvm.exVerifyError; 1442 char* msg = NULL; 1443 1444 switch ((VerifyError) errorKind) { 1445 case VERIFY_ERROR_NO_CLASS: 1446 exceptionClass = gDvm.exNoClassDefFoundError; 1447 msg = classNameFromIndex(method, ref, refType, 0); 1448 break; 1449 case VERIFY_ERROR_NO_FIELD: 1450 exceptionClass = gDvm.exNoSuchFieldError; 1451 msg = fieldNameFromIndex(method, ref, refType, 0); 1452 break; 1453 case VERIFY_ERROR_NO_METHOD: 1454 exceptionClass = gDvm.exNoSuchMethodError; 1455 msg = methodNameFromIndex(method, ref, refType, 0); 1456 break; 1457 case VERIFY_ERROR_ACCESS_CLASS: 1458 exceptionClass = gDvm.exIllegalAccessError; 1459 msg = classNameFromIndex(method, ref, refType, 1460 kThrowShow_accessFromClass); 1461 break; 1462 case VERIFY_ERROR_ACCESS_FIELD: 1463 exceptionClass = gDvm.exIllegalAccessError; 1464 msg = fieldNameFromIndex(method, ref, refType, 1465 kThrowShow_accessFromClass); 1466 break; 1467 case VERIFY_ERROR_ACCESS_METHOD: 1468 exceptionClass = gDvm.exIllegalAccessError; 1469 msg = methodNameFromIndex(method, ref, refType, 1470 kThrowShow_accessFromClass); 1471 break; 1472 case VERIFY_ERROR_CLASS_CHANGE: 1473 exceptionClass = gDvm.exIncompatibleClassChangeError; 1474 msg = classNameFromIndex(method, ref, refType, 0); 1475 break; 1476 case VERIFY_ERROR_INSTANTIATION: 1477 exceptionClass = gDvm.exInstantiationError; 1478 msg = classNameFromIndex(method, ref, refType, 0); 1479 break; 1480 1481 case VERIFY_ERROR_GENERIC: 1482 /* generic VerifyError; use default exception, no message */ 1483 break; 1484 case VERIFY_ERROR_NONE: 1485 /* should never happen; use default exception */ 1486 assert(false); 1487 msg = strdup("weird - no error specified"); 1488 break; 1489 1490 /* no default clause -- want warning if enum updated */ 1491 } 1492 1493 dvmThrowException(exceptionClass, msg); 1494 free(msg); 1495} 1496 1497/* 1498 * Update interpBreak for a single thread. 1499 */ 1500void updateInterpBreak(Thread* thread, ExecutionSubModes subMode, bool enable) 1501{ 1502 InterpBreak oldValue, newValue; 1503 do { 1504 oldValue = newValue = thread->interpBreak; 1505 newValue.ctl.breakFlags = kInterpNoBreak; // Assume full reset 1506 if (enable) 1507 newValue.ctl.subMode |= subMode; 1508 else 1509 newValue.ctl.subMode &= ~subMode; 1510 if (newValue.ctl.subMode & SINGLESTEP_BREAK_MASK) 1511 newValue.ctl.breakFlags |= kInterpSingleStep; 1512 if (newValue.ctl.subMode & SAFEPOINT_BREAK_MASK) 1513 newValue.ctl.breakFlags |= kInterpSafePoint; 1514 newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ? 1515 thread->altHandlerTable : thread->mainHandlerTable; 1516 } while (dvmQuasiAtomicCas64(oldValue.all, newValue.all, 1517 &thread->interpBreak.all) != 0); 1518} 1519 1520/* 1521 * Update interpBreak for all threads. 1522 */ 1523void updateAllInterpBreak(ExecutionSubModes subMode, bool enable) 1524{ 1525 Thread* self = dvmThreadSelf(); 1526 Thread* thread; 1527 1528 dvmLockThreadList(self); 1529 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 1530 updateInterpBreak(thread, subMode, enable); 1531 } 1532 dvmUnlockThreadList(); 1533} 1534 1535/* 1536 * Update the normal and debugger suspend counts for a thread. 1537 * threadSuspendCount must be acquired before calling this to 1538 * ensure a clean update of suspendCount, dbgSuspendCount and 1539 * sumThreadSuspendCount. 1540 * 1541 * CLEANUP TODO: Currently only the JIT is using sumThreadSuspendCount. 1542 * Move under WITH_JIT ifdefs. 1543*/ 1544void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta) 1545{ 1546 thread->suspendCount += delta; 1547 thread->dbgSuspendCount += dbgDelta; 1548 updateInterpBreak(thread, kSubModeSuspendPending, 1549 (thread->suspendCount != 0)); 1550 // Update the global suspend count total 1551 gDvm.sumThreadSuspendCount += delta; 1552} 1553 1554 1555void dvmDisableSubMode(Thread* thread, ExecutionSubModes subMode) 1556{ 1557 updateInterpBreak(thread, subMode, false); 1558} 1559 1560void dvmEnableSubMode(Thread* thread, ExecutionSubModes subMode) 1561{ 1562 updateInterpBreak(thread, subMode, true); 1563} 1564 1565void dvmEnableAllSubMode(ExecutionSubModes subMode) 1566{ 1567 updateAllInterpBreak(subMode, true); 1568} 1569 1570void dvmDisableAllSubMode(ExecutionSubModes subMode) 1571{ 1572 updateAllInterpBreak(subMode, false); 1573} 1574 1575/* 1576 * Do a sanity check on interpreter state saved to Thread. 1577 * A failure here doesn't necessarily mean that something is wrong, 1578 * so this code should only be used during development to suggest 1579 * a possible problem. 1580 */ 1581void dvmCheckInterpStateConsistency() 1582{ 1583 Thread* self = dvmThreadSelf(); 1584 Thread* thread; 1585 uint8_t breakFlags; 1586 uint8_t subMode; 1587 void* handlerTable; 1588 1589 dvmLockThreadList(self); 1590 breakFlags = self->interpBreak.ctl.breakFlags; 1591 subMode = self->interpBreak.ctl.subMode; 1592 handlerTable = self->interpBreak.ctl.curHandlerTable; 1593 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 1594 if (subMode != thread->interpBreak.ctl.subMode) { 1595 LOGD("Warning: subMode mismatch - 0x%x:0x%x, tid[%d]", 1596 subMode,thread->interpBreak.ctl.subMode,thread->threadId); 1597 } 1598 if (breakFlags != thread->interpBreak.ctl.breakFlags) { 1599 LOGD("Warning: breakFlags mismatch - 0x%x:0x%x, tid[%d]", 1600 breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId); 1601 } 1602 if (handlerTable != thread->interpBreak.ctl.curHandlerTable) { 1603 LOGD("Warning: curHandlerTable mismatch - 0x%x:0x%x, tid[%d]", 1604 (int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable, 1605 thread->threadId); 1606 } 1607#if defined(WITH_JIT) 1608 if (thread->pJitProfTable != gDvmJit.pProfTable) { 1609 LOGD("Warning: pJitProfTable mismatch - 0x%x:0x%x, tid[%d]", 1610 (int)thread->pJitProfTable,(int)gDvmJit.pProfTable, 1611 thread->threadId); 1612 } 1613 if (thread->jitThreshold != gDvmJit.threshold) { 1614 LOGD("Warning: jitThreshold mismatch - 0x%x:0x%x, tid[%d]", 1615 (int)thread->jitThreshold,(int)gDvmJit.threshold, 1616 thread->threadId); 1617 } 1618#endif 1619 } 1620 dvmUnlockThreadList(); 1621} 1622 1623/* 1624 * Arm a safepoint callback for a thread. If funct is null, 1625 * clear any pending callback. 1626 * TODO: only gc is currently using this feature, and will have 1627 * at most a single outstanding callback request. Until we need 1628 * something more capable and flexible, enforce this limit. 1629 */ 1630void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct, 1631 void* arg) 1632{ 1633 dvmLockMutex(&thread->callbackMutex); 1634 if ((funct == NULL) || (thread->callback == NULL)) { 1635 thread->callback = funct; 1636 thread->callbackArg = arg; 1637 if (funct != NULL) { 1638 dvmEnableSubMode(thread, kSubModeCallbackPending); 1639 } else { 1640 dvmDisableSubMode(thread, kSubModeCallbackPending); 1641 } 1642 } else { 1643 // Already armed. Different? 1644 if ((funct != thread->callback) || 1645 (arg != thread->callbackArg)) { 1646 // Yes - report failure and die 1647 LOGE("ArmSafePointCallback failed, thread %d", thread->threadId); 1648 dvmUnlockMutex(&thread->callbackMutex); 1649 dvmAbort(); 1650 } 1651 } 1652 dvmUnlockMutex(&thread->callbackMutex); 1653} 1654 1655/* 1656 * One-time initialization at thread creation. Here we initialize 1657 * useful constants. 1658 */ 1659void dvmInitInterpreterState(Thread* self) 1660{ 1661#if defined(WITH_JIT) 1662 /* 1663 * Reserve a static entity here to quickly setup runtime contents as 1664 * gcc will issue block copy instructions. 1665 */ 1666 static struct JitToInterpEntries jitToInterpEntries = { 1667 dvmJitToInterpNormal, 1668 dvmJitToInterpNoChain, 1669 dvmJitToInterpPunt, 1670 dvmJitToInterpSingleStep, 1671 dvmJitToInterpTraceSelect, 1672#if defined(WITH_SELF_VERIFICATION) 1673 dvmJitToInterpBackwardBranch, 1674#else 1675 NULL, 1676#endif 1677 }; 1678#endif 1679 1680 // Begin initialization 1681 self->cardTable = gDvm.biasedCardTableBase; 1682#if defined(WITH_JIT) 1683 // One-time initializations 1684 self->jitToInterpEntries = jitToInterpEntries; 1685 self->icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN; 1686 self->pProfileCountdown = &gDvmJit.profileCountdown; 1687 // Jit state that can change 1688 dvmJitUpdateThreadStateSingle(self); 1689#endif 1690} 1691 1692/* 1693 * For a newly-created thread, we need to start off with interpBreak 1694 * set to any existing global modes. The caller must hold the 1695 * thread list lock. 1696 */ 1697void dvmInitializeInterpBreak(Thread* thread) 1698{ 1699 if (gDvm.instructionCountEnableCount > 0) { 1700 dvmEnableSubMode(thread, kSubModeInstCounting); 1701 } 1702 if (dvmIsMethodTraceActive()) { 1703 dvmEnableSubMode(thread, kSubModeMethodTrace); 1704 } 1705 if (gDvm.emulatorTraceEnableCount > 0) { 1706 dvmEnableSubMode(thread, kSubModeEmulatorTrace); 1707 } 1708 if (gDvm.debuggerActive) { 1709 dvmEnableSubMode(thread, kSubModeDebuggerActive); 1710 } 1711} 1712 1713/* 1714 * Inter-instruction handler invoked in between instruction interpretations 1715 * to handle exceptional events such as debugging housekeeping, instruction 1716 * count profiling, JIT trace building, etc. Dalvik PC has been exported 1717 * prior to call, but Thread copy of dPC & fp are not current. 1718 */ 1719void dvmCheckBefore(const u2 *pc, u4 *fp, Thread* self) 1720{ 1721 const Method* method = self->interpSave.method; 1722 assert(self->interpBreak.ctl.breakFlags != 0); 1723 assert(pc >= method->insns && pc < 1724 method->insns + dvmGetMethodInsnsSize(method)); 1725 1726#if 0 1727 /* 1728 * When we hit a specific method, enable verbose instruction logging. 1729 * Sometimes it's helpful to use the debugger attach as a trigger too. 1730 */ 1731 if (*pIsMethodEntry) { 1732 static const char* cd = "Landroid/test/Arithmetic;"; 1733 static const char* mn = "shiftTest2"; 1734 static const char* sg = "()V"; 1735 1736 if (/*self->interpBreak.ctl.subMode & kSubModeDebuggerActive &&*/ 1737 strcmp(method->clazz->descriptor, cd) == 0 && 1738 strcmp(method->name, mn) == 0 && 1739 strcmp(method->shorty, sg) == 0) 1740 { 1741 LOGW("Reached %s.%s, enabling verbose mode\n", 1742 method->clazz->descriptor, method->name); 1743 android_setMinPriority(LOG_TAG"i", ANDROID_LOG_VERBOSE); 1744 dumpRegs(method, fp, true); 1745 } 1746 1747 if (!gDvm.debuggerActive) 1748 *pIsMethodEntry = false; 1749 } 1750#endif 1751 1752 /* Safe point handling */ 1753 if (self->suspendCount || 1754 (self->interpBreak.ctl.subMode & kSubModeCallbackPending)) { 1755 // Are we are a safe point? 1756 int flags; 1757 flags = dexGetFlagsFromOpcode(dexOpcodeFromCodeUnit(*pc)); 1758 if (flags & VERIFY_GC_INST_MASK) { 1759 // Yes, at a safe point. Pending callback? 1760 if (self->interpBreak.ctl.subMode & kSubModeCallbackPending) { 1761 SafePointCallback callback; 1762 void* arg; 1763 // Get consistent funct/arg pair 1764 dvmLockMutex(&self->callbackMutex); 1765 callback = self->callback; 1766 arg = self->callbackArg; 1767 dvmUnlockMutex(&self->callbackMutex); 1768 // Update Thread structure 1769 self->interpSave.pc = pc; 1770 self->interpSave.curFrame = fp; 1771 if (callback != NULL) { 1772 // Do the callback 1773 if (!callback(self,arg)) { 1774 // disarm 1775 dvmArmSafePointCallback(self, NULL, NULL); 1776 } 1777 } 1778 } 1779 // Need to suspend? 1780 if (self->suspendCount) { 1781 dvmExportPC(pc, fp); 1782 dvmCheckSuspendPending(self); 1783 } 1784 } 1785 } 1786 1787 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 1788 updateDebugger(method, pc, fp, self); 1789 } 1790 if (gDvm.instructionCountEnableCount != 0) { 1791 /* 1792 * Count up the #of executed instructions. This isn't synchronized 1793 * for thread-safety; if we need that we should make this 1794 * thread-local and merge counts into the global area when threads 1795 * exit (perhaps suspending all other threads GC-style and pulling 1796 * the data out of them). 1797 */ 1798 gDvm.executedInstrCounts[GET_OPCODE(*pc)]++; 1799 } 1800 1801 1802#if defined(WITH_TRACKREF_CHECKS) 1803 dvmInterpCheckTrackedRefs(self, method, 1804 self->interpSave.debugTrackedRefStart); 1805#endif 1806 1807#if defined(WITH_JIT) 1808 // Does the JIT need anything done now? 1809 if (self->interpBreak.ctl.subMode & 1810 (kSubModeJitTraceBuild | kSubModeJitSV)) { 1811 // Are we building a trace? 1812 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 1813 dvmCheckJit(pc, self); 1814 } 1815 1816#if defined(WITH_SELF_VERIFICATION) 1817 // Are we replaying a trace? 1818 if (self->interpBreak.ctl.subMode & kSubModeJitSV) { 1819 dvmCheckSelfVerification(pc, self); 1820 } 1821#endif 1822 } 1823#endif 1824 1825 /* 1826 * SingleStep processing. NOTE: must be the last here to allow 1827 * preceeding special case handler to manipulate single-step count. 1828 */ 1829 if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) { 1830 if (self->singleStepCount == 0) { 1831 // We've exhausted our single step count 1832 dvmDisableSubMode(self, kSubModeCountedStep); 1833#if defined(WITH_JIT) 1834#if 0 1835 /* 1836 * For debugging. If jitResumeDPC is non-zero, then 1837 * we expect to return to a trace in progress. There 1838 * are valid reasons why we wouldn't (such as an exception 1839 * throw), but here we can keep track. 1840 */ 1841 if (self->jitResumeDPC != NULL) { 1842 if (self->jitResumeDPC == pc) { 1843 if (self->jitResumeNPC != NULL) { 1844 LOGD("SS return to trace - pc:0x%x to 0x:%x", 1845 (int)pc, (int)self->jitResumeNPC); 1846 } else { 1847 LOGD("SS return to interp - pc:0x%x",(int)pc); 1848 } 1849 } else { 1850 LOGD("SS failed to return. Expected 0x%x, now at 0x%x", 1851 (int)self->jitResumeDPC, (int)pc); 1852 } 1853 } 1854#endif 1855 // If we've got a native return and no other reasons to 1856 // remain in singlestep/break mode, do a long jump 1857 if (self->jitResumeNPC != NULL && 1858 self->interpBreak.ctl.breakFlags == 0) { 1859 assert(self->jitResumeDPC == pc); 1860 self->jitResumeDPC = NULL; 1861 dvmJitResumeTranslation(self, pc, fp); 1862 // Doesn't return 1863 dvmAbort(); 1864 } 1865 self->jitResumeDPC = NULL; 1866 self->inJitCodeCache = NULL; 1867#endif 1868 } else { 1869 self->singleStepCount--; 1870#if defined(WITH_JIT) 1871 if ((self->singleStepCount > 0) && (self->jitResumeNPC != NULL)) { 1872 /* 1873 * Direct return to an existing translation following a 1874 * single step is valid only if we step once. If we're 1875 * here, an additional step was added so we need to invalidate 1876 * the return to translation. 1877 */ 1878 self->jitResumeNPC = NULL; 1879 self->inJitCodeCache = NULL; 1880 } 1881#endif 1882 } 1883 } 1884} 1885 1886/* 1887 * Main interpreter loop entry point. 1888 * 1889 * This begins executing code at the start of "method". On exit, "pResult" 1890 * holds the return value of the method (or, if "method" returns NULL, it 1891 * holds an undefined value). 1892 * 1893 * The interpreted stack frame, which holds the method arguments, has 1894 * already been set up. 1895 */ 1896void dvmInterpret(Thread* self, const Method* method, JValue* pResult) 1897{ 1898 InterpSaveState interpSaveState; 1899 ExecutionSubModes savedSubModes; 1900 1901#if defined(WITH_JIT) 1902 /* Target-specific save/restore */ 1903 double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT]; 1904 /* 1905 * If the previous VM left the code cache through single-stepping the 1906 * inJitCodeCache flag will be set when the VM is re-entered (for example, 1907 * in self-verification mode we single-step NEW_INSTANCE which may re-enter 1908 * the VM through findClassFromLoaderNoInit). Because of that, we cannot 1909 * assert that self->inJitCodeCache is NULL here. 1910 */ 1911#endif 1912 1913 /* 1914 * Save interpreter state from previous activation, linking 1915 * new to last. 1916 */ 1917 interpSaveState = self->interpSave; 1918 self->interpSave.prev = &interpSaveState; 1919 /* 1920 * Strip out and save any flags that should not be inherited by 1921 * nested interpreter activation. 1922 */ 1923 savedSubModes = (ExecutionSubModes)( 1924 self->interpBreak.ctl.subMode & LOCAL_SUBMODE); 1925 if (savedSubModes != kSubModeNormal) { 1926 dvmDisableSubMode(self, savedSubModes); 1927 } 1928#if defined(WITH_JIT) 1929 dvmJitCalleeSave(calleeSave); 1930#endif 1931 1932 1933#if defined(WITH_TRACKREF_CHECKS) 1934 self->interpSave.debugTrackedRefStart = 1935 dvmReferenceTableEntries(&self->internalLocalRefTable); 1936#endif 1937 self->debugIsMethodEntry = true; 1938#if defined(WITH_JIT) 1939 dvmJitCalleeSave(calleeSave); 1940 /* Initialize the state to kJitNot */ 1941 self->jitState = kJitNot; 1942#endif 1943 1944 /* 1945 * Initialize working state. 1946 * 1947 * No need to initialize "retval". 1948 */ 1949 self->interpSave.method = method; 1950 self->interpSave.curFrame = (u4*) self->interpSave.curFrame; 1951 self->interpSave.pc = method->insns; 1952 1953 assert(!dvmIsNativeMethod(method)); 1954 1955 /* 1956 * Make sure the class is ready to go. Shouldn't be possible to get 1957 * here otherwise. 1958 */ 1959 if (method->clazz->status < CLASS_INITIALIZING || 1960 method->clazz->status == CLASS_ERROR) 1961 { 1962 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n", 1963 method->clazz->descriptor, method->clazz->status); 1964 dvmDumpThread(self, false); 1965 dvmAbort(); 1966 } 1967 1968 typedef void (*Interpreter)(Thread*); 1969 Interpreter stdInterp; 1970 if (gDvm.executionMode == kExecutionModeInterpFast) 1971 stdInterp = dvmMterpStd; 1972#if defined(WITH_JIT) 1973 else if (gDvm.executionMode == kExecutionModeJit) 1974 stdInterp = dvmMterpStd; 1975#endif 1976 else 1977 stdInterp = dvmInterpretPortable; 1978 1979 // Call the interpreter 1980 (*stdInterp)(self); 1981 1982 *pResult = self->retval; 1983 1984 /* Restore interpreter state from previous activation */ 1985 self->interpSave = interpSaveState; 1986#if defined(WITH_JIT) 1987 dvmJitCalleeRestore(calleeSave); 1988#endif 1989 if (savedSubModes != kSubModeNormal) { 1990 dvmEnableSubMode(self, savedSubModes); 1991 } 1992} 1993