Fix interpreter debug attach
Fix a few miscellaneous bugs from the interpreter restructuring that were
causing a segfault on debugger attach.
Added a sanity checking routine for debugging.
Fixed a problem in which the JIT's threshold and on/off switch
wouldn't get initialized properly on thread creation.
Renamed dvmCompilerStateRefresh() to dvmCompilerUpdateGlobalState() to
better reflect its function.
Change-Id: I5b8af1ce2175e3c6f53cda19dd8e052a5f355587
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index 98f478e..b4a5ec9 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -596,13 +596,14 @@
/*
* The interpreter just threw. Handle any special subMode requirements.
+ * All interpSave state must be valid on entry.
*/
-void dvmReportExceptionThrow(Thread* self, const Method* curMethod,
- const u2* pc, void* fp)
+void dvmReportExceptionThrow(Thread* self, Object* exception)
{
+ const Method* curMethod = self->interpSave.method;
#if defined(WITH_JIT)
if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {
- dvmJitEndTraceSelect(self, pc);
+ dvmJitEndTraceSelect(self, self->interpSave.pc);
}
if (self->interpBreak.ctl.breakFlags & kInterpSingleStep) {
/* Discard any single-step native returns to translation */
@@ -611,17 +612,18 @@
#endif
if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
void *catchFrame;
- int offset = pc - curMethod->insns;
- int catchRelPc = dvmFindCatchBlock(self, offset, self->exception,
+ int offset = self->interpSave.pc - curMethod->insns;
+ int catchRelPc = dvmFindCatchBlock(self, offset, exception,
true, &catchFrame);
- dvmDbgPostException(fp, offset, catchFrame, catchRelPc,
- self->exception);
+ dvmDbgPostException(self->interpSave.fp, offset, catchFrame,
+ catchRelPc, exception);
}
}
/*
* The interpreter is preparing to do an invoke (both native & normal).
- * Handle any special subMode requirements.
+ * Handle any special subMode requirements. All interpSave state
+ * must be valid on entry.
*/
void dvmReportInvoke(Thread* self, const Method* methodToCall)
{
@@ -632,10 +634,10 @@
* The interpreter is preparing to do a native invoke. Handle any
* special subMode requirements. NOTE: for a native invoke,
* dvmReportInvoke() and dvmReportPreNativeInvoke() will both
- * be called prior to the invoke.
+ * be called prior to the invoke. All interpSave state must
+ * be valid on entry.
*/
-void dvmReportPreNativeInvoke(const u2* pc, Thread* self,
- const Method* methodToCall)
+void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self)
{
#if defined(WITH_JIT)
/*
@@ -643,7 +645,7 @@
* builder can't follow into or through a native method.
*/
if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {
- dvmCheckJit(pc, self);
+ dvmCheckJit(self->interpSave.pc, self);
}
#endif
if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
@@ -656,10 +658,10 @@
/*
* The interpreter has returned from a native invoke. Handle any
- * special subMode requirements.
+ * special subMode requirements. All interpSave state must be
+ * valid on entry.
*/
-void dvmReportPostNativeInvoke(const u2* pc, Thread* self,
- const Method* methodToCall)
+void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self)
{
if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
Object* thisPtr = dvmGetThisPtr(self->interpSave.method,
@@ -674,15 +676,15 @@
/*
* The interpreter has returned from a normal method. Handle any special
- * subMode requirements.
+ * subMode requirements. All interpSave state must be valid on entry.
*/
-void dvmReportReturn(Thread* self, const u2* pc, const u4* prevFP)
+void dvmReportReturn(Thread* self)
{
TRACE_METHOD_EXIT(self, self->interpSave.method);
#if defined(WITH_JIT)
- if (dvmIsBreakFrame(prevFP) &&
+ if (dvmIsBreakFrame(self->interpSave.fp) &&
(self->interpBreak.ctl.subMode & kSubModeJitTraceBuild)) {
- dvmCheckJit(pc, self);
+ dvmCheckJit(self->interpSave.pc, self);
}
#endif
}
@@ -711,8 +713,8 @@
* breakpoints. We may be able to speed things up a bit if we don't query
* the event list unless we know there's at least one lurking within.
*/
-void dvmUpdateDebugger(const Method* method, const u2* pc, const u4* fp,
- bool methodEntry, Thread* self)
+static void updateDebugger(const Method* method, const u2* pc, const u4* fp,
+ bool methodEntry, Thread* self)
{
int eventFlags = 0;
@@ -1552,6 +1554,54 @@
}
/*
+ * Do a sanity check on interpreter state saved to Thread.
+ * A failure here doesn't necessarily mean that something is wrong,
+ * so this code should only be used during development to suggest
+ * a possible problem.
+ */
+void dvmCheckInterpStateConsistency()
+{
+ Thread* self = dvmThreadSelf();
+ Thread* thread;
+ uint8_t breakFlags;
+ uint8_t subMode;
+ void* handlerTable;
+
+ dvmLockThreadList(self);
+ breakFlags = self->interpBreak.ctl.breakFlags;
+ subMode = self->interpBreak.ctl.subMode;
+ handlerTable = self->interpBreak.ctl.curHandlerTable;
+ for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+ if (subMode != thread->interpBreak.ctl.subMode) {
+ LOGD("Warning: subMode mismatch - 0x%x:0x%x, tid[%d]",
+ subMode,thread->interpBreak.ctl.subMode,thread->threadId);
+ }
+ if (breakFlags != thread->interpBreak.ctl.breakFlags) {
+ LOGD("Warning: breakFlags mismatch - 0x%x:0x%x, tid[%d]",
+ breakFlags,thread->interpBreak.ctl.breakFlags,thread->threadId);
+ }
+ if (handlerTable != thread->interpBreak.ctl.curHandlerTable) {
+ LOGD("Warning: curHandlerTable mismatch - 0x%x:0x%x, tid[%d]",
+ (int)handlerTable,(int)thread->interpBreak.ctl.curHandlerTable,
+ thread->threadId);
+ }
+#if defined(WITH_JIT)
+ if (thread->pJitProfTable != gDvmJit.pProfTable) {
+ LOGD("Warning: pJitProfTable mismatch - 0x%x:0x%x, tid[%d]",
+ (int)thread->pJitProfTable,(int)gDvmJit.pProfTable,
+ thread->threadId);
+ }
+ if (thread->jitThreshold != gDvmJit.threshold) {
+ LOGD("Warning: jitThreshold mismatch - 0x%x:0x%x, tid[%d]",
+ (int)thread->jitThreshold,(int)gDvmJit.threshold,
+ thread->threadId);
+ }
+#endif
+ }
+ dvmUnlockThreadList();
+}
+
+/*
* Arm a safepoint callback for a thread. If funct is null,
* clear any pending callback.
* TODO: only gc is currently using this feature, and will have
@@ -1622,9 +1672,32 @@
self->icRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
self->pProfileCountdown = &gDvmJit.profileCountdown;
// Jit state that can change
- dvmJitUpdateState();
+ dvmJitUpdateThreadStateSingle(self);
#endif
+}
+/*
+ * For a newly-created thread, we need to start off with interpBreak
+ * set to any existing global modes. The caller must hold the
+ * thread list lock.
+ */
+void dvmInitializeInterpBreak(Thread* thread)
+{
+ u1 flags = 0;
+ u1 subModes = 0;
+
+ if (gDvm.instructionCountEnableCount > 0) {
+ flags |= kInterpInstCountBreak;
+ subModes |= kSubModeInstCounting;
+ }
+ if (dvmIsMethodTraceActive()) {
+ subModes |= kSubModeMethodTrace;
+ }
+ if (gDvm.debuggerActive) {
+ flags |= kInterpDebugBreak;
+ subModes |= kSubModeDebuggerActive;
+ }
+ dvmUpdateInterpBreak(thread, flags, subModes, true);
}
/*
@@ -1702,8 +1775,8 @@
}
if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {
- dvmUpdateDebugger(method, pc, fp,
- self->debugIsMethodEntry, self);
+ updateDebugger(method, pc, fp,
+ self->debugIsMethodEntry, self);
}
if (gDvm.instructionCountEnableCount != 0) {
/*
diff --git a/vm/interp/Interp.h b/vm/interp/Interp.h
index b6919af..91e2262 100644
--- a/vm/interp/Interp.h
+++ b/vm/interp/Interp.h
@@ -77,17 +77,12 @@
/*
* Debugger support
*/
-void dvmUpdateDebugger(const Method* method, const u2* pc, const u4* fp,
- bool methodEntry, Thread* self);
void dvmCheckBefore(const u2 *dPC, u4 *fp, Thread* self);
-void dvmReportExceptionThrow(Thread* self, const Method* curMethod,
- const u2* pc, void* fp);
-void dvmReportPreNativeInvoke(const u2* pc, Thread* self,
- const Method* methodToCall);
-void dvmReportPostNativeInvoke(const u2* pc, Thread* self,
- const Method* methodToCall);
+void dvmReportExceptionThrow(Thread* self, Object* exception);
+void dvmReportPreNativeInvoke(const Method* methodToCall, Thread* self);
+void dvmReportPostNativeInvoke(const Method* methodToCall, Thread* self);
void dvmReportInvoke(Thread* self, const Method* methodToCall);
-void dvmReportReturn(Thread* self, const u2* pc, const u4* prevFP);
+void dvmReportReturn(Thread* self);
/*
* Update interpBreak
@@ -95,6 +90,8 @@
void dvmUpdateInterpBreak(Thread* thread, int newBreak, int newMode,
bool enable);
void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta);
+void dvmCheckInterpStateConsistency();
+void dvmInitializeInterpBreak(Thread* thread);
/*
* Update interpBreak for all threads
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 0274a24..936bbc8 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -440,7 +440,7 @@
* free it because some thread may be holding a reference.
*/
gDvmJit.pProfTable = NULL;
- dvmJitUpdateState();
+ dvmJitUpdateThreadStateAll();
}
#if defined(WITH_JIT_TUNING)
@@ -1479,18 +1479,26 @@
}
/*
+ * Update JIT-specific info in Thread structure for a single thread
+ */
+void dvmJitUpdateThreadStateSingle(Thread* thread)
+{
+ thread->pJitProfTable = gDvmJit.pProfTable;
+ thread->jitThreshold = gDvmJit.threshold;
+}
+
+/*
* Walk through the thread list and refresh all local copies of
* JIT global state (which was placed there for fast access).
*/
-void dvmJitUpdateState()
+void dvmJitUpdateThreadStateAll()
{
Thread* self = dvmThreadSelf();
Thread* thread;
dvmLockThreadList(self);
for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
- thread->pJitProfTable = gDvmJit.pProfTable;
- thread->jitThreshold = gDvmJit.threshold;
+ dvmJitUpdateThreadStateSingle(thread);
}
dvmUnlockThreadList();
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
index b7e0f4a..7dbe9ac 100644
--- a/vm/interp/Jit.h
+++ b/vm/interp/Jit.h
@@ -162,7 +162,8 @@
void dvmJitTraceProfilingOn(void);
void dvmJitChangeProfileMode(TraceProfilingModes newState);
void dvmJitDumpTraceDesc(JitTraceDescription *trace);
-void dvmJitUpdateState(void);
+void dvmJitUpdateThreadStateSingle(Thread* threead);
+void dvmJitUpdateThreadStateAll(void);
void dvmJitResumeTranslation(Thread* self, const u2* pc, const u4* fp);
#endif /*_DALVIK_INTERP_JIT*/