merge from master

Change-Id: I99ef0c5f5fcaee5e2cea55449488bae2ce330fb9
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1b48950..1db053d 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -46,6 +46,7 @@
 #$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
 $(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
 $(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
+$(call add-clean-step, rm -rf $(OUT)/obj/SHARED_LIBRARIES/libdvm*)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/vm/Android.mk b/vm/Android.mk
index dd77dd4..14ad5ae 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -32,10 +32,6 @@
 # Build for the target (device).
 #
 
-ifeq ($(TARGET_ARCH_VARIANT),armv5te)
-    WITH_JIT := false
-endif
-
 ifeq ($(TARGET_CPU_SMP),true)
     target_smp_flag := -DANDROID_SMP=1
 else
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 61783e3..81593e5 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -247,10 +247,6 @@
   endif # WITH_HPROF_STACK
 endif   # WITH_HPROF
 
-ifeq ($(strip $(DVM_TRACK_HEAP_MARKING)),true)
-  LOCAL_CFLAGS += -DDVM_TRACK_HEAP_MARKING=1
-endif
-
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
 	dalvik \
diff --git a/vm/Init.c b/vm/Init.c
index ece37f7..b0bcc4f 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -183,9 +183,6 @@
 #ifdef PROFILE_FIELD_ACCESS
         " profile_field_access"
 #endif
-#ifdef DVM_TRACK_HEAP_MARKING
-        " track_heap_marking"
-#endif
 #if DVM_RESOLVER_CACHE == DVM_RC_REDUCING
         " resolver_cache_reducing"
 #elif DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index f4d8e7b..f114e3b 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -708,17 +708,6 @@
     size_t sizeFreed;
     GcMode gcMode;
 
-#if DVM_TRACK_HEAP_MARKING
-    /* Since weak and soft references are always cleared,
-     * they don't require any marking.
-     * (Soft are lumped into strong when they aren't cleared.)
-     */
-    size_t strongMarkCount = 0;
-    size_t strongMarkSize = 0;
-    size_t finalizeMarkCount = 0;
-    size_t finalizeMarkSize = 0;
-#endif
-
     /* The heap lock must be held.
      */
 
@@ -845,10 +834,6 @@
         LOGD_HEAP("GC! (%d sec since last GC)\n",
                 (int)(timeSinceLastGc / 1000));
     }
-#if DVM_TRACK_HEAP_MARKING
-    gcHeap->markCount = 0;
-    gcHeap->markSize = 0;
-#endif
 
     /* Set up the marking context.
      */
@@ -875,12 +860,6 @@
      */
     LOGD_HEAP("Recursing...");
     dvmHeapScanMarkedObjects();
-#if DVM_TRACK_HEAP_MARKING
-    strongMarkCount = gcHeap->markCount;
-    strongMarkSize = gcHeap->markSize;
-    gcHeap->markCount = 0;
-    gcHeap->markSize = 0;
-#endif
 
     /* All strongly-reachable objects have now been marked.
      */
@@ -898,12 +877,6 @@
      */
     LOGD_HEAP("Finding finalizations...");
     dvmHeapScheduleFinalizations();
-#if DVM_TRACK_HEAP_MARKING
-    finalizeMarkCount = gcHeap->markCount;
-    finalizeMarkSize = gcHeap->markSize;
-    gcHeap->markCount = 0;
-    gcHeap->markSize = 0;
-#endif
 
     LOGD_HEAP("Handling f-reachable soft references...");
     dvmClearWhiteRefs(&gcHeap->softReferences);
@@ -918,11 +891,6 @@
     LOGD_HEAP("Handling phantom references...");
     dvmClearWhiteRefs(&gcHeap->phantomReferences);
 
-#if DVM_TRACK_HEAP_MARKING
-    LOGI_HEAP("Marked objects: %dB strong, %dB final\n",
-              strongMarkSize, finalizeMarkSize);
-#endif
-
 #ifdef WITH_DEADLOCK_PREDICTION
     dvmDumpMonitorInfo("before sweep");
 #endif
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index f078fdd..ea9fac2 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -109,15 +109,6 @@
      */
     bool            gcRunning;
 
-#if DVM_TRACK_HEAP_MARKING
-    /* Every time an unmarked object becomes marked, markCount
-     * is incremented and markSize increases by the size of
-     * that object.
-     */
-    size_t          markCount;
-    size_t          markSize;
-#endif
-
     /*
      * Debug control values
      */
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index bf869c6..78f4049 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -165,11 +165,6 @@
             hprofMarkRootObject(gDvm.gcHeap->hprofContext, obj, 0);
         }
 #endif
