Fix null check elimination

The existing null check elimination mechanism suffered from the same
limitation as the SSA renaming: it took shortcuts that were valid in
a trace compilation world, but not in a method compilation world.

This CL replaces the old mechanism, and additionally takes advantage
of some the fact that "this" is always non-null, as are objects returned
from OP_NEW_* (thanks Ian!).

Two test cases added.  The one for ensuring that unnecessary null checks
are elminated requires manual inspection.  The other - that we don't
eliminate a necessary null check - is disabled until exceptions are working.

Change-Id: I2a9b72741f56617bf609e4d7c20244796c988f28
diff --git a/build/Android.common.mk b/build/Android.common.mk
index ffa2636..1bd9367 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -181,6 +181,7 @@
 	AbstractMethod \
 	AllFields \
 	CreateMethodDescriptor \
+	ExceptionTest \
 	Fibonacci \
 	HelloWorld \
 	IntMath \
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index e2418b8..e25acd9 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -111,7 +111,7 @@
     struct MIR* prev;
     struct MIR* next;
     struct SSARepresentation* ssaRep;
-    int OptimizationFlags;
+    int optimizationFlags;
     int seqNum;
     union {
         // Used by the inlined insn from the callee to find the mother method
@@ -135,6 +135,7 @@
     int id;
     bool visited;
     bool hidden;
+    bool catchEntry;
     unsigned int startOffset;
     const Method* containingMethod;     // For blocks from the callee
     BBType blockType;
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 3369e9e..827470e 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -50,13 +50,13 @@
     DF_DA_WIDE | DF_UB_WIDE | DF_IS_MOVE,
 
     // 07 OP_MOVE_OBJECT vA, vB
-    DF_DA | DF_UB | DF_IS_MOVE,
+    DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
 
     // 08 OP_MOVE_OBJECT_FROM16 vAA, vBBBB
-    DF_DA | DF_UB | DF_IS_MOVE,
+    DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
 
     // 09 OP_MOVE_OBJECT_16 vAAAA, vBBBB
-    DF_DA | DF_UB | DF_IS_MOVE,
+    DF_DA | DF_UB | DF_NULL_TRANSFER_0 | DF_IS_MOVE,
 
     // 0A OP_MOVE_RESULT vAA
     DF_DA,
@@ -116,31 +116,31 @@
     DF_DA,
 
     // 1D OP_MONITOR_ENTER vAA
-    DF_UA,
+    DF_UA | DF_NULL_CHK_0,
 
     // 1E OP_MONITOR_EXIT vAA
-    DF_UA,
+    DF_UA | DF_NULL_CHK_0,
 
-    // 1F OP_CHECK_CAST vAA, type@BBBB
+    // 1F OP_CHK_CAST vAA, type@BBBB
     DF_UA,
 
     // 20 OP_INSTANCE_OF vA, vB, type@CCCC
     DF_DA | DF_UB,
 
     // 21 OP_ARRAY_LENGTH vA, vB
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NULL_CHK_0,
 
     // 22 OP_NEW_INSTANCE vAA, type@BBBB
-    DF_DA,
+    DF_DA | DF_NON_NULL_DST,
 
     // 23 OP_NEW_ARRAY vA, vB, type@CCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NON_NULL_DST,
 
     // 24 OP_FILLED_NEW_ARRAY {vD, vE, vF, vG, vA}
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NON_NULL_RET,
 
     // 25 OP_FILLED_NEW_ARRAY_RANGE {vCCCC .. vNNNN}, type@BBBB
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NON_NULL_RET,
 
     // 26 OP_FILL_ARRAY_DATA vAA, +BBBBBBBB
     DF_UA,
@@ -234,88 +234,88 @@
     DF_NOP,
 
     // 44 OP_AGET vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 45 OP_AGET_WIDE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA_WIDE | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 46 OP_AGET_OBJECT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 47 OP_AGET_BOOLEAN vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 48 OP_AGET_BYTE vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 49 OP_AGET_CHAR vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 4A OP_AGET_SHORT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_0 | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_UC | DF_NULL_CHK_0 | DF_RANGE_CHK_1 | DF_IS_GETTER,
 
     // 4B OP_APUT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 4C OP_APUT_WIDE vAA, vBB, vCC
-    DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_2 | DF_IS_SETTER,
+    DF_UA_WIDE | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 4D OP_APUT_OBJECT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 4E OP_APUT_BOOLEAN vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 4F OP_APUT_BYTE vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 50 OP_APUT_CHAR vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 51 OP_APUT_SHORT vAA, vBB, vCC
-    DF_UA | DF_UB | DF_UC | DF_NULL_N_RANGE_CHECK_1 | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_UC | DF_NULL_CHK_1 | DF_RANGE_CHK_2 | DF_IS_SETTER,
 
     // 52 OP_IGET vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 53 OP_IGET_WIDE vA, vB, field@CCCC
-    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+    DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 54 OP_IGET_OBJECT vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 55 OP_IGET_BOOLEAN vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 56 OP_IGET_BYTE vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 57 OP_IGET_CHAR vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 58 OP_IGET_SHORT vA, vB, field@CCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 59 OP_IPUT vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5A OP_IPUT_WIDE vA, vB, field@CCCC
-    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+    DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5B OP_IPUT_OBJECT vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5C OP_IPUT_BOOLEAN vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5D OP_IPUT_BYTE vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5E OP_IPUT_CHAR vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 5F OP_IPUT_SHORT vA, vB, field@CCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 60 OP_SGET vAA, field@BBBB
     DF_DA | DF_IS_GETTER,
@@ -360,13 +360,13 @@
     DF_UA | DF_IS_SETTER,
 
     // 6E OP_INVOKE_VIRTUAL {vD, vE, vF, vG, vA}
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NULL_CHK_OUT0,
 
     // 6F OP_INVOKE_SUPER {vD, vE, vF, vG, vA}
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NULL_CHK_OUT0,
 
     // 70 OP_INVOKE_DIRECT {vD, vE, vF, vG, vA}
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NULL_CHK_OUT0,
 
     // 71 OP_INVOKE_STATIC {vD, vE, vF, vG, vA}
     DF_FORMAT_35C,
@@ -378,13 +378,13 @@
     DF_NOP,
 
     // 74 OP_INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN}
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 75 OP_INVOKE_SUPER_RANGE {vCCCC .. vNNNN}
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 76 OP_INVOKE_DIRECT_RANGE {vCCCC .. vNNNN}
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 77 OP_INVOKE_STATIC_RANGE {vCCCC .. vNNNN}
     DF_FORMAT_3RC,
@@ -711,10 +711,10 @@
     DF_DA | DF_UB,
 
     // E3 OP_IGET_VOLATILE
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NULL_CHK_0,
 
     // E4 OP_IPUT_VOLATILE
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_NULL_CHK_1,
 
     // E5 OP_SGET_VOLATILE
     DF_DA,
@@ -723,13 +723,13 @@
     DF_UA,
 
     // E7 OP_IGET_OBJECT_VOLATILE
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NULL_CHK_0,
 
     // E8 OP_IGET_WIDE_VOLATILE
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_NULL_CHK_0,
 
     // E9 OP_IPUT_WIDE_VOLATILE
-    DF_UA_WIDE | DF_UB,
+    DF_UA_WIDE | DF_UB | DF_NULL_CHK_1,
 
     // EA OP_SGET_WIDE_VOLATILE
     DF_DA_WIDE,
@@ -750,43 +750,43 @@
     DF_FORMAT_3RC,
 
     // F0 OP_INVOKE_OBJECT_INIT_RANGE
-    DF_NOP,
+    DF_NOP | DF_NULL_CHK_0,
 
     // F1 OP_RETURN_VOID_BARRIER
     DF_NOP,
 
     // F2 OP_IGET_QUICK
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // F3 OP_IGET_WIDE_QUICK
-    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+    DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // F4 OP_IGET_OBJECT_QUICK
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // F5 OP_IPUT_QUICK
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // F6 OP_IPUT_WIDE_QUICK
-    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+    DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 |DF_IS_SETTER,
 
     // F7 OP_IPUT_OBJECT_QUICK
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // F8 OP_INVOKE_VIRTUAL_QUICK
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NULL_CHK_OUT0,
 
     // F9 OP_INVOKE_VIRTUAL_QUICK_RANGE
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // FA OP_INVOKE_SUPER_QUICK
-    DF_FORMAT_35C,
+    DF_FORMAT_35C | DF_NULL_CHK_OUT0,
 
     // FB OP_INVOKE_SUPER_QUICK_RANGE
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // FC OP_IPUT_OBJECT_VOLATILE
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_NULL_CHK_1,
 
     // FD OP_SGET_OBJECT_VOLATILE
     DF_DA,
@@ -797,65 +797,67 @@
     // FF OP_DISPATCH_FF
     DF_NOP,
 
+    //TODO: remove jumbo opcodes
+
     // 100 OP_CONST_CLASS_JUMBO vAAAA, type@BBBBBBBB
     DF_DA,
 
-    // 101 OP_CHECK_CAST_JUMBO vAAAA, type@BBBBBBBB
+    // 101 OP_CHK_CAST_JUMBO vAAAA, type@BBBBBBBB
     DF_UA,
 
     // 102 OP_INSTANCE_OF_JUMBO vAAAA, vBBBB, type@CCCCCCCC
     DF_DA | DF_UB,
 
     // 103 OP_NEW_INSTANCE_JUMBO vAAAA, type@BBBBBBBB
-    DF_DA,
+    DF_DA | DF_NON_NULL_DST,
 
     // 104 OP_NEW_ARRAY_JUMBO vAAAA, vBBBB, type@CCCCCCCC
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NON_NULL_DST,
 
     // 105 OP_FILLED_NEW_ARRAY_JUMBO {vCCCC .. vNNNN}, type@BBBBBBBB
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NON_NULL_RET,
 
     // 106 OP_IGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 107 OP_IGET_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA_WIDE | DF_UB | DF_IS_GETTER,
+    DF_DA_WIDE | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 108 OP_IGET_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 109 OP_IGET_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 10A OP_IGET_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 10B OP_IGET_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 10C OP_IGET_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_DA | DF_UB | DF_IS_GETTER,
+    DF_DA | DF_UB | DF_NULL_CHK_0 | DF_IS_GETTER,
 
     // 10D OP_IPUT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 10E OP_IPUT_WIDE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA_WIDE | DF_UB | DF_IS_SETTER,
+    DF_UA_WIDE | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 10F OP_IPUT_OBJECT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 110 OP_IPUT_BOOLEAN_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 111 OP_IPUT_BYTE_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 112 OP_IPUT_CHAR_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 113 OP_IPUT_SHORT_JUMBO vAAAA, vBBBB, field@CCCCCCCC
-    DF_UA | DF_UB | DF_IS_SETTER,
+    DF_UA | DF_UB | DF_NULL_CHK_1 | DF_IS_SETTER,
 
     // 114 OP_SGET_JUMBO vAAAA, vBBBB, field@CCCCCCCC
     DF_DA | DF_IS_GETTER,
@@ -900,13 +902,13 @@
     DF_UA | DF_IS_SETTER,
 
     // 122 OP_INVOKE_VIRTUAL_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 123 OP_INVOKE_SUPER_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 124 OP_INVOKE_DIRECT_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
-    DF_FORMAT_3RC,
+    DF_FORMAT_3RC | DF_NULL_CHK_OUT0,
 
     // 125 OP_INVOKE_STATIC_JUMBO {vCCCC .. vNNNN}, meth@BBBBBBBB
     DF_FORMAT_3RC,
@@ -1524,25 +1526,25 @@
     DF_NOP,
 
     // 1F2 OP_INVOKE_OBJECT_INIT_JUMBO
-    DF_NOP,
+    DF_NOP | DF_NULL_CHK_0,
 
     // 1F3 OP_IGET_VOLATILE_JUMBO
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NULL_CHK_0,
 
     // 1F4 OP_IGET_WIDE_VOLATILE_JUMBO
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_NULL_CHK_0,
 
     // 1F5 OP_IGET_OBJECT_VOLATILE_JUMBO
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_NULL_CHK_0,
 
     // 1F6 OP_IPUT_VOLATILE_JUMBO
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_NULL_CHK_1,
 
     // 1F7 OP_IPUT_WIDE_VOLATILE_JUMBO
-    DF_UA_WIDE | DF_UB,
+    DF_UA_WIDE | DF_UB | DF_NULL_CHK_1,
 
     // 1F8 OP_IPUT_OBJECT_VOLATILE_JUMBO
-    DF_UA | DF_UB,
+    DF_UA | DF_UB | DF_NULL_CHK_1,
 
     // 1F9 OP_SGET_VOLATILE_JUMBO
     DF_DA,
@@ -1567,7 +1569,7 @@
 
     // Beginning of extended MIR opcodes
     // 200 OP_MIR_PHI
-    DF_PHI | DF_DA,
+    DF_PHI | DF_DA | DF_NULL_TRANSFER_N,
     /*
      * For extended MIR inserted at the MIR2LIR stage, it is okay to have
      * undefined values here.
@@ -2357,3 +2359,140 @@
         change &= isIterative;
     }
 }
+
+static bool nullCheckEliminationInit(struct CompilationUnit* cUnit,
+                                     struct BasicBlock* bb)
+{
+    if (bb->dataFlowInfo == NULL) return false;
+    bb->dataFlowInfo->endingNullCheckV =
+        oatAllocBitVector(cUnit->numSSARegs, false);
+    oatClearAllBits(bb->dataFlowInfo->endingNullCheckV);
+    return true;
+}
+
+/* Eliminate unnecessary null checks for a basic block. */
+static bool eliminateNullChecks( struct CompilationUnit* cUnit,
+                                 struct BasicBlock* bb)
+{
+    if (bb->dataFlowInfo == NULL) return false;
+    /*
+     * Set initial state.  Be conservative with catch
+     * blocks and start with no assumptions about null check
+     * status (except for "this").
+     */
+
+    if ((bb->blockType == kEntryBlock) | bb->catchEntry) {
+        oatClearAllBits(cUnit->tempSSARegisterV);
+        if (!cUnit->method->IsStatic()) {
+            // If non-static method, mark "this" as non-null
+            int thisReg = cUnit->method->NumRegisters() -
+                          cUnit->method->NumIns();
+            oatSetBit(cUnit->tempSSARegisterV, thisReg);
+        }
+    } else {
+        // Starting state is intesection of all incoming arcs
+        GrowableList* blockList = &cUnit->blockList;
+        ArenaBitVectorIterator bvIterator;
+        oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
+        int predBBIdx = oatBitVectorIteratorNext(&bvIterator);
+        DCHECK(predBBIdx != -1);
+        BasicBlock* predBB = (BasicBlock*)oatGrowableListGetElement(
+            blockList, predBBIdx);
+        oatCopyBitVector(cUnit->tempSSARegisterV,
+                         predBB->dataFlowInfo->endingNullCheckV);
+        while (true) {
+            predBBIdx = oatBitVectorIteratorNext(&bvIterator);
+            if (predBBIdx == -1) break;
+            predBB = (BasicBlock*)oatGrowableListGetElement(
+                blockList, predBBIdx);
+            oatIntersectBitVectors(cUnit->tempSSARegisterV,
+                cUnit->tempSSARegisterV,
+                predBB->dataFlowInfo->endingNullCheckV);
+        }
+    }
+
+    // Walk through the instruction in the block, updating as necessary
+    for (MIR* mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        if (mir->ssaRep == NULL) {
+            continue;
+        }
+        int dfAttributes =
+            oatDataFlowAttributes[mir->dalvikInsn.opcode];
+
+        // Mark target of NEW* as non-null
+        if (dfAttributes & DF_NON_NULL_DST) {
+            oatSetBit(cUnit->tempSSARegisterV, mir->ssaRep->defs[0]);
+        }
+
+        // Mark non-null returns from invoke-style NEW*
+        if (dfAttributes & DF_NON_NULL_RET) {
+            MIR* nextMir = mir->next;
+            // Next should be an OP_MOVE_RESULT_OBJECT
+            if (nextMir && nextMir->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT) {
+                // Mark as null checked
+                oatSetBit(cUnit->tempSSARegisterV, nextMir->ssaRep->uses[0]);
+            } else {
+                if (nextMir) {
+                    LOG(WARNING) << "Unexpected opcode following new: " <<
+                    (int)nextMir->dalvikInsn.opcode;
+                } else {
+                    LOG(WARNING) << "Unexpected termination following new";
+                }
+            }
+        }
+
+        /*
+         * Propagate nullcheck state on register copies (including
+         * Phi pseudo copies.  For the latter, nullcheck state is
+         * the "and" of all the Phi's operands.
+         */
+        if (dfAttributes & (DF_NULL_TRANSFER_0 | DF_NULL_TRANSFER_N)) {
+            int tgtSreg = mir->ssaRep->defs[0];
+            int operands = (dfAttributes & DF_NULL_TRANSFER_0) ? 1 :
+                mir->ssaRep->numUses;
+            bool nullChecked = true;
+            for (int i = 0; i < operands; i++) {
+                nullChecked &= oatIsBitSet(cUnit->tempSSARegisterV,
+                    mir->ssaRep->uses[i]);
+            }
+            if (nullChecked) {
+                oatSetBit(cUnit->tempSSARegisterV, tgtSreg);
+            }
+        }
+
+        // Already nullchecked?
+        if (dfAttributes & DF_HAS_NULL_CHKS) {
+            int srcSreg = (dfAttributes & DF_NULL_CHK_1) ?
+                mir->ssaRep->uses[1] : mir->ssaRep->uses[0];
+            if (oatIsBitSet(cUnit->tempSSARegisterV, srcSreg)) {
+                // Eliminate the null check
+                mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+            } else {
+                // Mark sReg as null-checked
+                oatSetBit(cUnit->tempSSARegisterV, srcSreg);
+            }
+        }
+    }
+
+    // Did anything change?
+    bool res = oatCompareBitVectors(bb->dataFlowInfo->endingNullCheckV,
+                                    cUnit->tempSSARegisterV);
+    if (res) {
+        oatCopyBitVector(bb->dataFlowInfo->endingNullCheckV,
+                         cUnit->tempSSARegisterV);
+    }
+    return res;
+}
+
+void oatMethodNullCheckElimination(CompilationUnit *cUnit)
+{
+    if (!(cUnit->disableOpt & (1 << kNullCheckElimination))) {
+        DCHECK(cUnit->tempSSARegisterV != NULL);
+        oatDataFlowAnalysisDispatcher(cUnit, nullCheckEliminationInit,
+                                      kAllNodes,
+                                      false /* isIterative */);
+        oatDataFlowAnalysisDispatcher(cUnit, eliminateNullChecks,
+                                      kPreOrderDFSTraversal,
+                                      true /* isIterative */);
+    }
+}
diff --git a/src/compiler/Dataflow.h b/src/compiler/Dataflow.h
index 235ad31..e4a3726 100644
--- a/src/compiler/Dataflow.h
+++ b/src/compiler/Dataflow.h
@@ -35,9 +35,15 @@
     kFormat35c,
     kFormat3rc,
     kPhi,
-    kNullNRangeCheck0,
-    kNullNRangeCheck1,
-    kNullNRangeCheck2,
+    kNullCheckSrc0,        // Null check of src[0]
+    kNullCheckSrc1,        // Null check of src[1]
+    kNullCheckOut0,        // Null check out outgoing arg0
+    kDstNonNull,           // May assume dst is non-null
+    kRetNonNull,           // May assume retval is non-null
+    kNullTransferSrc0,     // Object copy src[0] -> dst
+    kNullTransferSrcN,     // Phi null check state transfer
+    kRangeCheckSrc1,       // Range check of src[1]
+    kRangeCheckSrc2,       // Range check of src[2]
     kFPA,
     kFPB,
     kFPC,
@@ -60,9 +66,15 @@
 #define DF_FORMAT_35C           (1 << kFormat35c)
 #define DF_FORMAT_3RC           (1 << kFormat3rc)
 #define DF_PHI                  (1 << kPhi)
-#define DF_NULL_N_RANGE_CHECK_0 (1 << kNullNRangeCheck0)
-#define DF_NULL_N_RANGE_CHECK_1 (1 << kNullNRangeCheck1)
-#define DF_NULL_N_RANGE_CHECK_2 (1 << kNullNRangeCheck2)
+#define DF_NULL_CHK_0           (1 << kNullCheckSrc0)
+#define DF_NULL_CHK_1           (1 << kNullCheckSrc1)
+#define DF_NULL_CHK_OUT0        (1 << kNullCheckOut0)
+#define DF_NON_NULL_DST         (1 << kDstNonNull)
+#define DF_NON_NULL_RET         (1 << kRetNonNull)
+#define DF_NULL_TRANSFER_0      (1 << kNullTransferSrc0)
+#define DF_NULL_TRANSFER_N      (1 << kNullTransferSrcN)
+#define DF_RANGE_CHK_1          (1 << kRangeCheckSrc1)
+#define DF_RANGE_CHK_2          (1 << kRangeCheckSrc2)
 #define DF_FP_A                 (1 << kFPA)
 #define DF_FP_B                 (1 << kFPB)
 #define DF_FP_C                 (1 << kFPC)
@@ -74,9 +86,13 @@
 
 #define DF_HAS_DEFS             (DF_DA | DF_DA_WIDE)
 
-#define DF_HAS_NR_CHECKS        (DF_NULL_N_RANGE_CHECK_0 | \
-                                 DF_NULL_N_RANGE_CHECK_1 | \
-                                 DF_NULL_N_RANGE_CHECK_2)
+#define DF_HAS_NULL_CHKS        (DF_NULL_CHK_0 | \
+                                 DF_NULL_CHK_1 | \
+                                 DF_NULL_CHK_OUT0)
+
+#define DF_HAS_NR_CHKS          (DF_HAS_NULL_CHKS | \
+                                 DF_RANGE_CHK_1 | \
+                                 DF_RANGE_CHK_2)
 
 #define DF_A_IS_REG             (DF_UA | DF_UA_WIDE | DF_DA | DF_DA_WIDE)
 #define DF_B_IS_REG             (DF_UB | DF_UB_WIDE)
