1/* 2 * C footer. This has some common code shared by the various targets. 3 */ 4 5/* 6 * Everything from here on is a "goto target". In the basic interpreter 7 * we jump into these targets and then jump directly to the handler for 8 * next instruction. Here, these are subroutines that return to the caller. 9 */ 10 11GOTO_TARGET(filledNewArray, bool methodCallRange) 12 { 13 ClassObject* arrayClass; 14 ArrayObject* newArray; 15 u4* contents; 16 char typeCh; 17 int i; 18 u4 arg5; 19 20 EXPORT_PC(); 21 22 ref = FETCH(1); /* class ref */ 23 vdst = FETCH(2); /* first 4 regs -or- range base */ 24 25 if (methodCallRange) { 26 vsrc1 = INST_AA(inst); /* #of elements */ 27 arg5 = -1; /* silence compiler warning */ 28 ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}", 29 vsrc1, ref, vdst, vdst+vsrc1-1); 30 } else { 31 arg5 = INST_A(inst); 32 vsrc1 = INST_B(inst); /* #of elements */ 33 ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}", 34 vsrc1, ref, vdst, arg5); 35 } 36 37 /* 38 * Resolve the array class. 39 */ 40 arrayClass = dvmDexGetResolvedClass(methodClassDex, ref); 41 if (arrayClass == NULL) { 42 arrayClass = dvmResolveClass(curMethod->clazz, ref, false); 43 if (arrayClass == NULL) 44 GOTO_exceptionThrown(); 45 } 46 /* 47 if (!dvmIsArrayClass(arrayClass)) { 48 dvmThrowException("Ljava/lang/RuntimeError;", 49 "filled-new-array needs array class"); 50 GOTO_exceptionThrown(); 51 } 52 */ 53 /* verifier guarantees this is an array class */ 54 assert(dvmIsArrayClass(arrayClass)); 55 assert(dvmIsClassInitialized(arrayClass)); 56 57 /* 58 * Create an array of the specified type. 59 */ 60 LOGVV("+++ filled-new-array type is '%s'\n", arrayClass->descriptor); 61 typeCh = arrayClass->descriptor[1]; 62 if (typeCh == 'D' || typeCh == 'J') { 63 /* category 2 primitives not allowed */ 64 dvmThrowException("Ljava/lang/RuntimeError;", 65 "bad filled array req"); 66 GOTO_exceptionThrown(); 67 } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') { 68 /* TODO: requires multiple "fill in" loops with different widths */ 69 LOGE("non-int primitives not implemented\n"); 70 dvmThrowException("Ljava/lang/InternalError;", 71 "filled-new-array not implemented for anything but 'int'"); 72 GOTO_exceptionThrown(); 73 } 74 75 newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK); 76 if (newArray == NULL) 77 GOTO_exceptionThrown(); 78 79 /* 80 * Fill in the elements. It's legal for vsrc1 to be zero. 81 */ 82 contents = (u4*) newArray->contents; 83 if (methodCallRange) { 84 for (i = 0; i < vsrc1; i++) 85 contents[i] = GET_REGISTER(vdst+i); 86 } else { 87 assert(vsrc1 <= 5); 88 if (vsrc1 == 5) { 89 contents[4] = GET_REGISTER(arg5); 90 vsrc1--; 91 } 92 for (i = 0; i < vsrc1; i++) { 93 contents[i] = GET_REGISTER(vdst & 0x0f); 94 vdst >>= 4; 95 } 96 } 97 if (typeCh == 'L' || typeCh == '[') { 98 dvmWriteBarrierArray(newArray, 0, newArray->length); 99 } 100 101 retval.l = newArray; 102 } 103 FINISH(3); 104GOTO_TARGET_END 105 106 107GOTO_TARGET(invokeVirtual, bool methodCallRange) 108 { 109 Method* baseMethod; 110 Object* thisPtr; 111 112 EXPORT_PC(); 113 114 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 115 ref = FETCH(1); /* method ref */ 116 vdst = FETCH(2); /* 4 regs -or- first reg */ 117 118 /* 119 * The object against which we are executing a method is always 120 * in the first argument. 121 */ 122 if (methodCallRange) { 123 assert(vsrc1 > 0); 124 ILOGV("|invoke-virtual-range args=%d @0x%04x {regs=v%d-v%d}", 125 vsrc1, ref, vdst, vdst+vsrc1-1); 126 thisPtr = (Object*) GET_REGISTER(vdst); 127 } else { 128 assert((vsrc1>>4) > 0); 129 ILOGV("|invoke-virtual args=%d @0x%04x {regs=0x%04x %x}", 130 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 131 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 132 } 133 134 if (!checkForNull(thisPtr)) 135 GOTO_exceptionThrown(); 136 137 /* 138 * Resolve the method. This is the correct method for the static 139 * type of the object. We also verify access permissions here. 140 */ 141 baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref); 142 if (baseMethod == NULL) { 143 baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL); 144 if (baseMethod == NULL) { 145 ILOGV("+ unknown method or access denied\n"); 146 GOTO_exceptionThrown(); 147 } 148 } 149 150 /* 151 * Combine the object we found with the vtable offset in the 152 * method. 153 */ 154 assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount); 155 methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex]; 156 157#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG) 158 callsiteClass = thisPtr->clazz; 159#endif 160 161#if 0 162 if (dvmIsAbstractMethod(methodToCall)) { 163 /* 164 * This can happen if you create two classes, Base and Sub, where 165 * Sub is a sub-class of Base. Declare a protected abstract 166 * method foo() in Base, and invoke foo() from a method in Base. 167 * Base is an "abstract base class" and is never instantiated 168 * directly. Now, Override foo() in Sub, and use Sub. This 169 * Works fine unless Sub stops providing an implementation of 170 * the method. 171 */ 172 dvmThrowException("Ljava/lang/AbstractMethodError;", 173 "abstract method not implemented"); 174 GOTO_exceptionThrown(); 175 } 176#else 177 assert(!dvmIsAbstractMethod(methodToCall) || 178 methodToCall->nativeFunc != NULL); 179#endif 180 181 LOGVV("+++ base=%s.%s virtual[%d]=%s.%s\n", 182 baseMethod->clazz->descriptor, baseMethod->name, 183 (u4) baseMethod->methodIndex, 184 methodToCall->clazz->descriptor, methodToCall->name); 185 assert(methodToCall != NULL); 186 187#if 0 188 if (vsrc1 != methodToCall->insSize) { 189 LOGW("WRONG METHOD: base=%s.%s virtual[%d]=%s.%s\n", 190 baseMethod->clazz->descriptor, baseMethod->name, 191 (u4) baseMethod->methodIndex, 192 methodToCall->clazz->descriptor, methodToCall->name); 193 //dvmDumpClass(baseMethod->clazz); 194 //dvmDumpClass(methodToCall->clazz); 195 dvmDumpAllClasses(0); 196 } 197#endif 198 199 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 200 } 201GOTO_TARGET_END 202 203GOTO_TARGET(invokeSuper, bool methodCallRange) 204 { 205 Method* baseMethod; 206 u2 thisReg; 207 208 EXPORT_PC(); 209 210 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 211 ref = FETCH(1); /* method ref */ 212 vdst = FETCH(2); /* 4 regs -or- first reg */ 213 214 if (methodCallRange) { 215 ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}", 216 vsrc1, ref, vdst, vdst+vsrc1-1); 217 thisReg = vdst; 218 } else { 219 ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}", 220 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 221 thisReg = vdst & 0x0f; 222 } 223 /* impossible in well-formed code, but we must check nevertheless */ 224 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 225 GOTO_exceptionThrown(); 226 227 /* 228 * Resolve the method. This is the correct method for the static 229 * type of the object. We also verify access permissions here. 230 * The first arg to dvmResolveMethod() is just the referring class 231 * (used for class loaders and such), so we don't want to pass 232 * the superclass into the resolution call. 233 */ 234 baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref); 235 if (baseMethod == NULL) { 236 baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL); 237 if (baseMethod == NULL) { 238 ILOGV("+ unknown method or access denied\n"); 239 GOTO_exceptionThrown(); 240 } 241 } 242 243 /* 244 * Combine the object we found with the vtable offset in the 245 * method's class. 246 * 247 * We're using the current method's class' superclass, not the 248 * superclass of "this". This is because we might be executing 249 * in a method inherited from a superclass, and we want to run 250 * in that class' superclass. 251 */ 252 if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) { 253 /* 254 * Method does not exist in the superclass. Could happen if 255 * superclass gets updated. 256 */ 257 dvmThrowException("Ljava/lang/NoSuchMethodError;", 258 baseMethod->name); 259 GOTO_exceptionThrown(); 260 } 261 methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex]; 262#if 0 263 if (dvmIsAbstractMethod(methodToCall)) { 264 dvmThrowException("Ljava/lang/AbstractMethodError;", 265 "abstract method not implemented"); 266 GOTO_exceptionThrown(); 267 } 268#else 269 assert(!dvmIsAbstractMethod(methodToCall) || 270 methodToCall->nativeFunc != NULL); 271#endif 272 LOGVV("+++ base=%s.%s super-virtual=%s.%s\n", 273 baseMethod->clazz->descriptor, baseMethod->name, 274 methodToCall->clazz->descriptor, methodToCall->name); 275 assert(methodToCall != NULL); 276 277 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 278 } 279GOTO_TARGET_END 280 281GOTO_TARGET(invokeInterface, bool methodCallRange) 282 { 283 Object* thisPtr; 284 ClassObject* thisClass; 285 286 EXPORT_PC(); 287 288 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 289 ref = FETCH(1); /* method ref */ 290 vdst = FETCH(2); /* 4 regs -or- first reg */ 291 292 /* 293 * The object against which we are executing a method is always 294 * in the first argument. 295 */ 296 if (methodCallRange) { 297 assert(vsrc1 > 0); 298 ILOGV("|invoke-interface-range args=%d @0x%04x {regs=v%d-v%d}", 299 vsrc1, ref, vdst, vdst+vsrc1-1); 300 thisPtr = (Object*) GET_REGISTER(vdst); 301 } else { 302 assert((vsrc1>>4) > 0); 303 ILOGV("|invoke-interface args=%d @0x%04x {regs=0x%04x %x}", 304 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 305 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 306 } 307 if (!checkForNull(thisPtr)) 308 GOTO_exceptionThrown(); 309 310 thisClass = thisPtr->clazz; 311 312#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG) 313 callsiteClass = thisClass; 314#endif 315 316 /* 317 * Given a class and a method index, find the Method* with the 318 * actual code we want to execute. 319 */ 320 methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod, 321 methodClassDex); 322 if (methodToCall == NULL) { 323 assert(dvmCheckException(self)); 324 GOTO_exceptionThrown(); 325 } 326 327 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 328 } 329GOTO_TARGET_END 330 331GOTO_TARGET(invokeDirect, bool methodCallRange) 332 { 333 u2 thisReg; 334 335 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 336 ref = FETCH(1); /* method ref */ 337 vdst = FETCH(2); /* 4 regs -or- first reg */ 338 339 EXPORT_PC(); 340 341 if (methodCallRange) { 342 ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}", 343 vsrc1, ref, vdst, vdst+vsrc1-1); 344 thisReg = vdst; 345 } else { 346 ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}", 347 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 348 thisReg = vdst & 0x0f; 349 } 350 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 351 GOTO_exceptionThrown(); 352 353 methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref); 354 if (methodToCall == NULL) { 355 methodToCall = dvmResolveMethod(curMethod->clazz, ref, 356 METHOD_DIRECT); 357 if (methodToCall == NULL) { 358 ILOGV("+ unknown direct method\n"); // should be impossible 359 GOTO_exceptionThrown(); 360 } 361 } 362 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 363 } 364GOTO_TARGET_END 365 366GOTO_TARGET(invokeStatic, bool methodCallRange) 367 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 368 ref = FETCH(1); /* method ref */ 369 vdst = FETCH(2); /* 4 regs -or- first reg */ 370 371 EXPORT_PC(); 372 373 if (methodCallRange) 374 ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}", 375 vsrc1, ref, vdst, vdst+vsrc1-1); 376 else 377 ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}", 378 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 379 380 methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref); 381 if (methodToCall == NULL) { 382 methodToCall = dvmResolveMethod(curMethod->clazz, ref, METHOD_STATIC); 383 if (methodToCall == NULL) { 384 ILOGV("+ unknown method\n"); 385 GOTO_exceptionThrown(); 386 } 387 388 /* 389 * The JIT needs dvmDexGetResolvedMethod() to return non-null. 390 * Since we use the portable interpreter to build the trace, this extra 391 * check is not needed for mterp. 392 */ 393 if (dvmDexGetResolvedMethod(methodClassDex, ref) == NULL) { 394 /* Class initialization is still ongoing */ 395 ABORT_JIT_TSELECT(); 396 } 397 } 398 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 399GOTO_TARGET_END 400 401GOTO_TARGET(invokeVirtualQuick, bool methodCallRange) 402 { 403 Object* thisPtr; 404 405 EXPORT_PC(); 406 407 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 408 ref = FETCH(1); /* vtable index */ 409 vdst = FETCH(2); /* 4 regs -or- first reg */ 410 411 /* 412 * The object against which we are executing a method is always 413 * in the first argument. 414 */ 415 if (methodCallRange) { 416 assert(vsrc1 > 0); 417 ILOGV("|invoke-virtual-quick-range args=%d @0x%04x {regs=v%d-v%d}", 418 vsrc1, ref, vdst, vdst+vsrc1-1); 419 thisPtr = (Object*) GET_REGISTER(vdst); 420 } else { 421 assert((vsrc1>>4) > 0); 422 ILOGV("|invoke-virtual-quick args=%d @0x%04x {regs=0x%04x %x}", 423 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 424 thisPtr = (Object*) GET_REGISTER(vdst & 0x0f); 425 } 426 427 if (!checkForNull(thisPtr)) 428 GOTO_exceptionThrown(); 429 430#if defined(WITH_JIT) && (INTERP_TYPE == INTERP_DBG) 431 callsiteClass = thisPtr->clazz; 432#endif 433 434 /* 435 * Combine the object we found with the vtable offset in the 436 * method. 437 */ 438 assert(ref < thisPtr->clazz->vtableCount); 439 methodToCall = thisPtr->clazz->vtable[ref]; 440 441#if 0 442 if (dvmIsAbstractMethod(methodToCall)) { 443 dvmThrowException("Ljava/lang/AbstractMethodError;", 444 "abstract method not implemented"); 445 GOTO_exceptionThrown(); 446 } 447#else 448 assert(!dvmIsAbstractMethod(methodToCall) || 449 methodToCall->nativeFunc != NULL); 450#endif 451 452 LOGVV("+++ virtual[%d]=%s.%s\n", 453 ref, methodToCall->clazz->descriptor, methodToCall->name); 454 assert(methodToCall != NULL); 455 456 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 457 } 458GOTO_TARGET_END 459 460GOTO_TARGET(invokeSuperQuick, bool methodCallRange) 461 { 462 u2 thisReg; 463 464 EXPORT_PC(); 465 466 vsrc1 = INST_AA(inst); /* AA (count) or BA (count + arg 5) */ 467 ref = FETCH(1); /* vtable index */ 468 vdst = FETCH(2); /* 4 regs -or- first reg */ 469 470 if (methodCallRange) { 471 ILOGV("|invoke-super-quick-range args=%d @0x%04x {regs=v%d-v%d}", 472 vsrc1, ref, vdst, vdst+vsrc1-1); 473 thisReg = vdst; 474 } else { 475 ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}", 476 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f); 477 thisReg = vdst & 0x0f; 478 } 479 /* impossible in well-formed code, but we must check nevertheless */ 480 if (!checkForNull((Object*) GET_REGISTER(thisReg))) 481 GOTO_exceptionThrown(); 482 483#if 0 /* impossible in optimized + verified code */ 484 if (ref >= curMethod->clazz->super->vtableCount) { 485 dvmThrowException("Ljava/lang/NoSuchMethodError;", NULL); 486 GOTO_exceptionThrown(); 487 } 488#else 489 assert(ref < curMethod->clazz->super->vtableCount); 490#endif 491 492 /* 493 * Combine the object we found with the vtable offset in the 494 * method's class. 495 * 496 * We're using the current method's class' superclass, not the 497 * superclass of "this". This is because we might be executing 498 * in a method inherited from a superclass, and we want to run 499 * in the method's class' superclass. 500 */ 501 methodToCall = curMethod->clazz->super->vtable[ref]; 502 503#if 0 504 if (dvmIsAbstractMethod(methodToCall)) { 505 dvmThrowException("Ljava/lang/AbstractMethodError;", 506 "abstract method not implemented"); 507 GOTO_exceptionThrown(); 508 } 509#else 510 assert(!dvmIsAbstractMethod(methodToCall) || 511 methodToCall->nativeFunc != NULL); 512#endif 513 LOGVV("+++ super-virtual[%d]=%s.%s\n", 514 ref, methodToCall->clazz->descriptor, methodToCall->name); 515 assert(methodToCall != NULL); 516 517 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst); 518 } 519GOTO_TARGET_END 520 521 522 /* 523 * General handling for return-void, return, and return-wide. Put the 524 * return value in "retval" before jumping here. 525 */ 526GOTO_TARGET(returnFromMethod) 527 { 528 StackSaveArea* saveArea; 529 530 /* 531 * We must do this BEFORE we pop the previous stack frame off, so 532 * that the GC can see the return value (if any) in the local vars. 533 * 534 * Since this is now an interpreter switch point, we must do it before 535 * we do anything at all. 536 */ 537 PERIODIC_CHECKS(kInterpEntryReturn, 0); 538 539 ILOGV("> retval=0x%llx (leaving %s.%s %s)", 540 retval.j, curMethod->clazz->descriptor, curMethod->name, 541 curMethod->shorty); 542 //DUMP_REGS(curMethod, fp); 543 544 saveArea = SAVEAREA_FROM_FP(fp); 545 546#ifdef EASY_GDB 547 debugSaveArea = saveArea; 548#endif 549#if (INTERP_TYPE == INTERP_DBG) 550 TRACE_METHOD_EXIT(self, curMethod); 551#endif 552 553 /* back up to previous frame and see if we hit a break */ 554 fp = saveArea->prevFrame; 555 assert(fp != NULL); 556 if (dvmIsBreakFrame(fp)) { 557 /* bail without popping the method frame from stack */ 558 LOGVV("+++ returned into break frame\n"); 559#if defined(WITH_JIT) 560 /* Let the Jit know the return is terminating normally */ 561 CHECK_JIT_VOID(); 562#endif 563 GOTO_bail(); 564 } 565 566 /* update thread FP, and reset local variables */ 567 self->curFrame = fp; 568 curMethod = SAVEAREA_FROM_FP(fp)->method; 569 //methodClass = curMethod->clazz; 570 methodClassDex = curMethod->clazz->pDvmDex; 571 pc = saveArea->savedPc; 572 ILOGD("> (return to %s.%s %s)", curMethod->clazz->descriptor, 573 curMethod->name, curMethod->shorty); 574 575 /* use FINISH on the caller's invoke instruction */ 576 //u2 invokeInstr = INST_INST(FETCH(0)); 577 if (true /*invokeInstr >= OP_INVOKE_VIRTUAL && 578 invokeInstr <= OP_INVOKE_INTERFACE*/) 579 { 580 FINISH(3); 581 } else { 582 //LOGE("Unknown invoke instr %02x at %d\n", 583 // invokeInstr, (int) (pc - curMethod->insns)); 584 assert(false); 585 } 586 } 587GOTO_TARGET_END 588 589 590 /* 591 * Jump here when the code throws an exception. 592 * 593 * By the time we get here, the Throwable has been created and the stack 594 * trace has been saved off. 595 */ 596GOTO_TARGET(exceptionThrown) 597 { 598 Object* exception; 599 int catchRelPc; 600 601 /* 602 * Since this is now an interpreter switch point, we must do it before 603 * we do anything at all. 604 */ 605 PERIODIC_CHECKS(kInterpEntryThrow, 0); 606 607#if defined(WITH_JIT) 608 // Something threw during trace selection - abort the current trace 609 ABORT_JIT_TSELECT(); 610#endif 611 /* 612 * We save off the exception and clear the exception status. While 613 * processing the exception we might need to load some Throwable 614 * classes, and we don't want class loader exceptions to get 615 * confused with this one. 616 */ 617 assert(dvmCheckException(self)); 618 exception = dvmGetException(self); 619 dvmAddTrackedAlloc(exception, self); 620 dvmClearException(self); 621 622 LOGV("Handling exception %s at %s:%d\n", 623 exception->clazz->descriptor, curMethod->name, 624 dvmLineNumFromPC(curMethod, pc - curMethod->insns)); 625 626#if (INTERP_TYPE == INTERP_DBG) 627 /* 628 * Tell the debugger about it. 629 * 630 * TODO: if the exception was thrown by interpreted code, control 631 * fell through native, and then back to us, we will report the 632 * exception at the point of the throw and again here. We can avoid 633 * this by not reporting exceptions when we jump here directly from 634 * the native call code above, but then we won't report exceptions 635 * that were thrown *from* the JNI code (as opposed to *through* it). 636 * 637 * The correct solution is probably to ignore from-native exceptions 638 * here, and have the JNI exception code do the reporting to the 639 * debugger. 640 */ 641 if (gDvm.debuggerActive) { 642 void* catchFrame; 643 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, 644 exception, true, &catchFrame); 645 dvmDbgPostException(fp, pc - curMethod->insns, catchFrame, 646 catchRelPc, exception); 647 } 648#endif 649 650 /* 651 * We need to unroll to the catch block or the nearest "break" 652 * frame. 653 * 654 * A break frame could indicate that we have reached an intermediate 655 * native call, or have gone off the top of the stack and the thread 656 * needs to exit. Either way, we return from here, leaving the 657 * exception raised. 658 * 659 * If we do find a catch block, we want to transfer execution to 660 * that point. 661 * 662 * Note this can cause an exception while resolving classes in 663 * the "catch" blocks. 664 */ 665 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns, 666 exception, false, (void*)&fp); 667 668 /* 669 * Restore the stack bounds after an overflow. This isn't going to 670 * be correct in all circumstances, e.g. if JNI code devours the 671 * exception this won't happen until some other exception gets 672 * thrown. If the code keeps pushing the stack bounds we'll end 673 * up aborting the VM. 674 * 675 * Note we want to do this *after* the call to dvmFindCatchBlock, 676 * because that may need extra stack space to resolve exception 677 * classes (e.g. through a class loader). 678 * 679 * It's possible for the stack overflow handling to cause an 680 * exception (specifically, class resolution in a "catch" block 681 * during the call above), so we could see the thread's overflow 682 * flag raised but actually be running in a "nested" interpreter 683 * frame. We don't allow doubled-up StackOverflowErrors, so 684 * we can check for this by just looking at the exception type 685 * in the cleanup function. Also, we won't unroll past the SOE 686 * point because the more-recent exception will hit a break frame 687 * as it unrolls to here. 688 */ 689 if (self->stackOverflowed) 690 dvmCleanupStackOverflow(self, exception); 691 692 if (catchRelPc < 0) { 693 /* falling through to JNI code or off the bottom of the stack */ 694#if DVM_SHOW_EXCEPTION >= 2 695 LOGD("Exception %s from %s:%d not caught locally\n", 696 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod), 697 dvmLineNumFromPC(curMethod, pc - curMethod->insns)); 698#endif 699 dvmSetException(self, exception); 700 dvmReleaseTrackedAlloc(exception, self); 701 GOTO_bail(); 702 } 703 704#if DVM_SHOW_EXCEPTION >= 3 705 { 706 const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method; 707 LOGD("Exception %s thrown from %s:%d to %s:%d\n", 708 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod), 709 dvmLineNumFromPC(curMethod, pc - curMethod->insns), 710 dvmGetMethodSourceFile(catchMethod), 711 dvmLineNumFromPC(catchMethod, catchRelPc)); 712 } 713#endif 714 715 /* 716 * Adjust local variables to match self->curFrame and the 717 * updated PC. 718 */ 719 //fp = (u4*) self->curFrame; 720 curMethod = SAVEAREA_FROM_FP(fp)->method; 721 //methodClass = curMethod->clazz; 722 methodClassDex = curMethod->clazz->pDvmDex; 723 pc = curMethod->insns + catchRelPc; 724 ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor, 725 curMethod->name, curMethod->shorty); 726 DUMP_REGS(curMethod, fp, false); // show all regs 727 728 /* 729 * Restore the exception if the handler wants it. 730 * 731 * The Dalvik spec mandates that, if an exception handler wants to 732 * do something with the exception, the first instruction executed 733 * must be "move-exception". We can pass the exception along 734 * through the thread struct, and let the move-exception instruction 735 * clear it for us. 736 * 737 * If the handler doesn't call move-exception, we don't want to 738 * finish here with an exception still pending. 739 */ 740 if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION) 741 dvmSetException(self, exception); 742 743 dvmReleaseTrackedAlloc(exception, self); 744 FINISH(0); 745 } 746GOTO_TARGET_END 747 748 749 750 /* 751 * General handling for invoke-{virtual,super,direct,static,interface}, 752 * including "quick" variants. 753 * 754 * Set "methodToCall" to the Method we're calling, and "methodCallRange" 755 * depending on whether this is a "/range" instruction. 756 * 757 * For a range call: 758 * "vsrc1" holds the argument count (8 bits) 759 * "vdst" holds the first argument in the range 760 * For a non-range call: 761 * "vsrc1" holds the argument count (4 bits) and the 5th argument index 762 * "vdst" holds four 4-bit register indices 763 * 764 * The caller must EXPORT_PC before jumping here, because any method 765 * call can throw a stack overflow exception. 766 */ 767GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, 768 u2 count, u2 regs) 769 { 770 STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;); 771 772 //printf("range=%d call=%p count=%d regs=0x%04x\n", 773 // methodCallRange, methodToCall, count, regs); 774 //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor, 775 // methodToCall->name, methodToCall->shorty); 776 777 u4* outs; 778 int i; 779 780 /* 781 * Copy args. This may corrupt vsrc1/vdst. 782 */ 783 if (methodCallRange) { 784 // could use memcpy or a "Duff's device"; most functions have 785 // so few args it won't matter much 786 assert(vsrc1 <= curMethod->outsSize); 787 assert(vsrc1 == methodToCall->insSize); 788 outs = OUTS_FROM_FP(fp, vsrc1); 789 for (i = 0; i < vsrc1; i++) 790 outs[i] = GET_REGISTER(vdst+i); 791 } else { 792 u4 count = vsrc1 >> 4; 793 794 assert(count <= curMethod->outsSize); 795 assert(count == methodToCall->insSize); 796 assert(count <= 5); 797 798 outs = OUTS_FROM_FP(fp, count); 799#if 0 800 if (count == 5) { 801 outs[4] = GET_REGISTER(vsrc1 & 0x0f); 802 count--; 803 } 804 for (i = 0; i < (int) count; i++) { 805 outs[i] = GET_REGISTER(vdst & 0x0f); 806 vdst >>= 4; 807 } 808#else 809 // This version executes fewer instructions but is larger 810 // overall. Seems to be a teensy bit faster. 811 assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear 812 switch (count) { 813 case 5: 814 outs[4] = GET_REGISTER(vsrc1 & 0x0f); 815 case 4: 816 outs[3] = GET_REGISTER(vdst >> 12); 817 case 3: 818 outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8); 819 case 2: 820 outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4); 821 case 1: 822 outs[0] = GET_REGISTER(vdst & 0x0f); 823 default: 824 ; 825 } 826#endif 827 } 828 } 829 830 /* 831 * (This was originally a "goto" target; I've kept it separate from the 832 * stuff above in case we want to refactor things again.) 833 * 834 * At this point, we have the arguments stored in the "outs" area of 835 * the current method's stack frame, and the method to call in 836 * "methodToCall". Push a new stack frame. 837 */ 838 { 839 StackSaveArea* newSaveArea; 840 u4* newFp; 841 842 ILOGV("> %s%s.%s %s", 843 dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "", 844 methodToCall->clazz->descriptor, methodToCall->name, 845 methodToCall->shorty); 846 847 newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize; 848 newSaveArea = SAVEAREA_FROM_FP(newFp); 849 850 /* verify that we have enough space */ 851 if (true) { 852 u1* bottom; 853 bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4); 854 if (bottom < self->interpStackEnd) { 855 /* stack overflow */ 856 LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')\n", 857 self->interpStackStart, self->interpStackEnd, bottom, 858 (u1*) fp - bottom, self->interpStackSize, 859 methodToCall->name); 860 dvmHandleStackOverflow(self, methodToCall); 861 assert(dvmCheckException(self)); 862 GOTO_exceptionThrown(); 863 } 864 //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p\n", 865 // fp, newFp, newSaveArea, bottom); 866 } 867 868#ifdef LOG_INSTR 869 if (methodToCall->registersSize > methodToCall->insSize) { 870 /* 871 * This makes valgrind quiet when we print registers that 872 * haven't been initialized. Turn it off when the debug 873 * messages are disabled -- we want valgrind to report any 874 * used-before-initialized issues. 875 */ 876 memset(newFp, 0xcc, 877 (methodToCall->registersSize - methodToCall->insSize) * 4); 878 } 879#endif 880 881#ifdef EASY_GDB 882 newSaveArea->prevSave = SAVEAREA_FROM_FP(fp); 883#endif 884 newSaveArea->prevFrame = fp; 885 newSaveArea->savedPc = pc; 886#if defined(WITH_JIT) 887 newSaveArea->returnAddr = 0; 888#endif 889 newSaveArea->method = methodToCall; 890 891 if (!dvmIsNativeMethod(methodToCall)) { 892 /* 893 * "Call" interpreted code. Reposition the PC, update the 894 * frame pointer and other local state, and continue. 895 */ 896 curMethod = methodToCall; 897 methodClassDex = curMethod->clazz->pDvmDex; 898 pc = methodToCall->insns; 899 fp = self->curFrame = newFp; 900#ifdef EASY_GDB 901 debugSaveArea = SAVEAREA_FROM_FP(newFp); 902#endif 903#if INTERP_TYPE == INTERP_DBG 904 debugIsMethodEntry = true; // profiling, debugging 905#endif 906 ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor, 907 curMethod->name, curMethod->shorty); 908 DUMP_REGS(curMethod, fp, true); // show input args 909 FINISH(0); // jump to method start 910 } else { 911 /* set this up for JNI locals, even if not a JNI native */ 912#ifdef USE_INDIRECT_REF 913 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all; 914#else 915 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry; 916#endif 917 918 self->curFrame = newFp; 919 920 DUMP_REGS(methodToCall, newFp, true); // show input args 921 922#if (INTERP_TYPE == INTERP_DBG) 923 if (gDvm.debuggerActive) { 924 dvmDbgPostLocationEvent(methodToCall, -1, 925 dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY); 926 } 927#endif 928#if (INTERP_TYPE == INTERP_DBG) 929 TRACE_METHOD_ENTER(self, methodToCall); 930#endif 931 932 { 933 ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor, 934 methodToCall->name, methodToCall->shorty); 935 } 936 937#if defined(WITH_JIT) 938 /* Allow the Jit to end any pending trace building */ 939 CHECK_JIT_VOID(); 940#endif 941 942 /* 943 * Jump through native call bridge. Because we leave no 944 * space for locals on native calls, "newFp" points directly 945 * to the method arguments. 946 */ 947 (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self); 948 949#if (INTERP_TYPE == INTERP_DBG) 950 if (gDvm.debuggerActive) { 951 dvmDbgPostLocationEvent(methodToCall, -1, 952 dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT); 953 } 954#endif 955#if (INTERP_TYPE == INTERP_DBG) 956 TRACE_METHOD_EXIT(self, methodToCall); 957#endif 958 959 /* pop frame off */ 960 dvmPopJniLocals(self, newSaveArea); 961 self->curFrame = fp; 962 963 /* 964 * If the native code threw an exception, or interpreted code 965 * invoked by the native call threw one and nobody has cleared 966 * it, jump to our local exception handling. 967 */ 968 if (dvmCheckException(self)) { 969 LOGV("Exception thrown by/below native code\n"); 970 GOTO_exceptionThrown(); 971 } 972 973 ILOGD("> retval=0x%llx (leaving native)", retval.j); 974 ILOGD("> (return from native %s.%s to %s.%s %s)", 975 methodToCall->clazz->descriptor, methodToCall->name, 976 curMethod->clazz->descriptor, curMethod->name, 977 curMethod->shorty); 978 979 //u2 invokeInstr = INST_INST(FETCH(0)); 980 if (true /*invokeInstr >= OP_INVOKE_VIRTUAL && 981 invokeInstr <= OP_INVOKE_INTERFACE*/) 982 { 983 FINISH(3); 984 } else { 985 //LOGE("Unknown invoke instr %02x at %d\n", 986 // invokeInstr, (int) (pc - curMethod->insns)); 987 assert(false); 988 } 989 } 990 } 991 assert(false); // should not get here 992GOTO_TARGET_END 993