gotoTargets.cpp revision e8e1ddccd616e8226b7cc1e4e9fdb327429249e8
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)
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            LOGE("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);
103GOTO_TARGET_END
104
105
106GOTO_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    }
200GOTO_TARGET_END
201
202GOTO_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    }
278GOTO_TARGET_END
279
280GOTO_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    }
329GOTO_TARGET_END
330
331GOTO_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    }
365GOTO_TARGET_END
366
367GOTO_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);
403GOTO_TARGET_END
404
405GOTO_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    }
462GOTO_TARGET_END
463
464GOTO_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    }
521GOTO_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     */
528GOTO_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            //LOGE("Unknown invoke instr %02x at %d",
586            //    invokeInstr, (int) (pc - curMethod->insns));
587            assert(false);
588        }
589    }
590GOTO_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     */
599GOTO_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    }
737GOTO_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     */
758GOTO_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            self->interpSave.curFrame = fp = newFp;
902#ifdef EASY_GDB
903            debugSaveArea = SAVEAREA_FROM_FP(newFp);
904#endif
905            self->debugIsMethodEntry = true;        // profiling, debugging
906            ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
907                curMethod->name, curMethod->shorty);
908            DUMP_REGS(curMethod, fp, true);         // show input args
909            FINISH(0);                              // jump to method start
910        } else {
911            /* set this up for JNI locals, even if not a JNI native */
912            newSaveArea->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
913
914            self->interpSave.curFrame = newFp;
915
916            DUMP_REGS(methodToCall, newFp, true);   // show input args
917
918            if (self->interpBreak.ctl.subMode != 0) {
919                dvmReportPreNativeInvoke(methodToCall, self, fp);
920            }
921
922            ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
923                  methodToCall->name, methodToCall->shorty);
924
925            /*
926             * Jump through native call bridge.  Because we leave no
927             * space for locals on native calls, "newFp" points directly
928             * to the method arguments.
929             */
930            (*methodToCall->nativeFunc)(newFp, &retval, methodToCall, self);
931
932            if (self->interpBreak.ctl.subMode != 0) {
933                dvmReportPostNativeInvoke(methodToCall, self, fp);
934            }
935
936            /* pop frame off */
937            dvmPopJniLocals(self, newSaveArea);
938            self->interpSave.curFrame = fp;
939
940            /*
941             * If the native code threw an exception, or interpreted code
942             * invoked by the native call threw one and nobody has cleared
943             * it, jump to our local exception handling.
944             */
945            if (dvmCheckException(self)) {
946                ALOGV("Exception thrown by/below native code");
947                GOTO_exceptionThrown();
948            }
949
950            ILOGD("> retval=0x%llx (leaving native)", retval.j);
951            ILOGD("> (return from native %s.%s to %s.%s %s)",
952                methodToCall->clazz->descriptor, methodToCall->name,
953                curMethod->clazz->descriptor, curMethod->name,
954                curMethod->shorty);
955
956            //u2 invokeInstr = INST_INST(FETCH(0));
957            if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
958                invokeInstr <= OP_INVOKE_INTERFACE*/)
959            {
960                FINISH(3);
961            } else {
962                //LOGE("Unknown invoke instr %02x at %d",
963                //    invokeInstr, (int) (pc - curMethod->insns));
964                assert(false);
965            }
966        }
967    }
968    assert(false);      // should not get here
969GOTO_TARGET_END
970