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