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