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