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