-#if DVM_TRACK_HEAP_MARKING
-        gDvm.gcHeap->markCount++;
-        gDvm.gcHeap->markSize += dvmHeapSourceChunkSize((void *)obj) +
-                HEAP_SOURCE_CHUNK_OVERHEAD;
-#endif
 
         /* obj->clazz can be NULL if we catch an object between
          * dvmMalloc() and DVM_OBJECT_INIT().  This is ok.
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index 9309a11..3793a4e 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -505,7 +505,7 @@
             int offset = -1;
             bool unused;
             if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
-                if (offset < 0) {
+                if (offset <= 0) {
                     dvmInsnSetGcPoint(insnFlags, i, true);
                 }
             } else {
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index 0ceaa9f..53daf17 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -86,6 +86,8 @@
 
 }
 
+#if 0
+/* Debugging routines */
 static void dumpConstants(CompilationUnit *cUnit)
 {
     int i;
@@ -126,6 +128,31 @@
     }
 }
 
+static void dumpHoistedChecks(CompilationUnit *cUnit)
+{
+    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+    unsigned int i;
+
+    for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+        ArrayAccessInfo *arrayAccessInfo =
+            GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+                       ArrayAccessInfo*, i);
+        int arrayReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+        int idxReg = DECODE_REG(
+            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+        LOGE("Array access %d", i);
+        LOGE("  arrayReg %d", arrayReg);
+        LOGE("  idxReg %d", idxReg);
+        LOGE("  endReg %d", loopAnalysis->endConditionReg);
+        LOGE("  maxC %d", arrayAccessInfo->maxC);
+        LOGE("  minC %d", arrayAccessInfo->minC);
+        LOGE("  opcode %d", loopAnalysis->loopBranchOpcode);
+    }
+}
+
+#endif
+
 /*
  * A loop is considered optimizable if:
  * 1) It has one basic induction variable
@@ -347,29 +374,6 @@
     return !loopBodyCanThrow;
 }
 
-static void dumpHoistedChecks(CompilationUnit *cUnit)
-{
-    LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
-    unsigned int i;
-
-    for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
-        ArrayAccessInfo *arrayAccessInfo =
-            GET_ELEM_N(loopAnalysis->arrayAccessInfo,
-                       ArrayAccessInfo*, i);
-        int arrayReg = DECODE_REG(
-            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
-        int idxReg = DECODE_REG(
-            dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
-        LOGE("Array access %d", i);
-        LOGE("  arrayReg %d", arrayReg);
-        LOGE("  idxReg %d", idxReg);
-        LOGE("  endReg %d", loopAnalysis->endConditionReg);
-        LOGE("  maxC %d", arrayAccessInfo->maxC);
-        LOGE("  minC %d", arrayAccessInfo->minC);
-        LOGE("  opcode %d", loopAnalysis->loopBranchOpcode);
-    }
-}
-
 static void genHoistedChecks(CompilationUnit *cUnit)
 {
     unsigned int i;
diff --git a/vm/compiler/codegen/arm/CalloutHelper.h b/vm/compiler/codegen/arm/CalloutHelper.h
index f6d5f4e..d6eb421 100644
--- a/vm/compiler/codegen/arm/CalloutHelper.h
+++ b/vm/compiler/codegen/arm/CalloutHelper.h
@@ -80,9 +80,12 @@
 bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,// OP_FILL_ARRAY_DATA
                                   const u2* arrayData);
 
-/* Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH */
-static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
-static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+/*
+ * Switch dispatch offset calculation for OP_PACKED_SWITCH & OP_SPARSE_SWITCH
+ * Used in CodegenDriver.c
+ * static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc);
+ * static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc);
+ */
 
 /*
  * Resolve interface callsites - OP_INVOKE_INTERFACE & OP_INVOKE_INTERFACE_RANGE
diff --git a/vm/compiler/codegen/arm/Codegen.h b/vm/compiler/codegen/arm/Codegen.h
index da65bb5..ca0a843 100644
--- a/vm/compiler/codegen/arm/Codegen.h
+++ b/vm/compiler/codegen/arm/Codegen.h
@@ -25,6 +25,7 @@
 #include "compiler/CompilerIR.h"
 #include "CalloutHelper.h"
 
+#if defined(_CODEGEN_C)
 /*
  * loadConstant() sometimes needs to add a small imm to a pre-existing constant
  */
