dvmLockThreadList(self);
breakFlags = self->interpBreak.ctl.breakFlags;
subMode = self->interpBreak.ctl.subMode;
+ #ifndef DVM_NO_ASM_INTERP
handlerTable = self->interpBreak.ctl.curHandlerTable;
+ #endif
for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
if (subMode != thread->interpBreak.ctl.subMode) {
- LOGD("Warning: subMode mismatch - %#x:%#x, tid[%d]",
+ ALOGD("Warning: subMode mismatch - %#x:%#x, tid[%d]",
subMode,thread->interpBreak.ctl.subMode,thread->threadId);
}
if (breakFlags != thread->interpBreak.ctl.breakFlags) {
- LOGD("Warning: breakFlags mismatch - %#x:%#x, tid[%d]",
+ ALOGD("Warning: breakFlags mismatch - %#x:%#x, tid[%d]",
breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId);
}
+ #ifndef DVM_NO_ASM_INTERP
if (handlerTable != thread->interpBreak.ctl.curHandlerTable) {
- LOGD("Warning: curHandlerTable mismatch - %#x:%#x, tid[%d]",
+ ALOGD("Warning: curHandlerTable mismatch - %#x:%#x, tid[%d]",
(int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable,
thread->threadId);
}
+ #endif
#if defined(WITH_JIT)
if (thread->pJitProfTable != gDvmJit.pProfTable) {
- LOGD("Warning: pJitProfTable mismatch - %#x:%#x, tid[%d]",
+ ALOGD("Warning: pJitProfTable mismatch - %#x:%#x, tid[%d]",
(int)thread->pJitProfTable,(int)gDvmJit.pProfTable,
thread->threadId);
}
HANDLE_SPUT_X(OP_SPUT_OBJECT_VOLATILE, "-object-volatile", ObjectVolatile, _AS_OBJECT)
OP_END
-/* File: c/OP_DISPATCH_FF.cpp */
-HANDLE_OPCODE(OP_DISPATCH_FF)
+/* File: c/OP_UNUSED_FF.cpp */
+HANDLE_OPCODE(OP_UNUSED_FF)
/*
- * Indicates extended opcode. Use next 8 bits to choose where to branch.
+ * In portable interp, most unused opcodes will fall through to here.
*/
- DISPATCH_EXTENDED(INST_AA(inst));
+ ALOGE("unknown opcode 0x%02x\n", INST_INST(inst));
+ dvmAbort();
+ FINISH(1);
OP_END
-/* File: c/OP_CONST_CLASS_JUMBO.cpp */
-HANDLE_OPCODE(OP_CONST_CLASS_JUMBO /*vBBBB, class@AAAAAAAA*/)
- {
- ClassObject* clazz;
+/* File: cstubs/entry.cpp */
+/*
+ * Handler function table, one entry per opcode.
+ */
+#undef H
- #define H(_op) dvmMterp_##_op
++#define H(_op) (const void*) dvmMterp_##_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlers)
- ref = FETCH(1) | (u4)FETCH(2) << 16;
- vdst = FETCH(3);
- ILOGV("|const-class/jumbo v%d class@0x%08x", vdst, ref);
- clazz = dvmDexGetResolvedClass(methodClassDex, ref);
- if (clazz == NULL) {
- EXPORT_PC();
- clazz = dvmResolveClass(curMethod->clazz, ref, true);
- if (clazz == NULL)
- GOTO_exceptionThrown();
- }
- SET_REGISTER(vdst, (u4) clazz);
- }
- FINISH(4);
-OP_END
+#undef H
+#define H(_op) #_op
+DEFINE_GOTO_TABLE(gDvmMterpHandlerNames)
-/* File: c/OP_CHECK_CAST_JUMBO.cpp */
-HANDLE_OPCODE(OP_CHECK_CAST_JUMBO /*vBBBB, class@AAAAAAAA*/)
- {
- ClassObject* clazz;
- Object* obj;
+#include <setjmp.h>
- EXPORT_PC();
+/*
+ * C mterp entry point. This just calls the various C fallbacks, making
+ * this a slow but portable interpeter.
+ *
+ * This is only used for the "allstubs" variant.
+ */
+void dvmMterpStdRun(Thread* self)
+{
+ jmp_buf jmpBuf;
- self->bailPtr = &jmpBuf;
- ref = FETCH(1) | (u4)FETCH(2) << 16; /* class to check against */
- vsrc1 = FETCH(3);
- ILOGV("|check-cast/jumbo v%d,class@0x%08x", vsrc1, ref);
++ self->interpSave.bailPtr = &jmpBuf;
- obj = (Object*)GET_REGISTER(vsrc1);
- if (obj != NULL) {
-#if defined(WITH_EXTRA_OBJECT_VALIDATION)
- if (!checkForNull(obj))
- GOTO_exceptionThrown();
-#endif
- clazz = dvmDexGetResolvedClass(methodClassDex, ref);
- if (clazz == NULL) {
- clazz = dvmResolveClass(curMethod->clazz, ref, false);
- if (clazz == NULL)
- GOTO_exceptionThrown();
- }
- if (!dvmInstanceof(obj->clazz, clazz)) {
- dvmThrowClassCastException(obj->clazz, clazz);
- GOTO_exceptionThrown();
- }
- }
+ /* We exit via a longjmp */
+ if (setjmp(jmpBuf)) {
+ LOGVV("mterp threadid=%d returning", dvmThreadSelf()->threadId);
- return
++ return;
}
- FINISH(4);
-OP_END
-
-/* File: c/OP_INSTANCE_OF_JUMBO.cpp */
-HANDLE_OPCODE(OP_INSTANCE_OF_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
- {
- ClassObject* clazz;
- Object* obj;
- ref = FETCH(1) | (u4)FETCH(2) << 16; /* class to check against */
- vdst = FETCH(3);
- vsrc1 = FETCH(4); /* object to check */
- ILOGV("|instance-of/jumbo v%d,v%d,class@0x%08x", vdst, vsrc1, ref);
+ /* run until somebody longjmp()s out */
+ while (true) {
+ typedef void (*Handler)(Thread* self);
- obj = (Object*)GET_REGISTER(vsrc1);
- if (obj == NULL) {
- SET_REGISTER(vdst, 0);
- } else {
-#if defined(WITH_EXTRA_OBJECT_VALIDATION)
- if (!checkForNullExportPC(obj, fp, pc))
- GOTO_exceptionThrown();
-#endif
- clazz = dvmDexGetResolvedClass(methodClassDex, ref);
- if (clazz == NULL) {
- EXPORT_PC();
- clazz = dvmResolveClass(curMethod->clazz, ref, true);
- if (clazz == NULL)
- GOTO_exceptionThrown();
- }
- SET_REGISTER(vdst, dvmInstanceof(obj->clazz, clazz));
+ u2 inst = /*self->interpSave.*/pc[0];
+ /*
+ * In mterp, dvmCheckBefore is handled via the altHandlerTable,
+ * while in the portable interpreter it is part of the handler
+ * FINISH code. For allstubs, we must do an explicit check
+ * in the interpretation loop.
+ */
- if (self-interpBreak.ctl.subMode) {
- dvmCheckBefore(pc, fp, self, curMethod);
++ if (self->interpBreak.ctl.subMode) {
++ dvmCheckBefore(pc, fp, self);
}
+ Handler handler = (Handler) gDvmMterpHandlers[inst & 0xff];
+ (void) gDvmMterpHandlerNames; /* avoid gcc "defined but not used" */
+ LOGVV("handler %p %s",
+ handler, (const char*) gDvmMterpHandlerNames[inst & 0xff]);
+ (*handler)(self);
}
- FINISH(5);
-OP_END
-
-/* File: c/OP_NEW_INSTANCE_JUMBO.cpp */
-HANDLE_OPCODE(OP_NEW_INSTANCE_JUMBO /*vBBBB, class@AAAAAAAA*/)
- {
- ClassObject* clazz;
- Object* newObj;
-
- EXPORT_PC();
-
- ref = FETCH(1) | (u4)FETCH(2) << 16;
- vdst = FETCH(3);
- ILOGV("|new-instance/jumbo v%d,class@0x%08x", vdst, ref);
- clazz = dvmDexGetResolvedClass(methodClassDex, ref);
- if (clazz == NULL) {
- clazz = dvmResolveClass(curMethod->clazz, ref, false);
- if (clazz == NULL)
- GOTO_exceptionThrown();
- }
+}
- if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))
- GOTO_exceptionThrown();
+/*
+ * C mterp exit point. Call here to bail out of the interpreter.
+ */
+void dvmMterpStdBail(Thread* self)
+{
- jmp_buf* pJmpBuf = self->bailPtr;
++ jmp_buf* pJmpBuf = (jmp_buf*) self->interpSave.bailPtr;
+ longjmp(*pJmpBuf, 1);
+}
-#if defined(WITH_JIT)
- /*
- * The JIT needs dvmDexGetResolvedClass() to return non-null.
- * Since we use the portable interpreter to build the trace, this extra
- * check is not needed for mterp.
- */
- if ((self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) &&
- (!dvmDexGetResolvedClass(methodClassDex, ref))) {
- /* Class initialization is still ongoing - end the trace */
- dvmJitEndTraceSelect(self,pc);
- }
-#endif
+/* File: c/gotoTargets.cpp */
+/*
+ * C footer. This has some common code shared by the various targets.
+ */
- /*
- * Verifier now tests for interface/abstract class.
- */
- //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
- // dvmThrowExceptionWithClassMessage(gDvm.exInstantiationError,
- // clazz->descriptor);
- // GOTO_exceptionThrown();
- //}
- newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
- if (newObj == NULL)
- GOTO_exceptionThrown();
- SET_REGISTER(vdst, (u4) newObj);
- }
- FINISH(4);
-OP_END
+/*
+ * Everything from here on is a "goto target". In the basic interpreter
+ * we jump into these targets and then jump directly to the handler for
+ * next instruction. Here, these are subroutines that return to the caller.
+ */
-/* File: c/OP_NEW_ARRAY_JUMBO.cpp */
-HANDLE_OPCODE(OP_NEW_ARRAY_JUMBO /*vBBBB, vCCCC, class@AAAAAAAA*/)
+GOTO_TARGET(filledNewArray, bool methodCallRange, bool)
{
ClassObject* arrayClass;
ArrayObject* newArray;