Interp.cpp revision 1813ab265f691e93401c7307c0b34247842ab35e
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(void); 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(void) 62{ 63 gDvm.breakpointSet = dvmBreakpointSetAlloc(); 64 return (gDvm.breakpointSet != NULL); 65} 66 67/* 68 * Free resources. 69 */ 70void dvmBreakpointShutdown(void) 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(void) 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(void) 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 void* fp; 541 void* prevFp = NULL; 542 543 for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) { 544 const Method* method; 545 546 saveArea = SAVEAREA_FROM_FP(fp); 547 method = saveArea->method; 548 549 if (!dvmIsBreakFrame((u4*)fp) && !dvmIsNativeMethod(method)) 550 break; 551 prevFp = fp; 552 } 553 if (fp == NULL) { 554 LOGW("Unexpected: step req in native-only threadid=%d\n", 555 thread->threadId); 556 return false; 557 } 558 if (prevFp != NULL) { 559 /* 560 * First interpreted frame wasn't the one at the bottom. Break 561 * frames are only inserted when calling from native->interp, so we 562 * don't need to worry about one being here. 563 */ 564 LOGV("##### init step while in native method\n"); 565 fp = prevFp; 566 assert(!dvmIsBreakFrame((u4*)fp)); 567 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method)); 568 saveArea = SAVEAREA_FROM_FP(fp); 569 } 570 571 /* 572 * Pull the goodies out. "xtra.currentPc" should be accurate since 573 * we update it on every instruction while the debugger is connected. 574 */ 575 pCtrl->method = saveArea->method; 576 // Clear out any old address set 577 if (pCtrl->pAddressSet != NULL) { 578 // (discard const) 579 free((void *)pCtrl->pAddressSet); 580 pCtrl->pAddressSet = NULL; 581 } 582 if (dvmIsNativeMethod(pCtrl->method)) { 583 pCtrl->line = -1; 584 } else { 585 pCtrl->line = dvmLineNumFromPC(saveArea->method, 586 saveArea->xtra.currentPc - saveArea->method->insns); 587 pCtrl->pAddressSet 588 = dvmAddressSetForLine(saveArea->method, pCtrl->line); 589 } 590 pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame); 591 pCtrl->active = true; 592 593 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n", 594 pCtrl->thread, pCtrl->method, pCtrl->method->name, 595 pCtrl->line, pCtrl->frameDepth, 596 dvmJdwpStepDepthStr(pCtrl->depth), 597 dvmJdwpStepSizeStr(pCtrl->size)); 598 599 return true; 600} 601 602/* 603 * Disable a single step event. 604 */ 605void dvmClearSingleStep(Thread* thread) 606{ 607 UNUSED_PARAMETER(thread); 608 609 gDvm.stepControl.active = false; 610} 611 612/* 613 * The interpreter just threw. Handle any special subMode requirements. 614 * All interpSave state must be valid on entry. 615 */ 616void dvmReportExceptionThrow(Thread* self, Object* exception) 617{ 618 const Method* curMethod = self->interpSave.method; 619#if defined(WITH_JIT) 620 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 621 dvmJitEndTraceSelect(self, self->interpSave.pc); 622 } 623 if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) { 624 /* Discard any single-step native returns to translation */ 625 self->jitResumeNPC = NULL; 626 } 627#endif 628 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 629 void *catchFrame; 630 int offset = self->interpSave.pc - curMethod->insns; 631 int catchRelPc = dvmFindCatchBlock(self, offset, exception, 632 true, &catchFrame); 633 dvmDbgPostException(self->interpSave.fp, offset, catchFrame, 634 catchRelPc, exception); 635 } 636} 637 638/* 639 * The interpreter is preparing to do an invoke (both native & normal). 640 * Handle any special subMode requirements. All interpSave state 641 * must be valid on entry. 642 */ 643void dvmReportInvoke(Thread* self, const Method* methodToCall) 644{ 645 TRACE_METHOD_ENTER(self, methodToCall); 646} 647 648/* 649 * The interpreter is preparing to do a native invoke. Handle any 650 * special subMode requirements. NOTE: for a native invoke, 651 * dvmReportInvoke() and dvmReportPreNativeInvoke() will both 652 * be called prior to the invoke. All interpSave state must 653 * be valid on entry. 654 */ 655void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self) 656{ 657#if defined(WITH_JIT) 658 /* 659 * Actively building a trace? If so, end it now. The trace 660 * builder can't follow into or through a native method. 661 */ 662 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 663 dvmCheckJit(self->interpSave.pc, self); 664 } 665#endif 666 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 667 Object* thisPtr = dvmGetThisPtr(self->interpSave.method, 668 self->interpSave.fp); 669 assert(thisPtr == NULL || dvmIsValidObject(thisPtr)); 670 dvmDbgPostLocationEvent(methodToCall, -1, thisPtr, DBG_METHOD_ENTRY); 671 } 672} 673 674/* 675 * The interpreter has returned from a native invoke. Handle any 676 * special subMode requirements. All interpSave state must be 677 * valid on entry. 678 */ 679void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self) 680{ 681 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 682 Object* thisPtr = dvmGetThisPtr(self->interpSave.method, 683 self->interpSave.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.fp) && 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. If there is an active break when 1499 * we're done, set altHandlerTable. Otherwise, revert to 1500 * the non-breaking table base. 1501 */ 1502void dvmUpdateInterpBreak(Thread* thread, int newBreak, int newMode, 1503 bool enable) 1504{ 1505 InterpBreak oldValue, newValue; 1506 1507 // Do not use this routine for suspend updates. See below. 1508 assert((newBreak & kInterpSuspendBreak) == 0); 1509 1510 do { 1511 oldValue = newValue = thread->interpBreak; 1512 if (enable) { 1513 newValue.ctl.breakFlags |= newBreak; 1514 newValue.ctl.subMode |= newMode; 1515 } else { 1516 newValue.ctl.breakFlags &= ~newBreak; 1517 newValue.ctl.subMode &= ~newMode; 1518 } 1519 newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ? 1520 thread->altHandlerTable : thread->mainHandlerTable; 1521 } while (dvmQuasiAtomicCas64(oldValue.all, newValue.all, 1522 &thread->interpBreak.all) != 0); 1523} 1524 1525/* 1526 * Update the normal and debugger suspend counts for a thread. 1527 * threadSuspendCount must be acquired before calling this to 1528 * ensure a clean update of suspendCount, dbgSuspendCount and 1529 * sumThreadSuspendCount. suspendCount & dbgSuspendCount must 1530 * use the atomic update to avoid conflict with writes to the 1531 * other fields in interpBreak. 1532 * 1533 * CLEANUP TODO: Currently only the JIT is using sumThreadSuspendCount. 1534 * Move under WITH_JIT ifdefs. 1535*/ 1536void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta) 1537{ 1538 InterpBreak oldValue, newValue; 1539 1540 do { 1541 oldValue = newValue = thread->interpBreak; 1542 newValue.ctl.suspendCount += delta; 1543 newValue.ctl.dbgSuspendCount += dbgDelta; 1544 assert(newValue.ctl.suspendCount >= newValue.ctl.dbgSuspendCount); 1545 if (newValue.ctl.suspendCount > 0) { 1546 newValue.ctl.breakFlags |= kInterpSuspendBreak; 1547 } else { 1548 newValue.ctl.breakFlags &= ~kInterpSuspendBreak; 1549 } 1550 newValue.ctl.curHandlerTable = (newValue.ctl.breakFlags) ? 1551 thread->altHandlerTable : thread->mainHandlerTable; 1552 } while (dvmQuasiAtomicCas64(oldValue.all, newValue.all, 1553 &thread->interpBreak.all) != 0); 1554 1555 // Update the global suspend count total 1556 gDvm.sumThreadSuspendCount += delta; 1557} 1558 1559/* 1560 * Update interpBreak for all threads. 1561 */ 1562void dvmUpdateAllInterpBreak(int newBreak, int newMode, bool enable) 1563{ 1564 Thread* self = dvmThreadSelf(); 1565 Thread* thread; 1566 1567 dvmLockThreadList(self); 1568 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 1569 dvmUpdateInterpBreak(thread, newBreak, newMode, enable); 1570 } 1571 dvmUnlockThreadList(); 1572} 1573 1574/* 1575 * Do a sanity check on interpreter state saved to Thread. 1576 * A failure here doesn't necessarily mean that something is wrong, 1577 * so this code should only be used during development to suggest 1578 * a possible problem. 1579 */ 1580void dvmCheckInterpStateConsistency() 1581{ 1582 Thread* self = dvmThreadSelf(); 1583 Thread* thread; 1584 uint8_t breakFlags; 1585 uint8_t subMode; 1586 void* handlerTable; 1587 1588 dvmLockThreadList(self); 1589 breakFlags = self->interpBreak.ctl.breakFlags; 1590 subMode = self->interpBreak.ctl.subMode; 1591 handlerTable = self->interpBreak.ctl.curHandlerTable; 1592 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 1593 if (subMode != thread->interpBreak.ctl.subMode) { 1594 LOGD("Warning: subMode mismatch - 0x%x:0x%x, tid[%d]", 1595 subMode,thread->interpBreak.ctl.subMode,thread->threadId); 1596 } 1597 if (breakFlags != thread->interpBreak.ctl.breakFlags) { 1598 LOGD("Warning: breakFlags mismatch - 0x%x:0x%x, tid[%d]", 1599 breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId); 1600 } 1601 if (handlerTable != thread->interpBreak.ctl.curHandlerTable) { 1602 LOGD("Warning: curHandlerTable mismatch - 0x%x:0x%x, tid[%d]", 1603 (int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable, 1604 thread->threadId); 1605 } 1606#if defined(WITH_JIT) 1607 if (thread->pJitProfTable != gDvmJit.pProfTable) { 1608 LOGD("Warning: pJitProfTable mismatch - 0x%x:0x%x, tid[%d]", 1609 (int)thread->pJitProfTable,(int)gDvmJit.pProfTable, 1610 thread->threadId); 1611 } 1612 if (thread->jitThreshold != gDvmJit.threshold) { 1613 LOGD("Warning: jitThreshold mismatch - 0x%x:0x%x, tid[%d]", 1614 (int)thread->jitThreshold,(int)gDvmJit.threshold, 1615 thread->threadId); 1616 } 1617#endif 1618 } 1619 dvmUnlockThreadList(); 1620} 1621 1622/* 1623 * Arm a safepoint callback for a thread. If funct is null, 1624 * clear any pending callback. 1625 * TODO: only gc is currently using this feature, and will have 1626 * at most a single outstanding callback request. Until we need 1627 * something more capable and flexible, enforce this limit. 1628 */ 1629void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct, 1630 void* arg) 1631{ 1632 dvmLockMutex(&thread->callbackMutex); 1633 if ((funct == NULL) || (thread->callback == NULL)) { 1634 thread->callback = funct; 1635 thread->callbackArg = arg; 1636 dvmUpdateInterpBreak(thread, kInterpSafePointCallback, 1637 kSubModeNormal, (funct != NULL)); 1638 } else { 1639 // Already armed. Different? 1640 if ((funct != thread->callback) || 1641 (arg != thread->callbackArg)) { 1642 // Yes - report failure and die 1643 LOGE("ArmSafePointCallback failed, thread %d", thread->threadId); 1644 dvmUnlockMutex(&thread->callbackMutex); 1645 dvmAbort(); 1646 } 1647 } 1648 dvmUnlockMutex(&thread->callbackMutex); 1649} 1650 1651/* 1652 * One-time initialization at thread creation. Here we initialize 1653 * useful constants. 1654 */ 1655void dvmInitInterpreterState(Thread* self) 1656{ 1657#if defined(WITH_JIT) 1658 /* 1659 * Reserve a static entity here to quickly setup runtime contents as 1660 * gcc will issue block copy instructions. 1661 */ 1662 static struct JitToInterpEntries jitToInterpEntries = { 1663 dvmJitToInterpNormal, 1664 dvmJitToInterpNoChain, 1665 dvmJitToInterpPunt, 1666 dvmJitToInterpSingleStep, 1667 dvmJitToInterpTraceSelect, 1668#if defined(WITH_SELF_VERIFICATION) 1669 dvmJitToInterpBackwardBranch, 1670#else 1671 NULL, 1672#endif 1673 }; 1674#endif 1675 1676 // Begin initialization 1677 self->cardTable = gDvm.biasedCardTableBase; 1678#if defined(WITH_JIT) 1679 // One-time initializations 1680 self->jitToInterpEntries = jitToInterpEntries; 1681 self->icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN; 1682 self->pProfileCountdown = &gDvmJit.profileCountdown; 1683 // Jit state that can change 1684 dvmJitUpdateThreadStateSingle(self); 1685#endif 1686} 1687 1688/* 1689 * For a newly-created thread, we need to start off with interpBreak 1690 * set to any existing global modes. The caller must hold the 1691 * thread list lock. 1692 */ 1693void dvmInitializeInterpBreak(Thread* thread) 1694{ 1695 u1 flags = 0; 1696 u1 subModes = 0; 1697 1698 if (gDvm.instructionCountEnableCount > 0) { 1699 flags |= kInterpInstCountBreak; 1700 subModes |= kSubModeInstCounting; 1701 } 1702 if (dvmIsMethodTraceActive()) { 1703 subModes |= kSubModeMethodTrace; 1704 } 1705 if (gDvm.debuggerActive) { 1706 flags |= kInterpDebugBreak; 1707 subModes |= kSubModeDebuggerActive; 1708 } 1709 dvmUpdateInterpBreak(thread, flags, subModes, true); 1710} 1711 1712/* 1713 * Inter-instruction handler invoked in between instruction interpretations 1714 * to handle exceptional events such as debugging housekeeping, instruction 1715 * count profiling, JIT trace building, etc. Dalvik PC has been exported 1716 * prior to call, but Thread copy of dPC & fp are not current. 1717 */ 1718void dvmCheckBefore(const u2 *pc, u4 *fp, Thread* self) 1719{ 1720 const Method* method = self->interpSave.method; 1721 assert(self->interpBreak.ctl.breakFlags != 0); 1722 assert(pc >= method->insns && pc < 1723 method->insns + dvmGetMethodInsnsSize(method)); 1724 1725#if 0 1726 /* 1727 * When we hit a specific method, enable verbose instruction logging. 1728 * Sometimes it's helpful to use the debugger attach as a trigger too. 1729 */ 1730 if (*pIsMethodEntry) { 1731 static const char* cd = "Landroid/test/Arithmetic;"; 1732 static const char* mn = "shiftTest2"; 1733 static const char* sg = "()V"; 1734 1735 if (/*self->interpBreak.ctl.subMode & kSubModeDebuggerActive &&*/ 1736 strcmp(method->clazz->descriptor, cd) == 0 && 1737 strcmp(method->name, mn) == 0 && 1738 strcmp(method->shorty, sg) == 0) 1739 { 1740 LOGW("Reached %s.%s, enabling verbose mode\n", 1741 method->clazz->descriptor, method->name); 1742 android_setMinPriority(LOG_TAG"i", ANDROID_LOG_VERBOSE); 1743 dumpRegs(method, fp, true); 1744 } 1745 1746 if (!gDvm.debuggerActive) 1747 *pIsMethodEntry = false; 1748 } 1749#endif 1750 1751 /* Safe point handling */ 1752 if (self->interpBreak.ctl.suspendCount || 1753 (self->interpBreak.ctl.breakFlags & kInterpSafePointCallback)) { 1754 // Are we are a safe point? 1755 int flags; 1756 flags = dexGetFlagsFromOpcode(dexOpcodeFromCodeUnit(*pc)); 1757 if (flags & VERIFY_GC_INST_MASK) { 1758 // Yes, at a safe point. Pending callback? 1759 if (self->interpBreak.ctl.breakFlags & kInterpSafePointCallback) { 1760 SafePointCallback callback; 1761 void* arg; 1762 // Get consistent funct/arg pair 1763 dvmLockMutex(&self->callbackMutex); 1764 callback = self->callback; 1765 arg = self->callbackArg; 1766 dvmUnlockMutex(&self->callbackMutex); 1767 // Update Thread structure 1768 self->interpSave.pc = pc; 1769 self->interpSave.fp = fp; 1770 if (callback != NULL) { 1771 // Do the callback 1772 if (!callback(self,arg)) { 1773 // disarm 1774 dvmArmSafePointCallback(self, NULL, NULL); 1775 } 1776 } 1777 } 1778 // Need to suspend? 1779 if (self->interpBreak.ctl.suspendCount) { 1780 dvmExportPC(pc, fp); 1781 dvmCheckSuspendPending(self); 1782 } 1783 } 1784 } 1785 1786 if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { 1787 updateDebugger(method, pc, fp, self); 1788 } 1789 if (gDvm.instructionCountEnableCount != 0) { 1790 /* 1791 * Count up the #of executed instructions. This isn't synchronized 1792 * for thread-safety; if we need that we should make this 1793 * thread-local and merge counts into the global area when threads 1794 * exit (perhaps suspending all other threads GC-style and pulling 1795 * the data out of them). 1796 */ 1797 gDvm.executedInstrCounts[GET_OPCODE(*pc)]++; 1798 } 1799 1800 1801#if defined(WITH_TRACKREF_CHECKS) 1802 dvmInterpCheckTrackedRefs(self, method, 1803 self->interpSave.debugTrackedRefStart); 1804#endif 1805 1806#if defined(WITH_JIT) 1807 // Does the JIT need anything done now? 1808 if (self->interpBreak.ctl.breakFlags & kInterpJitBreak) { 1809 // Are we building a trace? 1810 if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) { 1811 dvmCheckJit(pc, self); 1812 } 1813 1814#if defined(WITH_SELF_VERIFICATION) 1815 // Are we replaying a trace? 1816 if (self->interpBreak.ctl.subMode & kSubModeJitSV) { 1817 dvmCheckSelfVerification(pc, self); 1818 } 1819#endif 1820 } 1821#endif 1822 1823 /* 1824 * SingleStep processing. NOTE: must be the last here to allow 1825 * preceeding special case handler to manipulate single-step count. 1826 */ 1827 if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) { 1828 if (self->singleStepCount == 0) { 1829 // We've exhausted our single step count 1830 dvmUpdateInterpBreak(self, kInterpSingleStep, kSubModeNormal, 1831 false /* remove */); 1832#if defined(WITH_JIT) 1833#if 0 1834 /* 1835 * For debugging. If jitResumeDPC is non-zero, then 1836 * we expect to return to a trace in progress. There 1837 * are valid reasons why we wouldn't (such as an exception 1838 * throw), but here we can keep track. 1839 */ 1840 if (self->jitResumeDPC != NULL) { 1841 if (self->jitResumeDPC == pc) { 1842 if (self->jitResumeNPC != NULL) { 1843 LOGD("SS return to trace - pc:0x%x to 0x:%x", 1844 (int)pc, (int)self->jitResumeNPC); 1845 } else { 1846 LOGD("SS return to interp - pc:0x%x",(int)pc); 1847 } 1848 } else { 1849 LOGD("SS failed to return. Expected 0x%x, now at 0x%x", 1850 (int)self->jitResumeDPC, (int)pc); 1851 } 1852 } 1853#endif 1854 // If we've got a native return and no other reasons to 1855 // remain in singlestep/break mode, do a long jump 1856 if (self->jitResumeNPC != NULL && 1857 self->interpBreak.ctl.breakFlags == 0) { 1858 assert(self->jitResumeDPC == pc); 1859 self->jitResumeDPC = NULL; 1860 dvmJitResumeTranslation(self, pc, fp); 1861 // Doesn't return 1862 dvmAbort(); 1863 } 1864 self->jitResumeDPC = NULL; 1865 self->inJitCodeCache = NULL; 1866#endif 1867 } else { 1868 self->singleStepCount--; 1869#if defined(WITH_JIT) 1870 if ((self->singleStepCount > 0) && (self->jitResumeNPC != NULL)) { 1871 /* 1872 * Direct return to an existing translation following a 1873 * single step is valid only if we step once. If we're 1874 * here, an additional step was added so we need to invalidate 1875 * the return to translation. 1876 */ 1877 self->jitResumeNPC = NULL; 1878 self->inJitCodeCache = NULL; 1879 } 1880#endif 1881 } 1882 } 1883} 1884 1885/* 1886 * Main interpreter loop entry point. 1887 * 1888 * This begins executing code at the start of "method". On exit, "pResult" 1889 * holds the return value of the method (or, if "method" returns NULL, it 1890 * holds an undefined value). 1891 * 1892 * The interpreted stack frame, which holds the method arguments, has 1893 * already been set up. 1894 */ 1895void dvmInterpret(Thread* self, const Method* method, JValue* pResult) 1896{ 1897 InterpSaveState interpSaveState; 1898 int savedBreakFlags; 1899 int 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 savedBreakFlags = self->interpBreak.ctl.breakFlags & LOCAL_BREAKFLAGS; 1924 savedSubModes = self->interpBreak.ctl.subMode & LOCAL_SUBMODE; 1925 if (savedBreakFlags | savedSubModes) { 1926 dvmUpdateInterpBreak(self, savedBreakFlags, savedSubModes, 1927 false /*disable*/); 1928 } 1929#if defined(WITH_JIT) 1930 dvmJitCalleeSave(calleeSave); 1931#endif 1932 1933 1934#if defined(WITH_TRACKREF_CHECKS) 1935 self->interpSave.debugTrackedRefStart = 1936 dvmReferenceTableEntries(&self->internalLocalRefTable); 1937#endif 1938 self->debugIsMethodEntry = true; 1939#if defined(WITH_JIT) 1940 dvmJitCalleeSave(calleeSave); 1941 /* Initialize the state to kJitNot */ 1942 self->jitState = kJitNot; 1943#endif 1944 1945 /* 1946 * Initialize working state. 1947 * 1948 * No need to initialize "retval". 1949 */ 1950 self->interpSave.method = method; 1951 self->interpSave.fp = (u4*) self->curFrame; 1952 self->interpSave.pc = method->insns; 1953 1954 assert(!dvmIsNativeMethod(method)); 1955 1956 /* 1957 * Make sure the class is ready to go. Shouldn't be possible to get 1958 * here otherwise. 1959 */ 1960 if (method->clazz->status < CLASS_INITIALIZING || 1961 method->clazz->status == CLASS_ERROR) 1962 { 1963 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n", 1964 method->clazz->descriptor, method->clazz->status); 1965 dvmDumpThread(self, false); 1966 dvmAbort(); 1967 } 1968 1969 typedef void (*Interpreter)(Thread*); 1970 Interpreter stdInterp; 1971 if (gDvm.executionMode == kExecutionModeInterpFast) 1972 stdInterp = dvmMterpStd; 1973#if defined(WITH_JIT) 1974 else if (gDvm.executionMode == kExecutionModeJit) 1975 stdInterp = dvmMterpStd; 1976#endif 1977 else 1978 stdInterp = dvmInterpretPortable; 1979 1980 // Call the interpreter 1981 (*stdInterp)(self); 1982 1983 *pResult = self->retval; 1984 1985 /* Restore interpreter state from previous activation */ 1986 self->interpSave = interpSaveState; 1987#if defined(WITH_JIT) 1988 dvmJitCalleeRestore(calleeSave); 1989#endif 1990 if (savedBreakFlags | savedSubModes) { 1991 dvmUpdateInterpBreak(self, savedBreakFlags, savedSubModes, 1992 true /*enable*/); 1993 } 1994} 1995