@@ -44,10 +45,16 @@
 
 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
 
+#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \
+    defined(__ARM_ARCH_5__)
 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+#endif
 
 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir);
 
+#endif
+
+
 #if defined(WITH_SELF_VERIFICATION)
 /* Self Verification memory instruction decoder */
 void dvmSelfVerificationMemOpDecode(int lr, int* sp);
diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c
index 0cec99d..d8854ba 100644
--- a/vm/compiler/codegen/arm/CodegenCommon.c
+++ b/vm/compiler/codegen/arm/CodegenCommon.c
@@ -256,6 +256,7 @@
     return insn;
 }
 
+#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
 static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
                            int dest, int src1, int src2, int info)
 {
@@ -271,6 +272,7 @@
     dvmCompilerAppendLIR(cUnit, (LIR *) insn);
     return insn;
 }
+#endif
 
 /*
  * If the next instruction is a move-result or move-result-long,
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index f625771..dbb85c9 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -1214,6 +1214,8 @@
     opReg(cUnit, kOpBlx, r2);
 }
 
+#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \
+    defined(_ARMV5TE) || defined(_ARMV5TE_VFP)
 /*
  * To prevent a thread in a monitor wait from blocking the Jit from
  * resetting the code cache, heavyweight monitor lock will not
@@ -1259,6 +1261,7 @@
         dvmCompilerClobberCallRegs(cUnit);
     }
 }
+#endif
 
 /*
  * The following are the first-level codegen routines that analyze the format
diff --git a/vm/compiler/codegen/arm/LocalOptimizations.c b/vm/compiler/codegen/arm/LocalOptimizations.c
index 729486c..724fdb7 100644
--- a/vm/compiler/codegen/arm/LocalOptimizations.c
+++ b/vm/compiler/codegen/arm/LocalOptimizations.c
@@ -50,6 +50,8 @@
   return (reg1Lo == reg2Lo) || (reg1Lo == reg2Hi) || (reg1Hi == reg2Lo);
 }
 
+#if 0
+/* Debugging utility routine */
 static void dumpDependentInsnPair(ArmLIR *thisLIR, ArmLIR *checkLIR,
                                   const char *optimization)
 {
@@ -57,6 +59,7 @@
     dvmDumpLIRInsn((LIR *) thisLIR, 0);
     dvmDumpLIRInsn((LIR *) checkLIR, 0);
 }
+#endif
 
 /*
  * Perform a pass of top-down walk to
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c
index 4c010c6..85f612e 100644
--- a/vm/compiler/codegen/arm/Thumb/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb/Factory.c
@@ -23,7 +23,6 @@
  */
 
 static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
-static int corePreserved[] = {};
 
 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
                       int highReg);
@@ -569,7 +568,6 @@
     ArmLIR *load2 = NULL;
     ArmOpCode opCode = kThumbBkpt;
     bool shortForm = false;
-    int shortMax = 128;
     int encodedDisp = displacement;
     bool pair = false;
 
@@ -700,7 +698,6 @@
     ArmLIR *store2 = NULL;
     ArmOpCode opCode = kThumbBkpt;
     bool shortForm = false;
