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. Ideally their 25 * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that 26 * aggressive in other parts of the code yet. 27 */ 28 #include "Dalvik.h" 29 #include "interp/InterpDefs.h" 30 31 32 /* 33 * =========================================================================== 34 * Debugger support 35 * =========================================================================== 36 */ 37 38 // fwd 39 static BreakpointSet* dvmBreakpointSetAlloc(void); 40 static void dvmBreakpointSetFree(BreakpointSet* pSet); 41 42 /* 43 * Initialize global breakpoint structures. 44 */ 45 bool dvmBreakpointStartup(void) 46 { 47 #ifdef WITH_DEBUGGER 48 gDvm.breakpointSet = dvmBreakpointSetAlloc(); 49 return (gDvm.breakpointSet != NULL); 50 #else 51 return true; 52 #endif 53 } 54 55 /* 56 * Free resources. 57 */ 58 void dvmBreakpointShutdown(void) 59 { 60 #ifdef WITH_DEBUGGER 61 dvmBreakpointSetFree(gDvm.breakpointSet); 62 #endif 63 } 64 65 66 #ifdef WITH_DEBUGGER 67 /* 68 * This represents a breakpoint inserted in the instruction stream. 69 * 70 * The debugger may ask us to create the same breakpoint multiple times. 71 * We only remove the breakpoint when the last instance is cleared. 72 */ 73 typedef struct { 74 Method* method; /* method we're associated with */ 75 u2* addr; /* absolute memory address */ 76 u1 originalOpCode; /* original 8-bit opcode value */ 77 int setCount; /* #of times this breakpoint was set */ 78 } Breakpoint; 79 80 /* 81 * Set of breakpoints. 82 */ 83 struct BreakpointSet { 84 /* grab lock before reading or writing anything else in here */ 85 pthread_mutex_t lock; 86 87 /* vector of breakpoint structures */ 88 int alloc; 89 int count; 90 Breakpoint* breakpoints; 91 }; 92 93 /* 94 * Initialize a BreakpointSet. Initially empty. 95 */ 96 static BreakpointSet* dvmBreakpointSetAlloc(void) 97 { 98 BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet)); 99 100 dvmInitMutex(&pSet->lock); 101 /* leave the rest zeroed -- will alloc on first use */ 102 103 return pSet; 104 } 105 106 /* 107 * Free storage associated with a BreakpointSet. 108 */ 109 static void dvmBreakpointSetFree(BreakpointSet* pSet) 110 { 111 if (pSet == NULL) 112 return; 113 114 free(pSet->breakpoints); 115 free(pSet); 116 } 117 118 /* 119 * Lock the breakpoint set. 120 * 121 * It's not currently necessary to switch to VMWAIT in the event of 122 * contention, because nothing in here can block. However, it's possible 123 * that the bytecode-updater code could become fancier in the future, so 124 * we do the trylock dance as a bit of future-proofing. 125 */ 126 static void dvmBreakpointSetLock(BreakpointSet* pSet) 127 { 128 if (dvmTryLockMutex(&pSet->lock) != 0) { 129 Thread* self = dvmThreadSelf(); 130 int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); 131 dvmLockMutex(&pSet->lock); 132 dvmChangeStatus(self, oldStatus); 133 } 134 } 135 136 /* 137 * Unlock the breakpoint set. 138 */ 139 static void dvmBreakpointSetUnlock(BreakpointSet* pSet) 140 { 141 dvmUnlockMutex(&pSet->lock); 142 } 143 144 /* 145 * Return the #of breakpoints. 146 */ 147 static int dvmBreakpointSetCount(const BreakpointSet* pSet) 148 { 149 return pSet->count; 150 } 151 152 /* 153 * See if we already have an entry for this address. 154 * 155 * The BreakpointSet's lock must be acquired before calling here. 156 * 157 * Returns the index of the breakpoint entry, or -1 if not found. 158 */ 159 static int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr) 160 { 161 int i; 162 163 for (i = 0; i < pSet->count; i++) { 164 Breakpoint* pBreak = &pSet->breakpoints[i]; 165 if (pBreak->addr == addr) 166 return i; 167 } 168 169 return -1; 170 } 171 172 /* 173 * Retrieve the opcode that was originally at the specified location. 174 * 175 * The BreakpointSet's lock must be acquired before calling here. 176 * 177 * Returns "true" with the opcode in *pOrig on success. 178 */ 179 static bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet, 180 const u2* addr, u1* pOrig) 181 { 182 int idx = dvmBreakpointSetFind(pSet, addr); 183 if (idx < 0) 184 return false; 185 186 *pOrig = pSet->breakpoints[idx].originalOpCode; 187 return true; 188 } 189 190 /* 191 * Check the opcode. If it's a "magic" NOP, indicating the start of 192 * switch or array data in the instruction stream, we don't want to set 193 * a breakpoint. 194 * 195 * This can happen because the line number information dx generates 196 * associates the switch data with the switch statement's line number, 197 * and some debuggers put breakpoints at every address associated with 198 * a given line. The result is that the breakpoint stomps on the NOP 199 * instruction that doubles as a data table magic number, and an explicit 200 * check in the interpreter results in an exception being thrown. 201 * 202 * We don't want to simply refuse to add the breakpoint to the table, 203 * because that confuses the housekeeping. We don't want to reject the 204 * debugger's event request, and we want to be sure that there's exactly 205 * one un-set operation for every set op. 206 */ 207 static bool instructionIsMagicNop(const u2* addr) 208 { 209 u2 curVal = *addr; 210 return ((curVal & 0xff) == OP_NOP && (curVal >> 8) != 0); 211 } 212 213 /* 214 * Add a breakpoint at a specific address. If the address is already 215 * present in the table, this just increments the count. 216 * 217 * For a new entry, this will extract and preserve the current opcode from 218 * the instruction stream, and replace it with a breakpoint opcode. 219 * 220 * The BreakpointSet's lock must be acquired before calling here. 221 * 222 * Returns "true" on success. 223 */ 224 static bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method, 225 unsigned int instrOffset) 226 { 227 const int kBreakpointGrowth = 10; 228 const u2* addr = method->insns + instrOffset; 229 int idx = dvmBreakpointSetFind(pSet, addr); 230 Breakpoint* pBreak; 231 232 if (idx < 0) { 233 if (pSet->count == pSet->alloc) { 234 int newSize = pSet->alloc + kBreakpointGrowth; 235 Breakpoint* newVec; 236 237 LOGV("+++ increasing breakpoint set size to %d\n", newSize); 238 239 /* pSet->breakpoints will be NULL on first entry */ 240 newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint)); 241 if (newVec == NULL) 242 return false; 243 244 pSet->breakpoints = newVec; 245 pSet->alloc = newSize; 246 } 247 248 pBreak = &pSet->breakpoints[pSet->count++]; 249 pBreak->method = method; 250 pBreak->addr = (u2*)addr; 251 pBreak->originalOpCode = *(u1*)addr; 252 pBreak->setCount = 1; 253 254 /* 255 * Change the opcode. We must ensure that the BreakpointSet 256 * updates happen before we change the opcode. 257 * 258 * If the method has not been verified, we do NOT insert the 259 * breakpoint yet, since that will screw up the verifier. The 260 * debugger is allowed to insert breakpoints in unverified code, 261 * but since we don't execute unverified code we don't need to 262 * alter the bytecode yet. 263 * 264 * The class init code will "flush" all relevant breakpoints when 265 * verification completes. 266 */ 267 MEM_BARRIER(); 268 assert(*(u1*)addr != OP_BREAKPOINT); 269 if (dvmIsClassVerified(method->clazz)) { 270 LOGV("Class %s verified, adding breakpoint at %p\n", 271 method->clazz->descriptor, addr); 272 if (instructionIsMagicNop(addr)) { 273 LOGV("Refusing to set breakpoint on %04x at %s.%s + 0x%x\n", 274 *addr, method->clazz->descriptor, method->name, 275 instrOffset); 276 } else { 277 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 278 OP_BREAKPOINT); 279 } 280 } else { 281 LOGV("Class %s NOT verified, deferring breakpoint at %p\n", 282 method->clazz->descriptor, addr); 283 } 284 } else { 285 pBreak = &pSet->breakpoints[idx]; 286 pBreak->setCount++; 287 288 /* 289 * Instruction stream may not have breakpoint opcode yet -- flush 290 * may be pending during verification of class. 291 */ 292 //assert(*(u1*)addr == OP_BREAKPOINT); 293 } 294 295 return true; 296 } 297 298 /* 299 * Remove one instance of the specified breakpoint. When the count 300 * reaches zero, the entry is removed from the table, and the original 301 * opcode is restored. 302 * 303 * The BreakpointSet's lock must be acquired before calling here. 304 */ 305 static void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method, 306 unsigned int instrOffset) 307 { 308 const u2* addr = method->insns + instrOffset; 309 int idx = dvmBreakpointSetFind(pSet, addr); 310 311 if (idx < 0) { 312 /* breakpoint not found in set -- unexpected */ 313 if (*(u1*)addr == OP_BREAKPOINT) { 314 LOGE("Unable to restore breakpoint opcode (%s.%s +0x%x)\n", 315 method->clazz->descriptor, method->name, instrOffset); 316 dvmAbort(); 317 } else { 318 LOGW("Breakpoint was already restored? (%s.%s +0x%x)\n", 319 method->clazz->descriptor, method->name, instrOffset); 320 } 321 } else { 322 Breakpoint* pBreak = &pSet->breakpoints[idx]; 323 if (pBreak->setCount == 1) { 324 /* 325 * Must restore opcode before removing set entry. 326 * 327 * If the breakpoint was never flushed, we could be ovewriting 328 * a value with the same value. Not a problem, though we 329 * could end up causing a copy-on-write here when we didn't 330 * need to. (Not worth worrying about.) 331 */ 332 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, 333 pBreak->originalOpCode); 334 MEM_BARRIER(); 335 336 if (idx != pSet->count-1) { 337 /* shift down */ 338 memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1], 339 (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0])); 340 } 341 pSet->count--; 342 pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug 343 } else { 344 pBreak->setCount--; 345 assert(pBreak->setCount > 0); 346 } 347 } 348 } 349 350 /* 351 * Flush any breakpoints associated with methods in "clazz". We want to 352 * change the opcode, which might not have happened when the breakpoint 353 * was initially set because the class was in the process of being 354 * verified. 355 * 356 * The BreakpointSet's lock must be acquired before calling here. 357 */ 358 static void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz) 359 { 360 int i; 361 for (i = 0; i < pSet->count; i++) { 362 Breakpoint* pBreak = &pSet->breakpoints[i]; 363 if (pBreak->method->clazz == clazz) { 364 /* 365 * The breakpoint is associated with a method in this class. 366 * It might already be there or it might not; either way, 367 * flush it out. 368 */ 369 LOGV("Flushing breakpoint at %p for %s\n", 370 pBreak->addr, clazz->descriptor); 371 if (instructionIsMagicNop(pBreak->addr)) { 372 const Method* method = pBreak->method; 373 LOGV("Refusing to flush breakpoint on %04x at %s.%s + 0x%x\n", 374 *pBreak->addr, method->clazz->descriptor, 375 method->name, pBreak->addr - method->insns); 376 } else { 377 dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr, 378 OP_BREAKPOINT); 379 } 380 } 381 } 382 } 383 #endif /*WITH_DEBUGGER*/ 384 385 386 /* 387 * Do any debugger-attach-time initialization. 388 */ 389 void dvmInitBreakpoints(void) 390 { 391 #ifdef WITH_DEBUGGER 392 /* quick sanity check */ 393 BreakpointSet* pSet = gDvm.breakpointSet; 394 dvmBreakpointSetLock(pSet); 395 if (dvmBreakpointSetCount(pSet) != 0) { 396 LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet)); 397 /* generally not good, but we can keep going */ 398 } 399 dvmBreakpointSetUnlock(pSet); 400 #else 401 assert(false); 402 #endif 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 */ 419 void dvmAddBreakAddr(Method* method, unsigned int instrOffset) 420 { 421 #ifdef WITH_DEBUGGER 422 BreakpointSet* pSet = gDvm.breakpointSet; 423 dvmBreakpointSetLock(pSet); 424 dvmBreakpointSetAdd(pSet, method, instrOffset); 425 dvmBreakpointSetUnlock(pSet); 426 #else 427 assert(false); 428 #endif 429 } 430 431 /* 432 * Remove an address from the list by setting the entry to NULL. 433 * 434 * This can be called from the JDWP thread (because the debugger has 435 * cancelled the breakpoint) or from an event thread (because it's a 436 * single-shot breakpoint, e.g. "run to line"). We only get here as 437 * the result of removing an entry from the event list, which is 438 * synchronized, so it should not be possible for two threads to be 439 * updating breakpoints at the same time. 440 */ 441 void dvmClearBreakAddr(Method* method, unsigned int instrOffset) 442 { 443 #ifdef WITH_DEBUGGER 444 BreakpointSet* pSet = gDvm.breakpointSet; 445 dvmBreakpointSetLock(pSet); 446 dvmBreakpointSetRemove(pSet, method, instrOffset); 447 dvmBreakpointSetUnlock(pSet); 448 449 #else 450 assert(false); 451 #endif 452 } 453 454 #ifdef WITH_DEBUGGER 455 /* 456 * Get the original opcode from under a breakpoint. 457 */ 458 u1 dvmGetOriginalOpCode(const u2* addr) 459 { 460 BreakpointSet* pSet = gDvm.breakpointSet; 461 u1 orig = 0; 462 463 dvmBreakpointSetLock(pSet); 464 if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) { 465 orig = *(u1*)addr; 466 if (orig == OP_BREAKPOINT) { 467 LOGE("GLITCH: can't find breakpoint, opcode is still set\n"); 468 dvmAbort(); 469 } 470 } 471 dvmBreakpointSetUnlock(pSet); 472 473 return orig; 474 } 475 476 /* 477 * Flush any breakpoints associated with methods in "clazz". 478 * 479 * We don't want to modify the bytecode of a method before the verifier 480 * gets a chance to look at it, so we postpone opcode replacement until 481 * after verification completes. 482 */ 483 void dvmFlushBreakpoints(ClassObject* clazz) 484 { 485 BreakpointSet* pSet = gDvm.breakpointSet; 486 487 if (pSet == NULL) 488 return; 489 490 assert(dvmIsClassVerified(clazz)); 491 dvmBreakpointSetLock(pSet); 492 dvmBreakpointSetFlush(pSet, clazz); 493 dvmBreakpointSetUnlock(pSet); 494 } 495 #endif 496 497 /* 498 * Add a single step event. Currently this is a global item. 499 * 500 * We set up some initial values based on the thread's current state. This 501 * won't work well if the thread is running, so it's up to the caller to 502 * verify that it's suspended. 503 * 504 * This is only called from the JDWP thread. 505 */ 506 bool dvmAddSingleStep(Thread* thread, int size, int depth) 507 { 508 #ifdef WITH_DEBUGGER 509 StepControl* pCtrl = &gDvm.stepControl; 510 511 if (pCtrl->active && thread != pCtrl->thread) { 512 LOGW("WARNING: single-step active for %p; adding %p\n", 513 pCtrl->thread, thread); 514 515 /* 516 * Keep going, overwriting previous. This can happen if you 517 * suspend a thread in Object.wait, hit the single-step key, then 518 * switch to another thread and do the same thing again. 519 * The first thread's step is still pending. 520 * 521 * TODO: consider making single-step per-thread. Adds to the 522 * overhead, but could be useful in rare situations. 523 */ 524 } 525 526 pCtrl->size = size; 527 pCtrl->depth = depth; 528 pCtrl->thread = thread; 529 530 /* 531 * We may be stepping into or over method calls, or running until we 532 * return from the current method. To make this work we need to track 533 * the current line, current method, and current stack depth. We need 534 * to be checking these after most instructions, notably those that 535 * call methods, return from methods, or are on a different line from the 536 * previous instruction. 537 * 538 * We have to start with a snapshot of the current state. If we're in 539 * an interpreted method, everything we need is in the current frame. If 540 * we're in a native method, possibly with some extra JNI frames pushed 541 * on by PushLocalFrame, we want to use the topmost native method. 542 */ 543 const StackSaveArea* saveArea; 544 void* fp; 545 void* prevFp = NULL; 546 547 for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) { 548 const Method* method; 549 550 saveArea = SAVEAREA_FROM_FP(fp); 551 method = saveArea->method; 552 553 if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method)) 554 break; 555 prevFp = fp; 556 } 557 if (fp == NULL) { 558 LOGW("Unexpected: step req in native-only threadid=%d\n", 559 thread->threadId); 560 return false; 561 } 562 if (prevFp != NULL) { 563 /* 564 * First interpreted frame wasn't the one at the bottom. Break 565 * frames are only inserted when calling from native->interp, so we 566 * don't need to worry about one being here. 567 */ 568 LOGV("##### init step while in native method\n"); 569 fp = prevFp; 570 assert(!dvmIsBreakFrame(fp)); 571 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method)); 572 saveArea = SAVEAREA_FROM_FP(fp); 573 } 574 575 /* 576 * Pull the goodies out. "xtra.currentPc" should be accurate since 577 * we update it on every instruction while the debugger is connected. 578 */ 579 pCtrl->method = saveArea->method; 580 // Clear out any old address set 581 if (pCtrl->pAddressSet != NULL) { 582 // (discard const) 583 free((void *)pCtrl->pAddressSet); 584 pCtrl->pAddressSet = NULL; 585 } 586 if (dvmIsNativeMethod(pCtrl->method)) { 587 pCtrl->line = -1; 588 } else { 589 pCtrl->line = dvmLineNumFromPC(saveArea->method, 590 saveArea->xtra.currentPc - saveArea->method->insns); 591 pCtrl->pAddressSet 592 = dvmAddressSetForLine(saveArea->method, pCtrl->line); 593 } 594 pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame); 595 pCtrl->active = true; 596 597 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n", 598 pCtrl->thread, pCtrl->method, pCtrl->method->name, 599 pCtrl->line, pCtrl->frameDepth, 600 dvmJdwpStepDepthStr(pCtrl->depth), 601 dvmJdwpStepSizeStr(pCtrl->size)); 602 603 return true; 604 #else 605 assert(false); 606 return false; 607 #endif 608 } 609 610 /* 611 * Disable a single step event. 612 */ 613 void dvmClearSingleStep(Thread* thread) 614 { 615 #ifdef WITH_DEBUGGER 616 UNUSED_PARAMETER(thread); 617 618 gDvm.stepControl.active = false; 619 #else 620 assert(false); 621 #endif 622 } 623 624 625 /* 626 * Recover the "this" pointer from the current interpreted method. "this" 627 * is always in "in0" for non-static methods. 628 * 629 * The "ins" start at (#of registers - #of ins). Note in0 != v0. 630 * 631 * This works because "dx" guarantees that it will work. It's probably 632 * fairly common to have a virtual method that doesn't use its "this" 633 * pointer, in which case we're potentially wasting a register. However, 634 * the debugger doesn't treat "this" as just another argument. For 635 * example, events (such as breakpoints) can be enabled for specific 636 * values of "this". There is also a separate StackFrame.ThisObject call 637 * in JDWP that is expected to work for any non-native non-static method. 638 * 639 * Because we need it when setting up debugger event filters, we want to 640 * be able to do this quickly. 641 */ 642 Object* dvmGetThisPtr(const Method* method, const u4* fp) 643 { 644 if (dvmIsStaticMethod(method)) 645 return NULL; 646 return (Object*)fp[method->registersSize - method->insSize]; 647 } 648 649 650 #if defined(WITH_TRACKREF_CHECKS) 651 /* 652 * Verify that all internally-tracked references have been released. If 653 * they haven't, print them and abort the VM. 654 * 655 * "debugTrackedRefStart" indicates how many refs were on the list when 656 * we were first invoked. 657 */ 658 void dvmInterpCheckTrackedRefs(Thread* self, const Method* method, 659 int debugTrackedRefStart) 660 { 661 if (dvmReferenceTableEntries(&self->internalLocalRefTable) 662 != (size_t) debugTrackedRefStart) 663 { 664 char* desc; 665 Object** top; 666 int count; 667 668 count = dvmReferenceTableEntries(&self->internalLocalRefTable); 669 670 LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n", 671 debugTrackedRefStart, count); 672 desc = dexProtoCopyMethodDescriptor(&method->prototype); 673 LOGE(" current method is %s.%s %s\n", method->clazz->descriptor, 674 method->name, desc); 675 free(desc); 676 top = self->internalLocalRefTable.table + debugTrackedRefStart; 677 while (top < self->internalLocalRefTable.nextEntry) { 678 LOGE(" %p (%s)\n", 679 *top, 680 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : ""); 681 top++; 682 } 683 dvmDumpThread(self, false); 684 685 dvmAbort(); 686 } 687 //LOGI("TRACK OK\n"); 688 } 689 #endif 690 691 692 #ifdef LOG_INSTR 693 /* 694 * Dump the v-registers. Sent to the ILOG log tag. 695 */ 696 void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly) 697 { 698 int i, localCount; 699 700 localCount = method->registersSize - method->insSize; 701 702 LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr); 703 for (i = method->registersSize-1; i >= 0; i--) { 704 if (i >= localCount) { 705 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n", 706 i, i-localCount, framePtr[i]); 707 } else { 708 if (inOnly) { 709 LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n"); 710 break; 711 } 712 const char* name = ""; 713 int j; 714 #if 0 // "locals" structure has changed -- need to rewrite this 715 DexFile* pDexFile = method->clazz->pDexFile; 716 const DexCode* pDexCode = dvmGetMethodCode(method); 717 int localsSize = dexGetLocalsSize(pDexFile, pDexCode); 718 const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode); 719 for (j = 0; j < localsSize, j++) { 720 if (locals[j].registerNum == (u4) i) { 721 name = dvmDexStringStr(locals[j].pName); 722 break; 723 } 724 } 725 #endif 726 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n", 727 i, framePtr[i], name); 728 } 729 } 730 } 731 #endif 732 733 734 /* 735 * =========================================================================== 736 * Entry point and general support functions 737 * =========================================================================== 738 */ 739 740 /* 741 * Construct an s4 from two consecutive half-words of switch data. 742 * This needs to check endianness because the DEX optimizer only swaps 743 * half-words in instruction stream. 744 * 745 * "switchData" must be 32-bit aligned. 746 */ 747 #if __BYTE_ORDER == __LITTLE_ENDIAN 748 static inline s4 s4FromSwitchData(const void* switchData) { 749 return *(s4*) switchData; 750 } 751 #else 752 static inline s4 s4FromSwitchData(const void* switchData) { 753 u2* data = switchData; 754 return data[0] | (((s4) data[1]) << 16); 755 } 756 #endif 757 758 /* 759 * Find the matching case. Returns the offset to the handler instructions. 760 * 761 * Returns 3 if we don't find a match (it's the size of the packed-switch 762 * instruction). 763 */ 764 s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal) 765 { 766 const int kInstrLen = 3; 767 u2 size; 768 s4 firstKey; 769 const s4* entries; 770 771 /* 772 * Packed switch data format: 773 * ushort ident = 0x0100 magic value 774 * ushort size number of entries in the table 775 * int first_key first (and lowest) switch case value 776 * int targets[size] branch targets, relative to switch opcode 777 * 778 * Total size is (4+size*2) 16-bit code units. 779 */ 780 if (*switchData++ != kPackedSwitchSignature) { 781 /* should have been caught by verifier */ 782 dvmThrowException("Ljava/lang/InternalError;", 783 "bad packed switch magic"); 784 return kInstrLen; 785 } 786 787 size = *switchData++; 788 assert(size > 0); 789 790 firstKey = *switchData++; 791 firstKey |= (*switchData++) << 16; 792 793 if (testVal < firstKey || testVal >= firstKey + size) { 794 LOGVV("Value %d not found in switch (%d-%d)\n", 795 testVal, firstKey, firstKey+size-1); 796 return kInstrLen; 797 } 798 799 /* The entries are guaranteed to be aligned on a 32-bit boundary; 800 * we can treat them as a native int array. 801 */ 802 entries = (const s4*) switchData; 803 assert(((u4)entries & 0x3) == 0); 804 805 assert(testVal - firstKey >= 0 && testVal - firstKey < size); 806 LOGVV("Value %d found in slot %d (goto 0x%02x)\n", 807 testVal, testVal - firstKey, 808 s4FromSwitchData(&entries[testVal - firstKey])); 809 return s4FromSwitchData(&entries[testVal - firstKey]); 810 } 811 812 /* 813 * Find the matching case. Returns the offset to the handler instructions. 814 * 815 * Returns 3 if we don't find a match (it's the size of the sparse-switch 816 * instruction). 817 */ 818 s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal) 819 { 820 const int kInstrLen = 3; 821 u2 ident, size; 822 const s4* keys; 823 const s4* entries; 824 825 /* 826 * Sparse switch data format: 827 * ushort ident = 0x0200 magic value 828 * ushort size number of entries in the table; > 0 829 * int keys[size] keys, sorted low-to-high; 32-bit aligned 830 * int targets[size] branch targets, relative to switch opcode 831 * 832 * Total size is (2+size*4) 16-bit code units. 833 */ 834 835 if (*switchData++ != kSparseSwitchSignature) { 836 /* should have been caught by verifier */ 837 dvmThrowException("Ljava/lang/InternalError;", 838 "bad sparse switch magic"); 839 return kInstrLen; 840 } 841 842 size = *switchData++; 843 assert(size > 0); 844 845 /* The keys are guaranteed to be aligned on a 32-bit boundary; 846 * we can treat them as a native int array. 847 */ 848 keys = (const s4*) switchData; 849 assert(((u4)keys & 0x3) == 0); 850 851 /* The entries are guaranteed to be aligned on a 32-bit boundary; 852 * we can treat them as a native int array. 853 */ 854 entries = keys + size; 855 assert(((u4)entries & 0x3) == 0); 856 857 /* 858 * Binary-search through the array of keys, which are guaranteed to 859 * be sorted low-to-high. 860 */ 861 int lo = 0; 862 int hi = size - 1; 863 while (lo <= hi) { 864 int mid = (lo + hi) >> 1; 865 866 s4 foundVal = s4FromSwitchData(&keys[mid]); 867 if (testVal < foundVal) { 868 hi = mid - 1; 869 } else if (testVal > foundVal) { 870 lo = mid + 1; 871 } else { 872 LOGVV("Value %d found in entry %d (goto 0x%02x)\n", 873 testVal, mid, s4FromSwitchData(&entries[mid])); 874 return s4FromSwitchData(&entries[mid]); 875 } 876 } 877 878 LOGVV("Value %d not found in switch\n", testVal); 879 return kInstrLen; 880 } 881 882 /* 883 * Copy data for a fill-array-data instruction. On a little-endian machine 884 * we can just do a memcpy(), on a big-endian system we have work to do. 885 * 886 * The trick here is that dexopt has byte-swapped each code unit, which is 887 * exactly what we want for short/char data. For byte data we need to undo 888 * the swap, and for 4- or 8-byte values we need to swap pieces within 889 * each word. 890 */ 891 static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width) 892 { 893 #if __BYTE_ORDER == __LITTLE_ENDIAN 894 memcpy(dest, src, size*width); 895 #else 896 int i; 897 898 switch (width) { 899 case 1: 900 /* un-swap pairs of bytes as we go */ 901 for (i = (size-1) & ~1; i >= 0; i -= 2) { 902 ((u1*)dest)[i] = ((u1*)src)[i+1]; 903 ((u1*)dest)[i+1] = ((u1*)src)[i]; 904 } 905 /* 906 * "src" is padded to end on a two-byte boundary, but we don't want to 907 * assume "dest" is, so we handle odd length specially. 908 */ 909 if ((size & 1) != 0) { 910 ((u1*)dest)[size-1] = ((u1*)src)[size]; 911 } 912 break; 913 case 2: 914 /* already swapped correctly */ 915 memcpy(dest, src, size*width); 916 break; 917 case 4: 918 /* swap word halves */ 919 for (i = 0; i < (int) size; i++) { 920 ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1]; 921 } 922 break; 923 case 8: 924 /* swap word halves and words */ 925 for (i = 0; i < (int) (size << 1); i += 2) { 926 ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2]; 927 ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1]; 928 } 929 break; 930 default: 931 LOGE("Unexpected width %d in copySwappedArrayData\n", width); 932 dvmAbort(); 933 break; 934 } 935 #endif 936 } 937 938 /* 939 * Fill the array with predefined constant values. 940 * 941 * Returns true if job is completed, otherwise false to indicate that 942 * an exception has been thrown. 943 */ 944 bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData) 945 { 946 u2 width; 947 u4 size; 948 949 if (arrayObj == NULL) { 950 dvmThrowException("Ljava/lang/NullPointerException;", NULL); 951 return false; 952 } 953 954 /* 955 * Array data table format: 956 * ushort ident = 0x0300 magic value 957 * ushort width width of each element in the table 958 * uint size number of elements in the table 959 * ubyte data[size*width] table of data values (may contain a single-byte 960 * padding at the end) 961 * 962 * Total size is 4+(width * size + 1)/2 16-bit code units. 963 */ 964 if (arrayData[0] != kArrayDataSignature) { 965 dvmThrowException("Ljava/lang/InternalError;", "bad array data magic"); 966 return false; 967 } 968 969 width = arrayData[1]; 970 size = arrayData[2] | (((u4)arrayData[3]) << 16); 971 972 if (size > arrayObj->length) { 973 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL); 974 return false; 975 } 976 copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width); 977 return true; 978 } 979 980 /* 981 * Find the concrete method that corresponds to "methodIdx". The code in 982 * "method" is executing invoke-method with "thisClass" as its first argument. 983 * 984 * Returns NULL with an exception raised on failure. 985 */ 986 Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx, 987 const Method* method, DvmDex* methodClassDex) 988 { 989 Method* absMethod; 990 Method* methodToCall; 991 int i, vtableIndex; 992 993 /* 994 * Resolve the method. This gives us the abstract method from the 995 * interface class declaration. 996 */ 997 absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx); 998 if (absMethod == NULL) { 999 absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx); 1000 if (absMethod == NULL) { 1001 LOGV("+ unknown method\n"); 1002 return NULL; 1003 } 1004 } 1005 1006 /* make sure absMethod->methodIndex means what we think it means */ 1007 assert(dvmIsAbstractMethod(absMethod)); 1008 1009 /* 1010 * Run through the "this" object's iftable. Find the entry for 1011 * absMethod's class, then use absMethod->methodIndex to find 1012 * the method's entry. The value there is the offset into our 1013 * vtable of the actual method to execute. 1014 * 1015 * The verifier does not guarantee that objects stored into 1016 * interface references actually implement the interface, so this 1017 * check cannot be eliminated. 1018 */ 1019 for (i = 0; i < thisClass->iftableCount; i++) { 1020 if (thisClass->iftable[i].clazz == absMethod->clazz) 1021 break; 1022 } 1023 if (i == thisClass->iftableCount) { 1024 /* impossible in verified DEX, need to check for it in unverified */ 1025 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;", 1026 "interface not implemented"); 1027 return NULL; 1028 } 1029 1030 assert(absMethod->methodIndex < 1031 thisClass->iftable[i].clazz->virtualMethodCount); 1032 1033 vtableIndex = 1034 thisClass->iftable[i].methodIndexArray[absMethod->methodIndex]; 1035 assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount); 1036 methodToCall = thisClass->vtable[vtableIndex]; 1037 1038 #if 0 1039 /* this can happen when there's a stale class file */ 1040 if (dvmIsAbstractMethod(methodToCall)) { 1041 dvmThrowException("Ljava/lang/AbstractMethodError;", 1042 "interface method not implemented"); 1043 return NULL; 1044 } 1045 #else 1046 assert(!dvmIsAbstractMethod(methodToCall) || 1047 methodToCall->nativeFunc != NULL); 1048 #endif 1049 1050 LOGVV("+++ interface=%s.%s concrete=%s.%s\n", 1051 absMethod->clazz->descriptor, absMethod->name, 1052 methodToCall->clazz->descriptor, methodToCall->name); 1053 assert(methodToCall != NULL); 1054 1055 return methodToCall; 1056 } 1057 1058 1059 1060 /* 1061 * Helpers for dvmThrowVerificationError(). 1062 * 1063 * Each returns a newly-allocated string. 1064 */ 1065 #define kThrowShow_accessFromClass 1 1066 static char* classNameFromIndex(const Method* method, int ref, 1067 VerifyErrorRefType refType, int flags) 1068 { 1069 static const int kBufLen = 256; 1070 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1071 1072 if (refType == VERIFY_ERROR_REF_FIELD) { 1073 /* get class ID from field ID */ 1074 const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1075 ref = pFieldId->classIdx; 1076 } else if (refType == VERIFY_ERROR_REF_METHOD) { 1077 /* get class ID from method ID */ 1078 const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1079 ref = pMethodId->classIdx; 1080 } 1081 1082 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref); 1083 char* dotClassName = dvmDescriptorToDot(className); 1084 if (flags == 0) 1085 return dotClassName; 1086 1087 char* result = (char*) malloc(kBufLen); 1088 1089 if ((flags & kThrowShow_accessFromClass) != 0) { 1090 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1091 snprintf(result, kBufLen, "tried to access class %s from class %s", 1092 dotClassName, dotFromName); 1093 free(dotFromName); 1094 } else { 1095 assert(false); // should've been caught above 1096 result[0] = '\0'; 1097 } 1098 1099 free(dotClassName); 1100 return result; 1101 } 1102 static char* fieldNameFromIndex(const Method* method, int ref, 1103 VerifyErrorRefType refType, int flags) 1104 { 1105 static const int kBufLen = 256; 1106 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1107 const DexFieldId* pFieldId; 1108 const char* className; 1109 const char* fieldName; 1110 1111 if (refType != VERIFY_ERROR_REF_FIELD) { 1112 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType); 1113 return NULL; /* no message */ 1114 } 1115 1116 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref); 1117 className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx); 1118 fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx); 1119 1120 char* dotName = dvmDescriptorToDot(className); 1121 char* result = (char*) malloc(kBufLen); 1122 1123 if ((flags & kThrowShow_accessFromClass) != 0) { 1124 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1125 snprintf(result, kBufLen, "tried to access field %s.%s from class %s", 1126 dotName, fieldName, dotFromName); 1127 free(dotFromName); 1128 } else { 1129 snprintf(result, kBufLen, "%s.%s", dotName, fieldName); 1130 } 1131 1132 free(dotName); 1133 return result; 1134 } 1135 static char* methodNameFromIndex(const Method* method, int ref, 1136 VerifyErrorRefType refType, int flags) 1137 { 1138 static const int kBufLen = 384; 1139 const DvmDex* pDvmDex = method->clazz->pDvmDex; 1140 const DexMethodId* pMethodId; 1141 const char* className; 1142 const char* methodName; 1143 1144 if (refType != VERIFY_ERROR_REF_METHOD) { 1145 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType); 1146 return NULL; /* no message */ 1147 } 1148 1149 pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref); 1150 className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx); 1151 methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx); 1152 1153 char* dotName = dvmDescriptorToDot(className); 1154 char* result = (char*) malloc(kBufLen); 1155 1156 if ((flags & kThrowShow_accessFromClass) != 0) { 1157 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor); 1158 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1159 snprintf(result, kBufLen, 1160 "tried to access method %s.%s:%s from class %s", 1161 dotName, methodName, desc, dotFromName); 1162 free(dotFromName); 1163 free(desc); 1164 } else { 1165 snprintf(result, kBufLen, "%s.%s", dotName, methodName); 1166 } 1167 1168 free(dotName); 1169 return result; 1170 } 1171 1172 /* 1173 * Throw an exception for a problem identified by the verifier. 1174 * 1175 * This is used by the invoke-verification-error instruction. It always 1176 * throws an exception. 1177 * 1178 * "kind" indicates the kind of failure encountered by the verifier. It 1179 * has two parts, an error code and an indication of the reference type. 1180 */ 1181 void dvmThrowVerificationError(const Method* method, int kind, int ref) 1182 { 1183 const int typeMask = 0xff << kVerifyErrorRefTypeShift; 1184 VerifyError errorKind = kind & ~typeMask; 1185 VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift; 1186 const char* exceptionName = "Ljava/lang/VerifyError;"; 1187 char* msg = NULL; 1188 1189 switch ((VerifyError) errorKind) { 1190 case VERIFY_ERROR_NO_CLASS: 1191 exceptionName = "Ljava/lang/NoClassDefFoundError;"; 1192 msg = classNameFromIndex(method, ref, refType, 0); 1193 break; 1194 case VERIFY_ERROR_NO_FIELD: 1195 exceptionName = "Ljava/lang/NoSuchFieldError;"; 1196 msg = fieldNameFromIndex(method, ref, refType, 0); 1197 break; 1198 case VERIFY_ERROR_NO_METHOD: 1199 exceptionName = "Ljava/lang/NoSuchMethodError;"; 1200 msg = methodNameFromIndex(method, ref, refType, 0); 1201 break; 1202 case VERIFY_ERROR_ACCESS_CLASS: 1203 exceptionName = "Ljava/lang/IllegalAccessError;"; 1204 msg = classNameFromIndex(method, ref, refType, 1205 kThrowShow_accessFromClass); 1206 break; 1207 case VERIFY_ERROR_ACCESS_FIELD: 1208 exceptionName = "Ljava/lang/IllegalAccessError;"; 1209 msg = fieldNameFromIndex(method, ref, refType, 1210 kThrowShow_accessFromClass); 1211 break; 1212 case VERIFY_ERROR_ACCESS_METHOD: 1213 exceptionName = "Ljava/lang/IllegalAccessError;"; 1214 msg = methodNameFromIndex(method, ref, refType, 1215 kThrowShow_accessFromClass); 1216 break; 1217 case VERIFY_ERROR_CLASS_CHANGE: 1218 exceptionName = "Ljava/lang/IncompatibleClassChangeError;"; 1219 msg = classNameFromIndex(method, ref, refType, 0); 1220 break; 1221 case VERIFY_ERROR_INSTANTIATION: 1222 exceptionName = "Ljava/lang/InstantiationError;"; 1223 msg = classNameFromIndex(method, ref, refType, 0); 1224 break; 1225 1226 case VERIFY_ERROR_GENERIC: 1227 /* generic VerifyError; use default exception, no message */ 1228 break; 1229 case VERIFY_ERROR_NONE: 1230 /* should never happen; use default exception */ 1231 assert(false); 1232 msg = strdup("weird - no error specified"); 1233 break; 1234 1235 /* no default clause -- want warning if enum updated */ 1236 } 1237 1238 dvmThrowException(exceptionName, msg); 1239 free(msg); 1240 } 1241 1242 /* 1243 * Main interpreter loop entry point. Select "standard" or "debug" 1244 * interpreter and switch between them as required. 1245 * 1246 * This begins executing code at the start of "method". On exit, "pResult" 1247 * holds the return value of the method (or, if "method" returns NULL, it 1248 * holds an undefined value). 1249 * 1250 * The interpreted stack frame, which holds the method arguments, has 1251 * already been set up. 1252 */ 1253 void dvmInterpret(Thread* self, const Method* method, JValue* pResult) 1254 { 1255 InterpState interpState; 1256 bool change; 1257 #if defined(WITH_JIT) 1258 /* Target-specific save/restore */ 1259 extern void dvmJitCalleeSave(double *saveArea); 1260 extern void dvmJitCalleeRestore(double *saveArea); 1261 /* Interpreter entry points from compiled code */ 1262 extern void dvmJitToInterpNormal(); 1263 extern void dvmJitToInterpNoChain(); 1264 extern void dvmJitToInterpPunt(); 1265 extern void dvmJitToInterpSingleStep(); 1266 extern void dvmJitToInterpTraceSelectNoChain(); 1267 extern void dvmJitToInterpTraceSelect(); 1268 extern void dvmJitToPatchPredictedChain(); 1269 #if defined(WITH_SELF_VERIFICATION) 1270 extern void dvmJitToInterpBackwardBranch(); 1271 #endif 1272 1273 /* 1274 * Reserve a static entity here to quickly setup runtime contents as 1275 * gcc will issue block copy instructions. 1276 */ 1277 static struct JitToInterpEntries jitToInterpEntries = { 1278 dvmJitToInterpNormal, 1279 dvmJitToInterpNoChain, 1280 dvmJitToInterpPunt, 1281 dvmJitToInterpSingleStep, 1282 dvmJitToInterpTraceSelectNoChain, 1283 dvmJitToInterpTraceSelect, 1284 dvmJitToPatchPredictedChain, 1285 #if defined(WITH_SELF_VERIFICATION) 1286 dvmJitToInterpBackwardBranch, 1287 #endif 1288 }; 1289 1290 assert(self->inJitCodeCache == NULL); 1291 #endif 1292 1293 1294 #if defined(WITH_TRACKREF_CHECKS) 1295 interpState.debugTrackedRefStart = 1296 dvmReferenceTableEntries(&self->internalLocalRefTable); 1297 #endif 1298 #if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) 1299 interpState.debugIsMethodEntry = true; 1300 #endif 1301 #if defined(WITH_JIT) 1302 dvmJitCalleeSave(interpState.calleeSave); 1303 /* Initialize the state to kJitNot */ 1304 interpState.jitState = kJitNot; 1305 1306 /* Setup the Jit-to-interpreter entry points */ 1307 interpState.jitToInterpEntries = jitToInterpEntries; 1308 1309 /* 1310 * Initialize the threshold filter [don't bother to zero out the 1311 * actual table. We're looking for matches, and an occasional 1312 * false positive is acceptible. 1313 */ 1314 interpState.lastThreshFilter = 0; 1315 #endif 1316 1317 /* 1318 * Initialize working state. 1319 * 1320 * No need to initialize "retval". 1321 */ 1322 interpState.method = method; 1323 interpState.fp = (u4*) self->curFrame; 1324 interpState.pc = method->insns; 1325 interpState.entryPoint = kInterpEntryInstr; 1326 1327 if (dvmDebuggerOrProfilerActive()) 1328 interpState.nextMode = INTERP_DBG; 1329 else 1330 interpState.nextMode = INTERP_STD; 1331 1332 assert(!dvmIsNativeMethod(method)); 1333 1334 /* 1335 * Make sure the class is ready to go. Shouldn't be possible to get 1336 * here otherwise. 1337 */ 1338 if (method->clazz->status < CLASS_INITIALIZING || 1339 method->clazz->status == CLASS_ERROR) 1340 { 1341 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n", 1342 method->clazz->descriptor, method->clazz->status); 1343 dvmDumpThread(self, false); 1344 dvmAbort(); 1345 } 1346 1347 typedef bool (*Interpreter)(Thread*, InterpState*); 1348 Interpreter stdInterp; 1349 if (gDvm.executionMode == kExecutionModeInterpFast) 1350 stdInterp = dvmMterpStd; 1351 #if defined(WITH_JIT) 1352 else if (gDvm.executionMode == kExecutionModeJit) 1353 /* If profiling overhead can be kept low enough, we can use a profiling 1354 * mterp fast for both Jit and "fast" modes. If overhead is too high, 1355 * create a specialized profiling interpreter. 1356 */ 1357 stdInterp = dvmMterpStd; 1358 #endif 1359 else 1360 stdInterp = dvmInterpretStd; 1361 1362 change = true; 1363 while (change) { 1364 switch (interpState.nextMode) { 1365 case INTERP_STD: 1366 LOGVV("threadid=%d: interp STD\n", self->threadId); 1367 change = (*stdInterp)(self, &interpState); 1368 break; 1369 #if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT) 1370 case INTERP_DBG: 1371 LOGVV("threadid=%d: interp DBG\n", self->threadId); 1372 change = dvmInterpretDbg(self, &interpState); 1373 break; 1374 #endif 1375 default: 1376 dvmAbort(); 1377 } 1378 } 1379 1380 *pResult = interpState.retval; 1381 #if defined(WITH_JIT) 1382 dvmJitCalleeRestore(interpState.calleeSave); 1383 #endif 1384 } 1385