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