@@ -91,6 +107,7 @@
     ArenaBitVector* liveInV;
     ArenaBitVector* phiV;
     int* dalvikToSSAMap;
+    ArenaBitVector* endingNullCheckV;
 } BasicBlockDataFlow;
 
 typedef struct SSARepresentation {
@@ -125,4 +142,7 @@
 #define DECODE_REG(v)                   (v & 0xffff)
 #define DECODE_SUB(v)                   (((unsigned int) v) >> 16)
 
+
+void oatMethodNullCheckElimination(CompilationUnit*);
+
 #endif  // ART_SRC_COMPILER_DATAFLOW_H_
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index c419f1a..086c0bb 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -619,6 +619,7 @@
             BasicBlock *catchBlock = findBlock(cUnit, iterator.Get().address_,
                                                false /* split*/,
                                                false /* creat */);
+            catchBlock->catchEntry = true;
             SuccessorBlockInfo *successorBlockInfo =
                   (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
                   false);
@@ -702,6 +703,7 @@
          (1 << kLoadStoreElimination) |
          (1 << kLoadHoisting) |
          (1 << kSuppressLoads) |
+         (1 << kNullCheckElimination) |
          (1 << kPromoteRegs) |
          0;
 #endif
@@ -841,6 +843,9 @@
     /* Perform SSA transformation for the whole method */
     oatMethodSSATransformation(&cUnit);
 
+    /* Perform null check elimination */
+    oatMethodNullCheckElimination(&cUnit);
+
     oatInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
 
     /* Allocate Registers using simple local allocation scheme */
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc
index 5a75cee..14c7e57 100644
--- a/src/compiler/codegen/CodegenFactory.cc
+++ b/src/compiler/codegen/CodegenFactory.cc
@@ -127,7 +127,6 @@
     LIR* defEnd;
     assert(!rlDest.wide);
     assert(!rlSrc.wide);
-    oatKillNullCheckedLoc(cUnit, rlDest);
     rlSrc = oatUpdateLoc(cUnit, rlSrc);
     rlDest = oatUpdateLoc(cUnit, rlDest);
     if (rlSrc.location == kLocPhysReg) {
@@ -190,7 +189,6 @@
     assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
     assert(rlDest.wide);
     assert(rlSrc.wide);
-    oatKillNullCheckedLoc(cUnit, rlDest);
     if (rlSrc.location == kLocPhysReg) {
         if (oatIsLive(cUnit, rlSrc.lowReg) ||
             oatIsLive(cUnit, rlSrc.highReg) ||
diff --git a/src/compiler/codegen/Optimizer.h b/src/compiler/codegen/Optimizer.h
index b234587..23f0f17 100644
--- a/src/compiler/codegen/Optimizer.h
+++ b/src/compiler/codegen/Optimizer.h
@@ -27,6 +27,7 @@
     kLoadStoreElimination = 0,
     kLoadHoisting,
     kSuppressLoads,
+    kNullCheckElimination,
     kPromoteRegs,
 };
 
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index 82ce23e..ad19475 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -45,12 +45,6 @@
     return DECODE_REG(oatConvertSSARegToDalvik(cUnit, sReg));
 }
 
-/* Reset the tracker to unknown state */
-static inline void oatResetNullCheck(CompilationUnit* cUnit)
-{
-    oatClearAllBits(cUnit->regPool->nullCheckedRegs);
-}
-
 /*
  * Get the "real" sreg number associated with an sReg slot.  In general,
  * sReg values passed through codegen are the SSA names created by
@@ -161,10 +155,6 @@
 
 extern void oatResetDefTracking(CompilationUnit* cUnit);
 
-/* Kill the corresponding bit in the null-checked register list */
-extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
-                                  RegLocation loc);
-
 extern RegisterInfo *oatIsLive(CompilationUnit* cUnit, int reg);
 
 /* To be used when explicitly managing register use */
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 8295b33..8b84500 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -1036,17 +1036,3 @@
     assert(res.wide);
     return res;
 }
