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*/