• 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, newSaveArea->prevFrame);
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, newSaveArea->prevFrame);
935              }
936  
937              /* pop frame off */
938              dvmPopJniLocals(self, newSaveArea);
939              self->interpSave.curFrame = newSaveArea->prevFrame;
940              fp = newSaveArea->prevFrame;
941  
942              /*
943               * If the native code threw an exception, or interpreted code
944               * invoked by the native call threw one and nobody has cleared
945               * it, jump to our local exception handling.
946               */
947              if (dvmCheckException(self)) {
948                  ALOGV("Exception thrown by/below native code");
949                  GOTO_exceptionThrown();
950              }
951  
952              ILOGD("> retval=0x%llx (leaving native)", retval.j);
953              ILOGD("> (return from native %s.%s to %s.%s %s)",
954                  methodToCall->clazz->descriptor, methodToCall->name,
955                  curMethod->clazz->descriptor, curMethod->name,
956                  curMethod->shorty);
957  
958              //u2 invokeInstr = INST_INST(FETCH(0));
959              if (true /*invokeInstr >= OP_INVOKE_VIRTUAL &&
960                  invokeInstr <= OP_INVOKE_INTERFACE*/)
961              {
962                  FINISH(3);
963              } else {
964                  //ALOGE("Unknown invoke instr %02x at %d",
965                  //    invokeInstr, (int) (pc - curMethod->insns));
966                  assert(false);
967              }
968          }
969      }
970      assert(false);      // should not get here
971  GOTO_TARGET_END
972