-
-/* Kill the corresponding bit in the null-checked register list */
-extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
-                                  RegLocation loc)
-{
-    if (loc.sRegLow == INVALID_SREG)
-        return;
-    oatClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
-    if (loc.wide) {
-        assert(oatSRegHi(loc.sRegLow) != INVALID_SREG);
-        oatClearBit(cUnit->regPool->nullCheckedRegs,
-                    oatSRegHi(loc.sRegLow));
-    }
-}
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index 34a333d..8012d7d 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -70,19 +70,14 @@
     return branch;
 }
 
-/*
- * Perform null-check on a register. sReg is the ssa register being checked,
- * and mReg is the machine register holding the actual value. If internal state
- * indicates that sReg has been checked before the check request is ignored.
- */
+/* Perform null-check on a register.  */
 static ArmLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
                              MIR* mir)
 {
-    if (oatIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
-        /* This particular Dalvik register has been null-checked */
+    if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
+        mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
         return NULL;
     }
-    oatSetBit(cUnit->regPool->nullCheckedRegs, sReg);
     return genImmedCheck(cUnit, kArmCondEq, mReg, 0, mir, kArmThrowNullPointer);
 }
 
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 212358f..53e8dc8 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -149,7 +149,6 @@
 } RegisterInfo;
 
 typedef struct RegisterPool {
-    ArenaBitVector *nullCheckedRegs; // Which registers have been null-checked?
     int numCoreRegs;
     RegisterInfo *coreRegs;
     int nextCoreReg;
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 10f470d..7196efc 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -681,7 +681,7 @@
             break;
         case 4: // Get ...->super_class_->vtable [u/s r0]
             loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
-            if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+            if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
                 // Range check, throw NSM on failure
                 tReg = oatAllocTemp(cUnit);
                 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
@@ -1110,7 +1110,7 @@
             break;
 
         case OP_MOVE_RESULT_WIDE:
-            if (mir->OptimizationFlags & MIR_INLINED)
+            if (mir->optimizationFlags & MIR_INLINED)
                 break;  // Nop - combined w/ previous invoke
             /*
              * Somewhat hacky here.   Because we're now passing
@@ -1130,7 +1130,7 @@
 
         case OP_MOVE_RESULT:
         case OP_MOVE_RESULT_OBJECT:
-            if (mir->OptimizationFlags & MIR_INLINED)
+            if (mir->optimizationFlags & MIR_INLINED)
                 break;  // Nop - combined w/ previous invoke
             /* See comment for OP_MOVE_RESULT_WIDE */
             assert(retLoc.lowReg == r0);
@@ -1420,55 +1420,55 @@
 
         case OP_IGET_WIDE:
         case OP_IGET_WIDE_VOLATILE:
-            genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
+            genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
             break;
 
         case OP_IGET:
         case OP_IGET_VOLATILE:
         case OP_IGET_OBJECT:
         case OP_IGET_OBJECT_VOLATILE:
-            genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
+            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
             break;
 
         case OP_IGET_BOOLEAN:
         case OP_IGET_BYTE:
-            genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
+            genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
             break;
 
         case OP_IGET_CHAR:
-            genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
+            genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
             break;
 
         case OP_IGET_SHORT:
-            genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
+            genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
             break;
 
         case OP_IPUT_WIDE:
         case OP_IPUT_WIDE_VOLATILE:
-            genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
+            genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
             break;
 
         case OP_IPUT_OBJECT:
         case OP_IPUT_OBJECT_VOLATILE:
-            genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
             break;
 
         case OP_IPUT:
         case OP_IPUT_VOLATILE:
-            genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
             break;
 
         case OP_IPUT_BOOLEAN:
         case OP_IPUT_BYTE:
-            genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
+            genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
             break;
 
         case OP_IPUT_CHAR:
-            genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
+            genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
             break;
 
         case OP_IPUT_SHORT:
-            genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
+            genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
             break;
 
         case OP_SGET:
@@ -1805,7 +1805,6 @@
     oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
 
     oatClobberAllRegs(cUnit);
-    oatResetNullCheck(cUnit);
 
     ArmLIR* headLIR = NULL;
 
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index cd3a64a..c54a0a8 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -450,7 +450,7 @@
     loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
 }
 
