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