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