-static void genIGetX(CompilationUnit* cUnit, MIR* mir, OpSize size,
+static void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
                      RegLocation rlDest, RegLocation rlObj)
 {
     Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -485,7 +485,7 @@
     }
 }
 
-static void genIPutX(CompilationUnit* cUnit, MIR* mir, OpSize size,
+static void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
                     RegLocation rlSrc, RegLocation rlObj, bool isObject)
 {
     Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -521,7 +521,7 @@
     }
 }
 
-static void genIGetWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+static void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
                         RegLocation rlObj)
 {
     Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -564,7 +564,7 @@
     }
 }
 
-static void genIPutWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+static void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
                         RegLocation rlObj)
 {
     Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
@@ -886,8 +886,6 @@
     for (int i = 0; i < numFPTemps; i++) {
         oatMarkTemp(cUnit, fpTemps[i]);
     }
-    pool->nullCheckedRegs =
-        oatAllocBitVector(cUnit->numSSARegs, false);
 }
 
 /*
@@ -1267,11 +1265,7 @@
     loadValueDirectFixed(cUnit, rlSrc, r0);
 
     /* null array object? */
-    ArmLIR*  pcrLabel = NULL;
-
-    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
-        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
-    }
+    genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
     loadWordDisp(cUnit, rSELF,
                  OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
     /* Get the array's clazz */
@@ -1295,7 +1289,7 @@
         genRegCopy(cUnit, regPtr, rlArray.lowReg);
     }
 
