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