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