2 * C footer. This has some common code shared by the various targets.
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.
11 GOTO_TARGET(filledNewArray, bool methodCallRange)
13 ClassObject* arrayClass;
14 ArrayObject* newArray;
22 ref = FETCH(1); /* class ref */
23 vdst = FETCH(2); /* first 4 regs -or- range base */
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);
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);
38 * Resolve the array class.
40 arrayClass = dvmDexGetResolvedClass(methodClassDex, ref);
41 if (arrayClass == NULL) {
42 arrayClass = dvmResolveClass(curMethod->clazz, ref, false);
43 if (arrayClass == NULL)
44 GOTO_exceptionThrown();
47 if (!dvmIsArrayClass(arrayClass)) {
48 dvmThrowException("Ljava/lang/RuntimeError;",
49 "filled-new-array needs array class");
50 GOTO_exceptionThrown();
53 /* verifier guarantees this is an array class */
54 assert(dvmIsArrayClass(arrayClass));
55 assert(dvmIsClassInitialized(arrayClass));
58 * Create an array of the specified type.
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();
75 newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK);
77 GOTO_exceptionThrown();
80 * Fill in the elements. It's legal for vsrc1 to be zero.
82 contents = (u4*) newArray->contents;
83 if (methodCallRange) {
84 for (i = 0; i < vsrc1; i++)
85 contents[i] = GET_REGISTER(vdst+i);
89 contents[4] = GET_REGISTER(arg5);
92 for (i = 0; i < vsrc1; i++) {
93 contents[i] = GET_REGISTER(vdst & 0x0f);
104 GOTO_TARGET(invokeVirtual, bool methodCallRange)
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 */
116 * The object against which we are executing a method is always
117 * in the first argument.
119 if (methodCallRange) {
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);
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);
131 if (!checkForNull(thisPtr))
132 GOTO_exceptionThrown();
135 * Resolve the method. This is the correct method for the static
136 * type of the object. We also verify access permissions here.
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();
148 * Combine the object we found with the vtable offset in the
151 assert(baseMethod->methodIndex < thisPtr->clazz->vtableCount);
152 methodToCall = thisPtr->clazz->vtable[baseMethod->methodIndex];
155 if (dvmIsAbstractMethod(methodToCall)) {
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
165 dvmThrowException("Ljava/lang/AbstractMethodError;",
166 "abstract method not implemented");
167 GOTO_exceptionThrown();
170 assert(!dvmIsAbstractMethod(methodToCall) ||
171 methodToCall->nativeFunc != NULL);
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);
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);
192 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
196 GOTO_TARGET(invokeSuper, bool methodCallRange)
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 */
207 if (methodCallRange) {
208 ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
209 vsrc1, ref, vdst, vdst+vsrc1-1);
212 ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
213 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
214 thisReg = vdst & 0x0f;
216 /* impossible in well-formed code, but we must check nevertheless */
217 if (!checkForNull((Object*) GET_REGISTER(thisReg)))
218 GOTO_exceptionThrown();
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.
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();
237 * Combine the object we found with the vtable offset in the
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.
245 if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
247 * Method does not exist in the superclass. Could happen if
248 * superclass gets updated.
250 dvmThrowException("Ljava/lang/NoSuchMethodError;",
252 GOTO_exceptionThrown();
254 methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
256 if (dvmIsAbstractMethod(methodToCall)) {
257 dvmThrowException("Ljava/lang/AbstractMethodError;",
258 "abstract method not implemented");
259 GOTO_exceptionThrown();
262 assert(!dvmIsAbstractMethod(methodToCall) ||
263 methodToCall->nativeFunc != NULL);
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);
270 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
274 GOTO_TARGET(invokeInterface, bool methodCallRange)
277 ClassObject* thisClass;
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 */
286 * The object against which we are executing a method is always
287 * in the first argument.
289 if (methodCallRange) {
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);
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);
300 if (!checkForNull(thisPtr))
301 GOTO_exceptionThrown();
303 thisClass = thisPtr->clazz;
306 * Given a class and a method index, find the Method* with the
307 * actual code we want to execute.
309 methodToCall = dvmFindInterfaceMethodInCache(thisClass, ref, curMethod,
311 if (methodToCall == NULL) {
312 assert(dvmCheckException(self));
313 GOTO_exceptionThrown();
316 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
320 GOTO_TARGET(invokeDirect, bool methodCallRange)
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 */
330 if (methodCallRange) {
331 ILOGV("|invoke-direct-range args=%d @0x%04x {regs=v%d-v%d}",
332 vsrc1, ref, vdst, vdst+vsrc1-1);
335 ILOGV("|invoke-direct args=%d @0x%04x {regs=0x%04x %x}",
336 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
337 thisReg = vdst & 0x0f;
339 if (!checkForNull((Object*) GET_REGISTER(thisReg)))
340 GOTO_exceptionThrown();
342 methodToCall = dvmDexGetResolvedMethod(methodClassDex, ref);
343 if (methodToCall == NULL) {
344 methodToCall = dvmResolveMethod(curMethod->clazz, ref,
346 if (methodToCall == NULL) {
347 ILOGV("+ unknown direct method\n"); // should be impossible
348 GOTO_exceptionThrown();
351 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
355 GOTO_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 */
363 ILOGV("|invoke-static-range args=%d @0x%04x {regs=v%d-v%d}",
364 vsrc1, ref, vdst, vdst+vsrc1-1);
366 ILOGV("|invoke-static args=%d @0x%04x {regs=0x%04x %x}",
367 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
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();
377 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
380 GOTO_TARGET(invokeVirtualQuick, bool methodCallRange)
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 */
391 * The object against which we are executing a method is always
392 * in the first argument.
394 if (methodCallRange) {
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);
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);
406 if (!checkForNull(thisPtr))
407 GOTO_exceptionThrown();
410 * Combine the object we found with the vtable offset in the
413 assert(ref < thisPtr->clazz->vtableCount);
414 methodToCall = thisPtr->clazz->vtable[ref];
417 if (dvmIsAbstractMethod(methodToCall)) {
418 dvmThrowException("Ljava/lang/AbstractMethodError;",
419 "abstract method not implemented");
420 GOTO_exceptionThrown();
423 assert(!dvmIsAbstractMethod(methodToCall) ||
424 methodToCall->nativeFunc != NULL);
427 LOGVV("+++ virtual[%d]=%s.%s\n",
428 ref, methodToCall->clazz->descriptor, methodToCall->name);
429 assert(methodToCall != NULL);
431 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
435 GOTO_TARGET(invokeSuperQuick, bool methodCallRange)
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 */
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);
450 ILOGV("|invoke-super-quick args=%d @0x%04x {regs=0x%04x %x}",
451 vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
452 thisReg = vdst & 0x0f;
454 /* impossible in well-formed code, but we must check nevertheless */
455 if (!checkForNull((Object*) GET_REGISTER(thisReg)))
456 GOTO_exceptionThrown();
458 #if 0 /* impossible in optimized + verified code */
459 if (ref >= curMethod->clazz->super->vtableCount) {
460 dvmThrowException("Ljava/lang/NoSuchMethodError;", NULL);
461 GOTO_exceptionThrown();
464 assert(ref < curMethod->clazz->super->vtableCount);
468 * Combine the object we found with the vtable offset in the
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.
476 methodToCall = curMethod->clazz->super->vtable[ref];
479 if (dvmIsAbstractMethod(methodToCall)) {
480 dvmThrowException("Ljava/lang/AbstractMethodError;",
481 "abstract method not implemented");
482 GOTO_exceptionThrown();
485 assert(!dvmIsAbstractMethod(methodToCall) ||
486 methodToCall->nativeFunc != NULL);
488 LOGVV("+++ super-virtual[%d]=%s.%s\n",
489 ref, methodToCall->clazz->descriptor, methodToCall->name);
490 assert(methodToCall != NULL);
492 GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
499 * General handling for return-void, return, and return-wide. Put the
500 * return value in "retval" before jumping here.
502 GOTO_TARGET(returnFromMethod)
504 StackSaveArea* saveArea;
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.
510 * Since this is now an interpreter switch point, we must do it before
511 * we do anything at all.
513 PERIODIC_CHECKS(kInterpEntryReturn, 0);
515 ILOGV("> retval=0x%llx (leaving %s.%s %s)",
516 retval.j, curMethod->clazz->descriptor, curMethod->name,
518 //DUMP_REGS(curMethod, fp);
520 saveArea = SAVEAREA_FROM_FP(fp);
523 debugSaveArea = saveArea;
525 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER)
526 TRACE_METHOD_EXIT(self, curMethod);
529 /* back up to previous frame and see if we hit a break */
530 fp = saveArea->prevFrame;
532 if (dvmIsBreakFrame(fp)) {
533 /* bail without popping the method frame from stack */
534 LOGVV("+++ returned into break frame\n");
538 /* update thread FP, and reset local variables */
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->shorty);
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*/)
554 //LOGE("Unknown invoke instr %02x at %d\n",
555 // invokeInstr, (int) (pc - curMethod->insns));
563 * Jump here when the code throws an exception.
565 * By the time we get here, the Throwable has been created and the stack
566 * trace has been saved off.
568 GOTO_TARGET(exceptionThrown)
574 * Since this is now an interpreter switch point, we must do it before
575 * we do anything at all.
577 PERIODIC_CHECKS(kInterpEntryThrow, 0);
579 #if defined(WITH_JIT)
580 // Something threw during trace selection - abort the current trace
581 if (interpState->jitState == kJitTSelect) {
582 interpState->jitState = kJitTSelectEnd;
586 * We save off the exception and clear the exception status. While
587 * processing the exception we might need to load some Throwable
588 * classes, and we don't want class loader exceptions to get
589 * confused with this one.
591 assert(dvmCheckException(self));
592 exception = dvmGetException(self);
593 dvmAddTrackedAlloc(exception, self);
594 dvmClearException(self);
596 LOGV("Handling exception %s at %s:%d\n",
597 exception->clazz->descriptor, curMethod->name,
598 dvmLineNumFromPC(curMethod, pc - curMethod->insns));
600 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER)
602 * Tell the debugger about it.
604 * TODO: if the exception was thrown by interpreted code, control
605 * fell through native, and then back to us, we will report the
606 * exception at the point of the throw and again here. We can avoid
607 * this by not reporting exceptions when we jump here directly from
608 * the native call code above, but then we won't report exceptions
609 * that were thrown *from* the JNI code (as opposed to *through* it).
611 * The correct solution is probably to ignore from-native exceptions
612 * here, and have the JNI exception code do the reporting to the
615 if (gDvm.debuggerActive) {
617 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
618 exception, true, &catchFrame);
619 dvmDbgPostException(fp, pc - curMethod->insns, catchFrame,
620 catchRelPc, exception);
625 * We need to unroll to the catch block or the nearest "break"
628 * A break frame could indicate that we have reached an intermediate
629 * native call, or have gone off the top of the stack and the thread
630 * needs to exit. Either way, we return from here, leaving the
633 * If we do find a catch block, we want to transfer execution to
636 catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
637 exception, false, (void*)&fp);
640 * Restore the stack bounds after an overflow. This isn't going to
641 * be correct in all circumstances, e.g. if JNI code devours the
642 * exception this won't happen until some other exception gets
643 * thrown. If the code keeps pushing the stack bounds we'll end
644 * up aborting the VM.
646 * Note we want to do this *after* the call to dvmFindCatchBlock,
647 * because that may need extra stack space to resolve exception
648 * classes (e.g. through a class loader).
650 if (self->stackOverflowed)
651 dvmCleanupStackOverflow(self);
653 if (catchRelPc < 0) {
654 /* falling through to JNI code or off the bottom of the stack */
655 #if DVM_SHOW_EXCEPTION >= 2
656 LOGD("Exception %s from %s:%d not caught locally\n",
657 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
658 dvmLineNumFromPC(curMethod, pc - curMethod->insns));
660 dvmSetException(self, exception);
661 dvmReleaseTrackedAlloc(exception, self);
665 #if DVM_SHOW_EXCEPTION >= 3
667 const Method* catchMethod = SAVEAREA_FROM_FP(fp)->method;
668 LOGD("Exception %s thrown from %s:%d to %s:%d\n",
669 exception->clazz->descriptor, dvmGetMethodSourceFile(curMethod),
670 dvmLineNumFromPC(curMethod, pc - curMethod->insns),
671 dvmGetMethodSourceFile(catchMethod),
672 dvmLineNumFromPC(catchMethod, catchRelPc));
677 * Adjust local variables to match self->curFrame and the
680 //fp = (u4*) self->curFrame;
681 curMethod = SAVEAREA_FROM_FP(fp)->method;
682 //methodClass = curMethod->clazz;
683 methodClassDex = curMethod->clazz->pDvmDex;
684 pc = curMethod->insns + catchRelPc;
685 ILOGV("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
686 curMethod->name, curMethod->shorty);
687 DUMP_REGS(curMethod, fp, false); // show all regs
690 * Restore the exception if the handler wants it.
692 * The Dalvik spec mandates that, if an exception handler wants to
693 * do something with the exception, the first instruction executed
694 * must be "move-exception". We can pass the exception along
695 * through the thread struct, and let the move-exception instruction
698 * If the handler doesn't call move-exception, we don't want to
699 * finish here with an exception still pending.
701 if (INST_INST(FETCH(0)) == OP_MOVE_EXCEPTION)
702 dvmSetException(self, exception);
704 dvmReleaseTrackedAlloc(exception, self);
711 * General handling for invoke-{virtual,super,direct,static,interface},
712 * including "quick" variants.
714 * Set "methodToCall" to the Method we're calling, and "methodCallRange"
715 * depending on whether this is a "/range" instruction.
718 * "vsrc1" holds the argument count (8 bits)
719 * "vdst" holds the first argument in the range
720 * For a non-range call:
721 * "vsrc1" holds the argument count (4 bits) and the 5th argument index
722 * "vdst" holds four 4-bit register indices
724 * The caller must EXPORT_PC before jumping here, because any method
725 * call can throw a stack overflow exception.
727 GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall,
730 STUB_HACK(vsrc1 = count; vdst = regs; methodToCall = _methodToCall;);
732 //printf("range=%d call=%p count=%d regs=0x%04x\n",
733 // methodCallRange, methodToCall, count, regs);
734 //printf(" --> %s.%s %s\n", methodToCall->clazz->descriptor,
735 // methodToCall->name, methodToCall->shorty);
741 * Copy args. This may corrupt vsrc1/vdst.
743 if (methodCallRange) {
744 // could use memcpy or a "Duff's device"; most functions have
745 // so few args it won't matter much
746 assert(vsrc1 <= curMethod->outsSize);
747 assert(vsrc1 == methodToCall->insSize);
748 outs = OUTS_FROM_FP(fp, vsrc1);
749 for (i = 0; i < vsrc1; i++)
750 outs[i] = GET_REGISTER(vdst+i);
752 u4 count = vsrc1 >> 4;
754 assert(count <= curMethod->outsSize);
755 assert(count == methodToCall->insSize);
758 outs = OUTS_FROM_FP(fp, count);
761 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
764 for (i = 0; i < (int) count; i++) {
765 outs[i] = GET_REGISTER(vdst & 0x0f);
769 // This version executes fewer instructions but is larger
770 // overall. Seems to be a teensy bit faster.
771 assert((vdst >> 16) == 0); // 16 bits -or- high 16 bits clear
774 outs[4] = GET_REGISTER(vsrc1 & 0x0f);
776 outs[3] = GET_REGISTER(vdst >> 12);
778 outs[2] = GET_REGISTER((vdst & 0x0f00) >> 8);
780 outs[1] = GET_REGISTER((vdst & 0x00f0) >> 4);
782 outs[0] = GET_REGISTER(vdst & 0x0f);
791 * (This was originally a "goto" target; I've kept it separate from the
792 * stuff above in case we want to refactor things again.)
794 * At this point, we have the arguments stored in the "outs" area of
795 * the current method's stack frame, and the method to call in
796 * "methodToCall". Push a new stack frame.
799 StackSaveArea* newSaveArea;
802 ILOGV("> %s%s.%s %s",
803 dvmIsNativeMethod(methodToCall) ? "(NATIVE) " : "",
804 methodToCall->clazz->descriptor, methodToCall->name,
805 methodToCall->shorty);
807 newFp = (u4*) SAVEAREA_FROM_FP(fp) - methodToCall->registersSize;
808 newSaveArea = SAVEAREA_FROM_FP(newFp);
810 /* verify that we have enough space */
813 bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
814 if (bottom < self->interpStackEnd) {
816 LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')\n",
817 self->interpStackStart, self->interpStackEnd, bottom,
818 (u1*) fp - bottom, self->interpStackSize,
820 dvmHandleStackOverflow(self, methodToCall);
821 assert(dvmCheckException(self));
822 GOTO_exceptionThrown();
824 //LOGD("+++ fp=%p newFp=%p newSave=%p bottom=%p\n",
825 // fp, newFp, newSaveArea, bottom);
829 if (methodToCall->registersSize > methodToCall->insSize) {
831 * This makes valgrind quiet when we print registers that
832 * haven't been initialized. Turn it off when the debug
833 * messages are disabled -- we want valgrind to report any
834 * used-before-initialized issues.
837 (methodToCall->registersSize - methodToCall->insSize) * 4);
842 newSaveArea->prevSave = SAVEAREA_FROM_FP(fp);
844 newSaveArea->prevFrame = fp;
845 newSaveArea->savedPc = pc;
846 #if defined(WITH_JIT)
847 newSaveArea->returnAddr = 0;
849 newSaveArea->method = methodToCall;
851 if (!dvmIsNativeMethod(methodToCall)) {
853 * "Call" interpreted code. Reposition the PC, update the
854 * frame pointer and other local state, and continue.
856 curMethod = methodToCall;
857 methodClassDex = curMethod->clazz->pDvmDex;
858 pc = methodToCall->insns;
859 fp = self->curFrame = newFp;
861 debugSaveArea = SAVEAREA_FROM_FP(newFp);
863 #if INTERP_TYPE == INTERP_DBG
864 debugIsMethodEntry = true; // profiling, debugging
866 ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
867 curMethod->name, curMethod->shorty);
868 DUMP_REGS(curMethod, fp, true); // show input args
869 FINISH(0); // jump to method start
871 /* set this up for JNI locals, even if not a JNI native */
872 #ifdef USE_INDIRECT_REF
873 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
875 newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.nextEntry;
878 self->curFrame = newFp;
880 DUMP_REGS(methodToCall, newFp, true); // show input args
882 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER)
883 if (gDvm.debuggerActive) {
884 dvmDbgPostLocationEvent(methodToCall, -1,
885 dvmGetThisPtr(curMethod, fp), DBG_METHOD_ENTRY);
888 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER)
889 TRACE_METHOD_ENTER(self, methodToCall);
892 ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
893 methodToCall->name, methodToCall->shorty);
896 * Jump through native call bridge. Because we leave no
897 * space for locals on native calls, "newFp" points directly
898 * to the method arguments.
900 (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
902 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER)
903 if (gDvm.debuggerActive) {
904 dvmDbgPostLocationEvent(methodToCall, -1,
905 dvmGetThisPtr(curMethod, fp), DBG_METHOD_EXIT);
908 #if (INTERP_TYPE == INTERP_DBG) && defined(WITH_PROFILER)
909 TRACE_METHOD_EXIT(self, methodToCall);
913 dvmPopJniLocals(self, newSaveArea);
917 * If the native code threw an exception, or interpreted code
918 * invoked by the native call threw one and nobody has cleared
919 * it, jump to our local exception handling.
921 if (dvmCheckException(self)) {
922 LOGV("Exception thrown by/below native code\n");
923 GOTO_exceptionThrown();
926 ILOGD("> retval=0x%llx (leaving native)", retval.j);
927 ILOGD("> (return from native %s.%s to %s.%s %s)",
928 methodToCall->clazz->descriptor, methodToCall->name,
929 curMethod->clazz->descriptor, curMethod->name,
932 //u2 invokeInstr = INST_INST(FETCH(0));
933 if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
934 invokeInstr <= OP_INVOKE_INTERFACE*/)
938 //LOGE("Unknown invoke instr %02x at %d\n",
939 // invokeInstr, (int) (pc - curMethod->insns));
944 assert(false); // should not get here