Fixed the trace builder to correctly handle excpetion throwing instruction.

Added a new unit test 081-hot-exceptions to target this problem.
diff --git a/tests/081-hot-exceptions/expected.txt b/tests/081-hot-exceptions/expected.txt
new file mode 100644
index 0000000..2432ff4
--- /dev/null
+++ b/tests/081-hot-exceptions/expected.txt
@@ -0,0 +1,2 @@
+sum = 0
+exception = 1024
diff --git a/tests/081-hot-exceptions/info.txt b/tests/081-hot-exceptions/info.txt
new file mode 100644
index 0000000..cc514f3
--- /dev/null
+++ b/tests/081-hot-exceptions/info.txt
@@ -0,0 +1,3 @@
+Make a hot exception-throwing path to stress test how the trace builder handles
+exceptions encountered during trace selection. The existence of exceptions will
+cause a control flow change to deviate from the current method.
diff --git a/tests/081-hot-exceptions/src/Main.java b/tests/081-hot-exceptions/src/Main.java
new file mode 100644
index 0000000..90e7af2
--- /dev/null
+++ b/tests/081-hot-exceptions/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+    static class ArrayObj {
+        int[] array;
+
+        int getArrayElement(int i) throws NullPointerException {
+            return array[i];
+        }
+    }
+
+    public static void main(String[] args) {
+        ArrayObj arrayObj2 = new ArrayObj();
+        int sum = 0;
+        int exception = 0;
+
+        for (int i = 0; i < 1024; i++) {
+            try {
+                // A hot method invocation that always encounters exceptions
+                sum += arrayObj2.getArrayElement(i);
+            } catch (NullPointerException npe) {
+                exception++;
+            }
+        }
+        System.out.println("sum = " + sum);
+        System.out.println("exception = " + exception);
+    }
+}
diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c
index 30a7b1b..2e735fa 100644
--- a/vm/compiler/codegen/arm/Codegen.c
+++ b/vm/compiler/codegen/arm/Codegen.c
@@ -2316,11 +2316,11 @@
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
             assert(classPtr != NULL);
             assert(classPtr->status & CLASS_INITIALIZED);
-            if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
-                /* It's going to throw, just let the interp. deal with it. */
-                genInterpSingleStep(cUnit, mir);
-                return false;
-            }
+            /*
+             * If it is going to throw, it should not make to the trace to begin
+             * with.
+             */
+            assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
             loadConstant(cUnit, r4PC, (int)dvmAllocObject);
             loadConstant(cUnit, r0, (int) classPtr);
             genExportPC(cUnit, mir, r2, r3 );
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 928ca09..28994b7 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -161,10 +161,11 @@
 
     int currTraceRun;
     int totalTraceLen;        // Number of Dalvik insts in trace
-    const u2* currTraceHead;        // Start of the trace we're building
-    const u2* currRunHead;          // Start of run we're building
+    const u2* currTraceHead;  // Start of the trace we're building
+    const u2* currRunHead;    // Start of run we're building
     int currRunLen;           // Length of run in 16-bit words
     int lastThreshFilter;
+    const u2* lastPC;         // Stage the PC first for the threaded interpreter
 #if defined(WITH_SELF_VERIFICATION)
     struct HeapArgSpace heapArgSpace;
 #endif
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index f1ac1c2..aca5fff 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -515,25 +515,38 @@
 #endif
             );
 
+    /* First instruction - just remember the PC and exit */
+    if (interpState->lastPC == NULL) {
+        interpState->lastPC = pc;
+        return switchInterp;
+    }
+
+    /* Prepare to handle last PC and stage the current PC */
+    const u2 *lastPC = interpState->lastPC;
+    interpState->lastPC = pc;
+
     switch (interpState->jitState) {
         char* nopStr;
         int target;
         int offset;
         DecodedInstruction decInsn;
         case kJitTSelect:
-            dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
+            /* Grow the trace around the last PC if jitState is kJitTSelect */
+            dexDecodeInstruction(gDvm.instrFormat, lastPC, &decInsn);
 #if defined(SHOW_TRACE)
             LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
 #endif
             flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
-            len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
-            offset = pc - interpState->method->insns;
-            if (pc != interpState->currRunHead + interpState->currRunLen) {
+            len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, lastPC);
+            offset = lastPC - interpState->method->insns;
+            assert((unsigned) offset <
+                   dvmGetMethodInsnsSize(interpState->method));
+            if (lastPC != interpState->currRunHead + interpState->currRunLen) {
                 int currTraceRun;
                 /* We need to start a new trace run */
                 currTraceRun = ++interpState->currTraceRun;
                 interpState->currRunLen = 0;
-                interpState->currRunHead = (u2*)pc;
+                interpState->currRunHead = (u2*)lastPC;
                 interpState->trace[currTraceRun].frag.startOffset = offset;
                 interpState->trace[currTraceRun].frag.numInsts = 0;
                 interpState->trace[currTraceRun].frag.runEnd = false;
@@ -542,6 +555,12 @@
             interpState->trace[interpState->currTraceRun].frag.numInsts++;
             interpState->totalTraceLen++;
             interpState->currRunLen += len;
+
+            /* Will probably never hit this with the current trace buildier */
+            if (interpState->currTraceRun == (MAX_JIT_RUN_LEN - 1)) {
+                interpState->jitState = kJitTSelectEnd;
+            }
+
             if (  ((flags & kInstrUnconditional) == 0) &&
                   /* don't end trace on INVOKE_DIRECT_EMPTY  */
                   (decInsn.opCode != OP_INVOKE_DIRECT_EMPTY) &&
@@ -880,6 +899,7 @@
                  interpState->trace[0].frag.numInsts = 0;
                  interpState->trace[0].frag.runEnd = false;
                  interpState->trace[0].frag.hint = kJitHintNone;
+                 interpState->lastPC = 0;
                  break;
             case kJitTSelect:
             case kJitTSelectAbort:
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index f20c0f1..c34d6c4 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -576,6 +576,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 4b0a17d..81e7165 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3609,6 +3609,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index a336a95..45a18da 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -3909,6 +3909,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 7e03400..3576608 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -3623,6 +3623,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index f8792bd..6492daf 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1764,6 +1764,10 @@
          */
         PERIODIC_CHECKS(kInterpEntryThrow, 0);
 
+#if defined(WITH_JIT)
+        // Something threw during trace selection - abort the current trace
+        interpState->jitState = kJitTSelectEnd;
+#endif
         /*
          * We save off the exception and clear the exception status.  While
          * processing the exception we might need to load some Throwable
diff --git a/vm/native/java_lang_Runtime.c b/vm/native/java_lang_Runtime.c
index 1278f03..b5c0aee 100644
--- a/vm/native/java_lang_Runtime.c
+++ b/vm/native/java_lang_Runtime.c
@@ -53,6 +53,9 @@
         LOGW("JNI exit hook returned\n");
     }
     LOGD("Calling exit(%d)\n", status);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+    dvmCompilerDumpStats();
+#endif
     exit(status);
 }
 
@@ -161,4 +164,3 @@
         Dalvik_java_lang_Runtime_totalMemory },
     { NULL, NULL, NULL },
 };
-