Improve JIT self verifier test coverage to follow single-step instructions.
Bug: 2549326
Change-Id: I01412d4aac1379b61c90fe6e59c534b33be93f66
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 1be8096..dad3a4c 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -78,6 +78,20 @@
}
shadowSpace->selfVerificationState = kSVSStart;
+ if (interpState->entryPoint == kInterpEntryResume) {
+ interpState->entryPoint = kInterpEntryInstr;
+#if 0
+ /* Tracking the success rate of resume after single-stepping */
+ if (interpState->jitResumeDPC == pc) {
+ LOGD("SV single step resumed at %p", pc);
+ }
+ else {
+ LOGD("real %p DPC %p NPC %p", pc, interpState->jitResumeDPC,
+ interpState->jitResumeNPC);
+ }
+#endif
+ }
+
// Dynamically grow shadow register space if necessary
if (preBytes + postBytes > shadowSpace->registerSpaceSize * sizeof(u4)) {
free(shadowSpace->registerSpace);
@@ -99,7 +113,6 @@
shadowSpace->registerSpaceSize - postBytes/4;
// Create a copy of the InterpState
- //shadowSpace->interpState = *interpState;
memcpy(&(shadowSpace->interpState), interpState, sizeof(InterpState));
shadowSpace->interpState.fp = shadowSpace->shadowFP;
shadowSpace->interpState.interpStackEnd = (u1*)shadowSpace->registerSpace;
@@ -126,6 +139,8 @@
{
Thread *self = dvmThreadSelf();
ShadowSpace *shadowSpace = self->shadowSpace;
+ // Official InterpState structure
+ InterpState *realGlue = shadowSpace->glue;
shadowSpace->endPC = pc;
shadowSpace->endShadowFP = fp;
@@ -144,9 +159,18 @@
(int)shadowSpace->endShadowFP);
}
+ // Move the resume [ND]PC from the shadow space to the real space so that
+ // the debug interpreter can return to the translation
+ if (exitPoint == kSVSSingleStep) {
+ realGlue->jitResumeNPC = shadowSpace->interpState.jitResumeNPC;
+ realGlue->jitResumeDPC = shadowSpace->interpState.jitResumeDPC;
+ } else {
+ realGlue->jitResumeNPC = NULL;
+ realGlue->jitResumeDPC = NULL;
+ }
+
// Special case when punting after a single instruction
- if ((exitPoint == kSVSPunt || exitPoint == kSVSSingleStep) &&
- pc == shadowSpace->startPC) {
+ if (exitPoint == kSVSPunt && pc == shadowSpace->startPC) {
shadowSpace->selfVerificationState = kSVSIdle;
} else {
shadowSpace->selfVerificationState = exitPoint;
@@ -232,7 +256,8 @@
}
/* Manage self verification while in the debug interpreter */
-static bool selfVerificationDebugInterp(const u2* pc, Thread* self)
+static bool selfVerificationDebugInterp(const u2* pc, Thread* self,
+ InterpState *interpState)
{
ShadowSpace *shadowSpace = self->shadowSpace;
SelfVerificationState state = shadowSpace->selfVerificationState;
@@ -251,14 +276,18 @@
selfVerificationDumpTrace(pc, self);
}
- /* Skip endPC once when trace has a backward branch */
+ /*
+ * Skip endPC once when trace has a backward branch. If the SV state is
+ * single step, keep it that way.
+ */
if ((state == kSVSBackwardBranch && pc == shadowSpace->endPC) ||
- state != kSVSBackwardBranch) {
+ (state != kSVSBackwardBranch && state != kSVSSingleStep)) {
shadowSpace->selfVerificationState = kSVSDebugInterp;
}
/* Check that the current pc is the end of the trace */
- if (state == kSVSDebugInterp && pc == shadowSpace->endPC) {
+ if ((state == kSVSDebugInterp || state == kSVSSingleStep) &&
+ pc == shadowSpace->endPC) {
shadowSpace->selfVerificationState = kSVSIdle;
@@ -325,6 +354,14 @@
}
}
if (memDiff) selfVerificationSpinLoop(shadowSpace);
+
+ /*
+ * Switch to JIT single step mode to stay in the debug interpreter for
+ * one more instruction
+ */
+ if (state == kSVSSingleStep) {
+ interpState->jitState = kJitSingleStepEnd;
+ }
return true;
/* If end not been reached, make sure max length not exceeded */
@@ -468,25 +505,6 @@
interpState->jitState = kJitTSelectAbort;
}
-#if defined(WITH_SELF_VERIFICATION)
-static bool selfVerificationPuntOps(DecodedInstruction *decInsn)
-{
- OpCode op = decInsn->opCode;
- int flags = dexGetInstrFlags(gDvm.instrFlags, op);
- /*
- * All opcodes that can throw exceptions and use the
- * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
- * under self-verification mode.
- */
- return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
- op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY ||
- op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION ||
- op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE ||
- op == OP_EXECUTE_INLINE_RANGE ||
- (flags & kInstrInvoke));
-}
-#endif
-
/*
* Find an entry in the JitTable, creating if necessary.
* Returns null if table is full.
@@ -605,21 +623,6 @@
const u2 *lastPC = interpState->lastPC;
interpState->lastPC = pc;
-#if defined(WITH_SELF_VERIFICATION)
- /*
- * We can't allow some instructions to be executed twice, and so they
- * must not appear in any translations. End the trace before they
- * are inlcluded.
- */
- if (lastPC && interpState->jitState == kJitTSelect) {
- DecodedInstruction decInsn;
- dexDecodeInstruction(gDvm.instrFormat, lastPC, &decInsn);
- if (selfVerificationPuntOps(&decInsn)) {
- interpState->jitState = kJitTSelectEnd;
- }
- }
-#endif
-
switch (interpState->jitState) {
char* nopStr;
int target;
@@ -777,9 +780,15 @@
break;
#if defined(WITH_SELF_VERIFICATION)
case kJitSelfVerification:
- if (selfVerificationDebugInterp(pc, self)) {
- interpState->jitState = kJitNormal;
- switchInterp = !debugOrProfile;
+ if (selfVerificationDebugInterp(pc, self, interpState)) {
+ /*
+ * If the next state is not single-step end, we can switch
+ * interpreter now.
+ */
+ if (interpState->jitState != kJitSingleStepEnd) {
+ interpState->jitState = kJitNormal;
+ switchInterp = !debugOrProfile;
+ }
}
break;
#endif