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