New changes to enable self verification mode.
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 9079da1..3dca45b 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -33,6 +33,285 @@
#include "compiler/CompilerIR.h"
#include <errno.h>
+#if defined(WITH_SELF_VERIFICATION)
+/* Allocate space for per-thread ShadowSpace data structures */
+void* dvmSelfVerificationShadowSpaceAlloc(Thread* self)
+{
+ self->shadowSpace = (ShadowSpace*) calloc(1, sizeof(ShadowSpace));
+ if (self->shadowSpace == NULL)
+ return NULL;
+
+ self->shadowSpace->registerSpaceSize = REG_SPACE;
+ self->shadowSpace->registerSpace =
+ (int*) calloc(self->shadowSpace->registerSpaceSize, sizeof(int));
+
+ return self->shadowSpace->registerSpace;
+}
+
+/* Free per-thread ShadowSpace data structures */
+void dvmSelfVerificationShadowSpaceFree(Thread* self)
+{
+ free(self->shadowSpace->registerSpace);
+ free(self->shadowSpace);
+}
+
+/*
+ * Save out PC, FP, InterpState, and registers to shadow space.
+ * Return a pointer to the shadow space for JIT to use.
+ */
+void* dvmSelfVerificationSaveState(const u2* pc, const void* fp,
+ void* interpStatePtr)
+{
+ Thread *self = dvmThreadSelf();
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ InterpState *interpState = (InterpState *) interpStatePtr;
+ int preBytes = interpState->method->outsSize*4 + sizeof(StackSaveArea);
+ int postBytes = interpState->method->registersSize*4;
+
+ //LOGD("### selfVerificationSaveState(%d) pc: 0x%x fp: 0x%x",
+ // self->threadId, (int)pc, (int)fp);
+
+ if (shadowSpace->selfVerificationState != kSVSIdle) {
+ LOGD("~~~ Save: INCORRECT PREVIOUS STATE(%d): %d",
+ self->threadId, shadowSpace->selfVerificationState);
+ LOGD("********** SHADOW STATE DUMP **********");
+ LOGD("* PC: 0x%x FP: 0x%x", (int)pc, (int)fp);
+ }
+ shadowSpace->selfVerificationState = kSVSStart;
+
+ // Dynamically grow shadow register space if necessary
+ while (preBytes + postBytes > shadowSpace->registerSpaceSize) {
+ shadowSpace->registerSpaceSize *= 2;
+ free(shadowSpace->registerSpace);
+ shadowSpace->registerSpace =
+ (int*) calloc(shadowSpace->registerSpaceSize, sizeof(int));
+ }
+
+ // Remember original state
+ shadowSpace->startPC = pc;
+ shadowSpace->fp = fp;
+ shadowSpace->glue = interpStatePtr;
+ shadowSpace->shadowFP = shadowSpace->registerSpace +
+ shadowSpace->registerSpaceSize - postBytes/4;
+
+ // Create a copy of the InterpState
+ memcpy(&(shadowSpace->interpState), interpStatePtr, sizeof(InterpState));
+ shadowSpace->interpState.fp = shadowSpace->shadowFP;
+ shadowSpace->interpState.interpStackEnd = (u1*)shadowSpace->registerSpace;
+
+ // Create a copy of the stack
+ memcpy(((char*)shadowSpace->shadowFP)-preBytes, ((char*)fp)-preBytes,
+ preBytes+postBytes);
+
+ // Setup the shadowed heap space
+ shadowSpace->heapSpaceTail = shadowSpace->heapSpace;
+
+ // Reset trace length
+ shadowSpace->traceLength = 0;
+
+ return shadowSpace;
+}
+
+/*
+ * Save ending PC, FP and compiled code exit point to shadow space.
+ * Return a pointer to the shadow space for JIT to restore state.
+ */
+void* dvmSelfVerificationRestoreState(const u2* pc, const void* fp,
+ SelfVerificationState exitPoint)
+{
+ Thread *self = dvmThreadSelf();
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ shadowSpace->endPC = pc;
+ shadowSpace->endShadowFP = fp;
+
+ //LOGD("### selfVerificationRestoreState(%d) pc: 0x%x fp: 0x%x endPC: 0x%x",
+ // self->threadId, (int)shadowSpace->startPC, (int)shadowSpace->fp,
+ // (int)pc);
+
+ if (shadowSpace->selfVerificationState != kSVSStart) {
+ LOGD("~~~ Restore: INCORRECT PREVIOUS STATE(%d): %d",
+ self->threadId, shadowSpace->selfVerificationState);
+ LOGD("********** SHADOW STATE DUMP **********");
+ LOGD("* Dalvik PC: 0x%x endPC: 0x%x", (int)shadowSpace->startPC,
+ (int)shadowSpace->endPC);
+ LOGD("* Interp FP: 0x%x", (int)shadowSpace->fp);
+ LOGD("* Shadow FP: 0x%x endFP: 0x%x", (int)shadowSpace->shadowFP,
+ (int)shadowSpace->endShadowFP);
+ }
+
+ // Special case when punting after a single instruction
+ if (exitPoint == kSVSPunt && pc == shadowSpace->startPC) {
+ shadowSpace->selfVerificationState = kSVSIdle;
+ } else {
+ shadowSpace->selfVerificationState = exitPoint;
+ }
+
+ return shadowSpace;
+}
+
+/* Print contents of virtual registers */
+static void selfVerificationPrintRegisters(int* addr, int numWords)
+{
+ int i;
+ for (i = 0; i < numWords; i++) {
+ LOGD("* 0x%x: (v%d) 0x%8x", (int)(addr+i), i, *(addr+i));
+ }
+}
+
+/* Print values maintained in shadowSpace */
+static void selfVerificationDumpState(const u2* pc, Thread* self)
+{
+ ShadowSpace* shadowSpace = self->shadowSpace;
+ StackSaveArea* stackSave = SAVEAREA_FROM_FP(self->curFrame);
+ int frameBytes = (int) shadowSpace->registerSpace +
+ shadowSpace->registerSpaceSize*4 -
+ (int) shadowSpace->shadowFP;
+ int localRegs = 0;
+ int frameBytes2 = 0;
+ if (self->curFrame < shadowSpace->fp) {
+ localRegs = (stackSave->method->registersSize -
+ stackSave->method->insSize)*4;
+ frameBytes2 = (int) shadowSpace->fp - (int) self->curFrame - localRegs;
+ }
+ LOGD("********** SHADOW STATE DUMP **********");
+ LOGD("* CurrentPC: 0x%x, Offset: 0x%04x", (int)pc,
+ (int)(pc - stackSave->method->insns));
+ LOGD("* Class: %s Method: %s", stackSave->method->clazz->descriptor,
+ stackSave->method->name);
+ LOGD("* Dalvik PC: 0x%x endPC: 0x%x", (int)shadowSpace->startPC,
+ (int)shadowSpace->endPC);
+ LOGD("* Interp FP: 0x%x endFP: 0x%x", (int)shadowSpace->fp,
+ (int)self->curFrame);
+ LOGD("* Shadow FP: 0x%x endFP: 0x%x", (int)shadowSpace->shadowFP,
+ (int)shadowSpace->endShadowFP);
+ LOGD("* Frame1 Bytes: %d Frame2 Local: %d Bytes: %d", frameBytes,
+ localRegs, frameBytes2);
+ LOGD("* Trace length: %d State: %d", shadowSpace->traceLength,
+ shadowSpace->selfVerificationState);
+}
+
+/* Print decoded instructions in the current trace */
+static void selfVerificationDumpTrace(const u2* pc, Thread* self)
+{
+ ShadowSpace* shadowSpace = self->shadowSpace;
+ StackSaveArea* stackSave = SAVEAREA_FROM_FP(self->curFrame);
+ int i;
+ u2 *addr, *offset;
+ OpCode opcode;
+
+ LOGD("********** SHADOW TRACE DUMP **********");
+ for (i = 0; i < shadowSpace->traceLength; i++) {
+ addr = (u2*) shadowSpace->trace[i].addr;
+ offset = (u2*)(addr - stackSave->method->insns);
+ opcode = (OpCode) shadowSpace->trace[i].opcode;
+ LOGD("* 0x%x: (0x%04x) %s", (int)addr, (int)offset,
+ getOpcodeName(opcode));
+ }
+}
+
+/* Manage self verification while in the debug interpreter */
+static bool selfVerificationDebugInterp(const u2* pc, Thread* self)
+{
+ ShadowSpace *shadowSpace = self->shadowSpace;
+ OpCode opcode = *pc & 0xff;
+ SelfVerificationState state = shadowSpace->selfVerificationState;
+ //LOGD("### DbgIntp(%d): PC: 0x%x endPC: 0x%x state: %d len: %d %s",
+ // self->threadId, (int)pc, (int)shadowSpace->endPC, state,
+ // shadowSpace->traceLength, getOpcodeName(opcode));
+
+ if (state == kSVSIdle || state == kSVSStart) {
+ LOGD("~~~ DbgIntrp: INCORRECT PREVIOUS STATE(%d): %d",
+ self->threadId, state);
+ selfVerificationDumpState(pc, self);
+ selfVerificationDumpTrace(pc, self);
+ }
+
+ /* Skip endPC once when trace has a backward branch */
+ if ((state == kSVSBackwardBranch && pc == shadowSpace->endPC) ||
+ state != kSVSBackwardBranch) {
+ shadowSpace->selfVerificationState = kSVSDebugInterp;
+ }
+
+ /* Check that the current pc is the end of the trace */
+ if ((state == kSVSSingleStep || state == kSVSDebugInterp) &&
+ pc == shadowSpace->endPC) {
+
+ shadowSpace->selfVerificationState = kSVSIdle;
+
+ /* Check register space */
+ int frameBytes = (int) shadowSpace->registerSpace +
+ shadowSpace->registerSpaceSize*4 -
+ (int) shadowSpace->shadowFP;
+ if (memcmp(shadowSpace->fp, shadowSpace->shadowFP, frameBytes)) {
+ LOGD("~~~ DbgIntp(%d): REGISTERS UNEQUAL!", self->threadId);
+ selfVerificationDumpState(pc, self);
+ selfVerificationDumpTrace(pc, self);
+ LOGD("*** Interp Registers: addr: 0x%x bytes: %d",
+ (int)shadowSpace->fp, frameBytes);
+ selfVerificationPrintRegisters((int*)shadowSpace->fp, frameBytes/4);
+ LOGD("*** Shadow Registers: addr: 0x%x bytes: %d",
+ (int)shadowSpace->shadowFP, frameBytes);
+ selfVerificationPrintRegisters((int*)shadowSpace->shadowFP,
+ frameBytes/4);
+ }
+ /* Check new frame if it exists (invokes only) */
+ if (self->curFrame < shadowSpace->fp) {
+ StackSaveArea* stackSave = SAVEAREA_FROM_FP(self->curFrame);
+ int localRegs = (stackSave->method->registersSize -
+ stackSave->method->insSize)*4;
+ int frameBytes2 = (int) shadowSpace->fp -
+ (int) self->curFrame - localRegs;
+ if (memcmp(((char*)self->curFrame)+localRegs,
+ ((char*)shadowSpace->endShadowFP)+localRegs, frameBytes2)) {
+ LOGD("~~~ DbgIntp(%d): REGISTERS (FRAME2) UNEQUAL!",
+ self->threadId);
+ selfVerificationDumpState(pc, self);
+ selfVerificationDumpTrace(pc, self);
+ LOGD("*** Interp Registers: addr: 0x%x l: %d bytes: %d",
+ (int)self->curFrame, localRegs, frameBytes2);
+ selfVerificationPrintRegisters((int*)self->curFrame,
+ (frameBytes2+localRegs)/4);
+ LOGD("*** Shadow Registers: addr: 0x%x l: %d bytes: %d",
+ (int)shadowSpace->endShadowFP, localRegs, frameBytes2);
+ selfVerificationPrintRegisters((int*)shadowSpace->endShadowFP,
+ (frameBytes2+localRegs)/4);
+ }
+ }
+
+ /* Check memory space */
+ ShadowHeap* heapSpacePtr;
+ for (heapSpacePtr = shadowSpace->heapSpace;
+ heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
+ int mem_data = *((unsigned int*) heapSpacePtr->addr);
+ if (heapSpacePtr->data != mem_data) {
+ LOGD("~~~ DbgIntp(%d): MEMORY UNEQUAL!", self->threadId);
+ LOGD("* Addr: 0x%x Intrp Data: 0x%x Jit Data: 0x%x",
+ heapSpacePtr->addr, mem_data, heapSpacePtr->data);
+ selfVerificationDumpState(pc, self);
+ selfVerificationDumpTrace(pc, self);
+ }
+ }
+ return true;
+
+ /* If end not been reached, make sure max length not exceeded */
+ } else if (shadowSpace->traceLength >= JIT_MAX_TRACE_LEN) {
+ LOGD("~~~ DbgIntp(%d): CONTROL DIVERGENCE!", self->threadId);
+ LOGD("* startPC: 0x%x endPC: 0x%x currPC: 0x%x",
+ (int)shadowSpace->startPC, (int)shadowSpace->endPC, (int)pc);
+ selfVerificationDumpState(pc, self);
+ selfVerificationDumpTrace(pc, self);
+
+ return true;
+ }
+ /* Log the instruction address and opcode for debug */
+ shadowSpace->trace[shadowSpace->traceLength].addr = (int)pc;
+ shadowSpace->trace[shadowSpace->traceLength].opcode = opcode;
+ shadowSpace->traceLength++;
+
+ return false;
+}
+#endif
+
int dvmJitStartup(void)
{
unsigned int i;
@@ -325,6 +604,14 @@
case kJitNormal:
switchInterp = !debugOrProfile;
break;
+#if defined(WITH_SELF_VERIFICATION)
+ case kJitSelfVerification:
+ if (selfVerificationDebugInterp(pc, self)) {
+ interpState->jitState = kJitNormal;
+ switchInterp = !debugOrProfile;
+ }
+ break;
+#endif
default:
dvmAbort();
}
@@ -584,6 +871,9 @@
case kJitSingleStepEnd:
case kJitOff:
case kJitNormal:
+#if defined(WITH_SELF_VERIFICATION)
+ case kJitSelfVerification:
+#endif
break;
default:
dvmAbort();