-    int shortMax = 128;
     int encodedDisp = displacement;
     bool pair = false;
 
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.c b/vm/compiler/codegen/arm/Thumb/Gen.c
index e014795..37cc18d 100644
--- a/vm/compiler/codegen/arm/Thumb/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb/Gen.c
@@ -112,7 +112,6 @@
 
 void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
 {
-    int i;
     int numTemps = sizeof(coreTemps)/sizeof(int);
     RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
     cUnit->regPool = pool;
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
index 04bb3a2..3b03901 100644
--- a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define _CODEGEN_C
+#define _ARMV5TE_VFP
 
 #include "Dalvik.h"
 #include "interp/InterpDefs.h"
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.c b/vm/compiler/codegen/arm/armv5te/Codegen.c
index 5e53ae4..1d9ee6d 100644
--- a/vm/compiler/codegen/arm/armv5te/Codegen.c
+++ b/vm/compiler/codegen/arm/armv5te/Codegen.c
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define _CODEGEN_C
+#define _ARMV5TE
 
 #include "Dalvik.h"
 #include "interp/InterpDefs.h"
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
index baa9632..305d103 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define _CODEGEN_C
+#define _ARMV7_A_NEON
 
 #include "Dalvik.h"
 #include "interp/InterpDefs.h"
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.c b/vm/compiler/codegen/arm/armv7-a/Codegen.c
index baa9632..0f64694 100644
--- a/vm/compiler/codegen/arm/armv7-a/Codegen.c
+++ b/vm/compiler/codegen/arm/armv7-a/Codegen.c
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define _CODEGEN_C
+#define _ARMV7_A
 
 #include "Dalvik.h"
 #include "interp/InterpDefs.h"
diff --git a/vm/mterp/armv5te/OP_THROW.S b/vm/mterp/armv5te/OP_THROW.S
index c8c5c36..b034243 100644
--- a/vm/mterp/armv5te/OP_THROW.S
+++ b/vm/mterp/armv5te/OP_THROW.S
@@ -7,6 +7,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/c/OP_THROW.c b/vm/mterp/c/OP_THROW.c
index 9a56040..0dcaced 100644
--- a/vm/mterp/c/OP_THROW.c
+++ b/vm/mterp/c/OP_THROW.c
@@ -2,10 +2,17 @@
     {
         Object* obj;
 
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
         vsrc1 = INST_AA(inst);
         ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
         obj = (Object*) GET_REGISTER(vsrc1);
-        if (!checkForNullExportPC(obj, fp, pc)) {
+        if (!checkForNull(obj)) {
             /* will throw a null pointer exception */
             LOGVV("Bad exception\n");
         } else {
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index 9d7212f..acbde1c 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -544,7 +544,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -919,7 +919,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/cstubs/stubdefs.c b/vm/mterp/cstubs/stubdefs.c
index 5a8d585..bf870c6 100644
--- a/vm/mterp/cstubs/stubdefs.c
+++ b/vm/mterp/cstubs/stubdefs.c
@@ -2,7 +2,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index fa992d9..7f8ff9a 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -1135,6 +1135,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index fc7e003..a265b0b 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -1135,6 +1135,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index e35c1ce..4307b2e 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -1135,6 +1135,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/out/InterpAsm-armv7-a-neon.S b/vm/mterp/out/InterpAsm-armv7-a-neon.S
index ef8b31f..9cd811c 100644
--- a/vm/mterp/out/InterpAsm-armv7-a-neon.S
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -1131,6 +1131,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index 68049bc..02bfecb 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -1131,6 +1131,7 @@
     mov     r2, rINST, lsr #8           @ r2<- AA
     GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
     ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ exception handler can throw
     cmp     r1, #0                      @ null object?
     beq     common_errNullObject        @ yes, throw an NPE instead
     @ bypass dvmSetException, just store it
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index 831586f..c654202 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -927,6 +927,7 @@
      */
     /* throw vAA */
     GET_GLUE(%ecx)
+    EXPORT_PC()
     movzbl   rINST_HI,rINST_FULL       # rINST_FULL<- AA
     GET_VREG(%eax,rINST_FULL)          # eax<- exception object
     movl     offGlue_self(%ecx),%ecx   # ecx<- glue->self
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index ea1de07..4f6ca97 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
@@ -1808,10 +1809,17 @@
     {
         Object* obj;
 
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
         vsrc1 = INST_AA(inst);
         ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
         obj = (Object*) GET_REGISTER(vsrc1);
-        if (!checkForNullExportPC(obj, fp, pc)) {
+        if (!checkForNull(obj)) {
             /* will throw a null pointer exception */
             LOGVV("Bad exception\n");
         } else {
@@ -3671,7 +3679,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -4046,7 +4054,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/out/InterpC-armv4t.c b/vm/mterp/out/InterpC-armv4t.c
index 76c8664..55a020d 100644
--- a/vm/mterp/out/InterpC-armv4t.c
+++ b/vm/mterp/out/InterpC-armv4t.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.c b/vm/mterp/out/InterpC-armv5te-vfp.c
index a991c2b..8e58f8b 100644
--- a/vm/mterp/out/InterpC-armv5te-vfp.c
+++ b/vm/mterp/out/InterpC-armv5te-vfp.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpC-armv5te.c b/vm/mterp/out/InterpC-armv5te.c
index 21ed408..d3c041f 100644
--- a/vm/mterp/out/InterpC-armv5te.c
+++ b/vm/mterp/out/InterpC-armv5te.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpC-armv7-a-neon.c b/vm/mterp/out/InterpC-armv7-a-neon.c
index a9de36f..77b1fce 100644
--- a/vm/mterp/out/InterpC-armv7-a-neon.c
+++ b/vm/mterp/out/InterpC-armv7-a-neon.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpC-armv7-a.c b/vm/mterp/out/InterpC-armv7-a.c
index 3dfca56..7f46f4f 100644
--- a/vm/mterp/out/InterpC-armv7-a.c
+++ b/vm/mterp/out/InterpC-armv7-a.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index bcc6b99..08172a8 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -425,10 +425,12 @@
     checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
 
 #if defined(WITH_JIT)
-#define CHECK_JIT() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
 #define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
 #else
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT(x) ((void)0)
 #endif
 
@@ -465,7 +467,7 @@
         inst = FETCH(0);                                                    \
         CHECK_DEBUG_AND_PROF();                                             \
         CHECK_TRACKED_REFS();                                               \
-        if (CHECK_JIT()) GOTO_bail_switch();                                \
+        if (CHECK_JIT_BOOL()) GOTO_bail_switch();                           \
         goto *handlerTable[INST_INST(inst)];                                \
     }
 # define FINISH_BKPT(_opcode) {                                             \
@@ -1543,7 +1545,7 @@
         /* just fall through to instruction loop or threaded kickstart */
         break;
     case kInterpEntryReturn:
-        CHECK_JIT();
+        CHECK_JIT_VOID();
         goto returnFromMethod;
     case kInterpEntryThrow:
         goto exceptionThrown;
@@ -2174,10 +2176,17 @@
     {
         Object* obj;
 
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
         vsrc1 = INST_AA(inst);
         ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
         obj = (Object*) GET_REGISTER(vsrc1);
-        if (!checkForNullExportPC(obj, fp, pc)) {
+        if (!checkForNull(obj)) {
             /* will throw a null pointer exception */
             LOGVV("Bad exception\n");
         } else {
@@ -3954,7 +3963,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -4329,7 +4338,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 1937bd1..7e20714 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -423,7 +423,8 @@
 
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /* File: portable/stubdefs.c */
@@ -459,7 +460,7 @@
         inst = FETCH(0);                                                    \
         CHECK_DEBUG_AND_PROF();                                             \
         CHECK_TRACKED_REFS();                                               \
-        if (CHECK_JIT()) GOTO_bail_switch();                                \
+        if (CHECK_JIT_BOOL()) GOTO_bail_switch();                           \
         goto *handlerTable[INST_INST(inst)];                                \
     }
 # define FINISH_BKPT(_opcode) {                                             \
@@ -1282,7 +1283,7 @@
         /* just fall through to instruction loop or threaded kickstart */
         break;
     case kInterpEntryReturn:
-        CHECK_JIT();
+        CHECK_JIT_VOID();
         goto returnFromMethod;
     case kInterpEntryThrow:
         goto exceptionThrown;
@@ -1913,10 +1914,17 @@
     {
         Object* obj;
 
+        /*
+         * We don't create an exception here, but the process of searching
+         * for a catch block can do class lookups and throw exceptions.
+         * We need to update the saved PC.
+         */
+        EXPORT_PC();
+
         vsrc1 = INST_AA(inst);
         ILOGV("|throw v%d  (%p)", vsrc1, (void*)GET_REGISTER(vsrc1));
         obj = (Object*) GET_REGISTER(vsrc1);
-        if (!checkForNullExportPC(obj, fp, pc)) {
+        if (!checkForNull(obj)) {
             /* will throw a null pointer exception */
             LOGVV("Bad exception\n");
         } else {
@@ -3693,7 +3701,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -4068,7 +4076,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/out/InterpC-x86-atom.c b/vm/mterp/out/InterpC-x86-atom.c
index 4ee7181..0061a61 100644
--- a/vm/mterp/out/InterpC-x86-atom.c
+++ b/vm/mterp/out/InterpC-x86-atom.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
@@ -1839,7 +1840,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -2214,7 +2215,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index ecbb614..c95ef90 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -422,7 +422,8 @@
 #define INTERP_TYPE INTERP_STD
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 # define CHECK_TRACKED_REFS() ((void)0)
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
 
 /*
@@ -1808,7 +1809,7 @@
             LOGVV("+++ returned into break frame\n");
 #if defined(WITH_JIT)
             /* Let the Jit know the return is terminating normally */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
             GOTO_bail();
         }
@@ -2183,7 +2184,7 @@
 
 #if defined(WITH_JIT)
             /* Allow the Jit to end any pending trace building */
-            CHECK_JIT();
+            CHECK_JIT_VOID();
 #endif
 
             /*
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index 2aa7867..b2ec1d8 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -97,7 +97,7 @@
         /* just fall through to instruction loop or threaded kickstart */
         break;
     case kInterpEntryReturn:
-        CHECK_JIT();
+        CHECK_JIT_VOID();
         goto returnFromMethod;
     case kInterpEntryThrow:
         goto exceptionThrown;
diff --git a/vm/mterp/portable/portdbg.c b/vm/mterp/portable/portdbg.c
index 030a515..76b7637 100644
--- a/vm/mterp/portable/portdbg.c
+++ b/vm/mterp/portable/portdbg.c
@@ -5,9 +5,11 @@
     checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
 
 #if defined(WITH_JIT)
-#define CHECK_JIT() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_BOOL() (dvmCheckJit(pc, self, interpState))
+#define CHECK_JIT_VOID() (dvmCheckJit(pc, self, interpState))
 #define ABORT_JIT_TSELECT() (dvmJitAbortTraceSelect(interpState))
 #else
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT(x) ((void)0)
 #endif
diff --git a/vm/mterp/portable/portstd.c b/vm/mterp/portable/portstd.c
index e2d8b10..f37c22b 100644
--- a/vm/mterp/portable/portstd.c
+++ b/vm/mterp/portable/portstd.c
@@ -3,5 +3,6 @@
 
 #define CHECK_DEBUG_AND_PROF() ((void)0)
 
-#define CHECK_JIT() (0)
+#define CHECK_JIT_BOOL() (false)
+#define CHECK_JIT_VOID()
 #define ABORT_JIT_TSELECT() ((void)0)
diff --git a/vm/mterp/portable/stubdefs.c b/vm/mterp/portable/stubdefs.c
index 29258fc..b46bb3a 100644
--- a/vm/mterp/portable/stubdefs.c
+++ b/vm/mterp/portable/stubdefs.c
@@ -30,7 +30,7 @@
         inst = FETCH(0);                                                    \
         CHECK_DEBUG_AND_PROF();                                             \
         CHECK_TRACKED_REFS();                                               \
-        if (CHECK_JIT()) GOTO_bail_switch();                                \
+        if (CHECK_JIT_BOOL()) GOTO_bail_switch();                           \
         goto *handlerTable[INST_INST(inst)];                                \
     }
 # define FINISH_BKPT(_opcode) {                                             \
diff --git a/vm/mterp/x86-atom/TODO.txt b/vm/mterp/x86-atom/TODO.txt
index 825e7db..0bebef5 100644
--- a/vm/mterp/x86-atom/TODO.txt
+++ b/vm/mterp/x86-atom/TODO.txt
@@ -11,4 +11,5 @@
 (lo) Implement OP_BREAKPOINT
 (lo) Implement OP_EXECUTE_INLINE_RANGE
 (lo) Implement OP_*_WIDE_VOLATILE
+(lo) OP_THROW needs to export the PC
 
diff --git a/vm/mterp/x86/OP_THROW.S b/vm/mterp/x86/OP_THROW.S
index 7ed2ead..d7e1574 100644
--- a/vm/mterp/x86/OP_THROW.S
+++ b/vm/mterp/x86/OP_THROW.S
@@ -5,6 +5,7 @@
      */
     /* throw vAA */
     GET_GLUE(%ecx)
+    EXPORT_PC()
     movzbl   rINST_HI,rINST_FULL       # rINST_FULL<- AA
     GET_VREG(%eax,rINST_FULL)          # eax<- exception object
     movl     offGlue_self(%ecx),%ecx   # ecx<- glue->self