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