-    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+    if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
         int regLen = oatAllocTemp(cUnit);
         //NOTE: max live temps(4) here.
         /* Get len */
@@ -1331,15 +1325,11 @@
     int regPtr;
 
     /* null object? */
-    ArmLIR*  pcrLabel = NULL;
-
-    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
-        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
-    }
+    genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
 
     regPtr = oatAllocTemp(cUnit);
 
-    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+    if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
         int regLen = oatAllocTemp(cUnit);
         /* Get len */
         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
@@ -1405,13 +1395,9 @@
     }
 
     /* null object? */
-    ArmLIR*  pcrLabel = NULL;
+    genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
 
-    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
-        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
-    }
-
-    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+    if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
         int regLen = oatAllocTemp(cUnit);
         //NOTE: max live temps(4) here.
         /* Get len */
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index 2a145f8..5c1bbef 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -163,6 +163,16 @@
   }
 }
 
+TEST_F(CompilerTest, NullCheckElimination1) {
+  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+  AssertStaticIntMethod(2054, LoadDex("ExceptionTest"), "ExceptionTest", "nullCheckTestNoThrow", "(I)I", 1976);
+}
+
+TEST_F(CompilerTest, DISABLED_NullCheckElimination2) {
+  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+  AssertStaticIntMethod(2057, LoadDex("ExceptionTest"), "ExceptionTest", "nullCheckTestThrow", "(I)I", 1976);
+}
+
 TEST_F(CompilerTest, ByBillion) {
   CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
   AssertStaticLongMethod(123, LoadDex("IntMath"), "IntMath", "divideLongByBillion", "(J)J", 123000000000LL);
diff --git a/test/ExceptionTest/ExceptionTest.java b/test/ExceptionTest/ExceptionTest.java
new file mode 100644
index 0000000..13ef058
--- /dev/null
+++ b/test/ExceptionTest/ExceptionTest.java
@@ -0,0 +1,158 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+class ExceptionTest {
+
+    public int ifoo;
+
+    /* Test requires visual inspection of object code to verify */
+    int noThrow(ExceptionTest nonNullA,
+                ExceptionTest nonNullB,
+                ExceptionTest nonNullC) {
+
+        // "this" check should be eliminated on both IGET/IPUT
+        ifoo++;
+
+       // "this" check should be eliminated on both IGET/IPUT
+       if (ifoo != 321) {
+           // Check not eliminated
+           nonNullA.ifoo = 12;
+           // Check not eliminated
+           nonNullB.ifoo = 21;
+       } else {
+           // Check not eliminated
+           nonNullA.ifoo = 12;
+       }
+
+       // Check eliminated
+       nonNullA.ifoo = 13;
+
+       // Check not eliminated
+       nonNullB.ifoo = 21;
+
+       nonNullC = nonNullB;
+
+       // Check eliminated
+       nonNullC.ifoo = 32;
+
+      // All null checks eliminated
+      return ifoo + nonNullA.ifoo + nonNullB.ifoo + nonNullC.ifoo;
+    }
+
+    /* Test to ensure we don't remove necessary null checks */
+    int checkThrow(ExceptionTest nonNullA,
+                   ExceptionTest nonNullB,
+                   ExceptionTest nonNullC,
+                   ExceptionTest nullA,
+                   ExceptionTest nullB,
+                   ExceptionTest nullC) {
+
+        // "this" check should be eliminated on both IGET/IPUT
+        ifoo++;
+
+       try {
+           nullA.ifoo = 12;
+           // Should not be reached
+           return -1;
+       } catch (NullPointerException npe) {
+           ifoo++;
+       }
+       try {
+           nullB.ifoo = 13;
+           // Should not be reached
+           return -2;
+       } catch (NullPointerException npe) {
+           ifoo++;
+       }
+       try {
+           nullC.ifoo = 14;
+           // Should not be reached
+           return -3;
+       } catch (NullPointerException npe) {
+           ifoo++;
+       }
+
+       // "this" check should be eliminated
+       if (ifoo != 321) {
+           // Check not eliminated
+           nonNullA.ifoo = 12;
+           // Check not eliminated
+           nonNullB.ifoo = 21;
+           // Should throw here
+           try {
+               nullA.ifoo = 11;
+               return -4;
+           } catch (NullPointerException npe) {
+           }
+       } else {
+           // Check not eliminated
+           nonNullA.ifoo = 12;
+           // Should throw here
+           try {
+               nullA.ifoo = 11;
+               return -5;
+           } catch (NullPointerException npe) {
+           }
+       }
+
+       // Check not eliminated
+       nonNullA.ifoo = 13;
+
+       // Check not eliminated
+       nonNullB.ifoo = 21;
+
+       nonNullC = nonNullB;
+
+       // Check eliminated
+       nonNullC.ifoo = 32;
+
+       // Should throw here
+       try {
+           nullA.ifoo = 13;
+           return -6;
+       } catch (NullPointerException npe) {
+       }
+
+      return ifoo + nonNullA.ifoo + nonNullB.ifoo + nonNullC.ifoo;
+    }
+
+
+    static int nullCheckTestNoThrow(int x) {
+        ExceptionTest base = new ExceptionTest();
+        ExceptionTest a = new ExceptionTest();
+        ExceptionTest b = new ExceptionTest();
+        ExceptionTest c = new ExceptionTest();
+        base.ifoo = x;
+        return base.noThrow(a,b,c);
+    }
+
+    static int nullCheckTestThrow(int x) {
+        ExceptionTest base = new ExceptionTest();
+        ExceptionTest a = new ExceptionTest();
+        ExceptionTest b = new ExceptionTest();
+        ExceptionTest c = new ExceptionTest();
+        ExceptionTest d = null;
+        ExceptionTest e = null;
+        ExceptionTest f = null;
+        base.ifoo = x;
+        return base.checkThrow(a,b,c,d,e,f);
+    }
+
+
+    public static void main(String[] args) {
+        int res;
+
+        res = nullCheckTestNoThrow(1976);
+        if (res == 2054) {
+            System.out.println("nullCheckTestNoThrow PASSED");
+        } else {
+            System.out.println("nullCheckTestNoThrow FAILED: " + res);
+        }
+
+        res = nullCheckTestThrow(1976);
+        if (res == 2057) {
+            System.out.println("nullCheckTestNoThrow PASSED");
+        } else {
+            System.out.println("nullCheckTestNoThrow FAILED: " + res);
+        }
+    }
+}