Fixed OOM exception handling in JIT'ed code and added a new unit test.
diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c
index d65023d..30a7b1b 100644
--- a/vm/compiler/codegen/arm/Codegen.c
+++ b/vm/compiler/codegen/arm/Codegen.c
@@ -810,7 +810,7 @@
 {
     ArmLIR *res;
     res = opRegReg(cUnit, OP_CMP, reg1, reg2);
-    ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
+    ArmLIR *branch = opCondBranch(cUnit, cond);
     genCheckCommon(cUnit, dOffset, branch, pcrLabel);
     return res;
 }
@@ -1851,8 +1851,7 @@
     /* Check if rechain limit is reached */
     opRegImm(cUnit, OP_CMP, r1, 0, rNone);
 
-    ArmLIR *bypassRechaining =
-        opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
+    ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
 
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
@@ -1936,7 +1935,7 @@
     /* Check if r2 (predicted class) == r3 (actual class) */
     opRegReg(cUnit, OP_CMP, r2, r3);
 
-    return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
+    return opCondBranch(cUnit, ARM_COND_EQ);
 }
 
 /* Geneate a branch to go back to the interpreter */
@@ -1978,7 +1977,7 @@
                                     ArmConditionCode cond,
                                     ArmLIR *target)
 {
-    ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
+    ArmLIR *branch = opCondBranch(cUnit, cond);
     branch->generic.target = (LIR *) target;
     return branch;
 }
@@ -2327,7 +2326,20 @@
             genExportPC(cUnit, mir, r2, r3 );
             loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
             opReg(cUnit, OP_BLX, r4PC);
-            genZeroCheck(cUnit, r0, mir->offset, NULL);
+            /* generate a branch over if allocation is successful */
+            opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
+            ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
+            /*
+             * OOM exception needs to be thrown here and cannot re-execute
+             */
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            /* noreturn */
+
+            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
             storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
             break;
         }
@@ -2341,14 +2353,12 @@
             loadConstant(cUnit, r1, (int) classPtr );
             loadValue(cUnit, mir->dalvikInsn.vA, r0);  /* Ref */
             opRegImm(cUnit, OP_CMP, r0, 0, rNone);   /* Null? */
-            ArmLIR *branch1 =
-                opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
+            ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
             /* r0 now contains object->clazz */
             loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
             loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
             opRegReg(cUnit, OP_CMP, r0, r1);
-            ArmLIR *branch2 =
-                opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
+            ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
             opReg(cUnit, OP_BLX, r4PC);
             /* check cast failed - punt to the interpreter */
             genZeroCheck(cUnit, r0, mir->offset, NULL);
@@ -2658,7 +2668,7 @@
     int vSrc = mir->dalvikInsn.vB;
     int vDest = mir->dalvikInsn.vA;
     int lit = mir->dalvikInsn.vC;
-    OpKind op;
+    OpKind op = 0;      /* Make gcc happy */
     int reg0, reg1, regDest;
 
     reg0 = selectFirstRegister(cUnit, vSrc, false);
@@ -2800,13 +2810,29 @@
             loadValue(cUnit, mir->dalvikInsn.vB, r1);  /* Len */
             loadConstant(cUnit, r0, (int) classPtr );
             loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
+            /*
+             * "len < 0": bail to the interpreter to re-execute the
+             * instruction
+             */
             ArmLIR *pcrLabel =
                 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
             genExportPC(cUnit, mir, r2, r3 );
             loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
             opReg(cUnit, OP_BLX, r4PC);
-            /* Note: on failure, we'll bail and reinterpret */
-            genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
+            /* generate a branch over if allocation is successful */
+            opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
+            ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
+            /*
+             * OOM exception needs to be thrown here and cannot re-execute
+             */
+            loadConstant(cUnit, r0,
+                         (int) (cUnit->method->insns + mir->offset));
+            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
+            /* noreturn */
+
+            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            target->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR *) target;
             storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
             break;
         }
@@ -2819,13 +2845,13 @@
 //TUNING: compare to 0 primative to allow use of CB[N]Z
             opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
             /* When taken r0 has NULL which can be used for store directly */
-            ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
+            ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
             /* r1 now contains object->clazz */
             loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
             loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
             loadConstant(cUnit, r0, 1);                /* Assume true */
             opRegReg(cUnit, OP_CMP, r1, r2);
-            ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
+            ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
             opRegReg(cUnit, OP_MOV, r0, r1);
             opRegReg(cUnit, OP_MOV, r1, r2);
             opReg(cUnit, OP_BLX, r4PC);
@@ -3345,8 +3371,7 @@
             /* Check if rechain limit is reached */
             opRegImm(cUnit, OP_CMP, r1, 0, rNone);
 
-            ArmLIR *bypassRechaining =
-                opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
+            ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
 
             loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                          jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
diff --git a/vm/compiler/codegen/arm/Thumb2Util.c b/vm/compiler/codegen/arm/Thumb2Util.c
index b40656d..dfbb030 100644
--- a/vm/compiler/codegen/arm/Thumb2Util.c
+++ b/vm/compiler/codegen/arm/Thumb2Util.c
@@ -68,8 +68,7 @@
 
 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
-static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
-                        int value2);
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc);
 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
                         int rSrc2);
@@ -795,18 +794,9 @@
     return newLIR0(cUnit, opCode);
 }
 
-static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
-                        int value2)
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
 {
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_COND_BR:
-            opCode = THUMB_B_COND;
-            break;
-        default:
-            assert(0);
-    }
-    return newLIR2(cUnit, opCode, value1, value2);
+    return newLIR2(cUnit, THUMB_B_COND, 0 /* offset to be patched */, cc);
 }
 
 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
@@ -1210,10 +1200,10 @@
     /* Note: using hardcoded r7 & r4PC for now.  revisit */
     loadConstant(cUnit, r7, -1);
     opRegReg(cUnit, OP_CMP, op1hi, op2hi);
-    ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_LT);
-    ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
+    ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_LT);
+    ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_GT);
     opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
-    ArmLIR *branch3 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
+    ArmLIR *branch3 = opCondBranch(cUnit, ARM_COND_EQ);
 
     // TODO: need assert mechanism to verify IT block size
     branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
diff --git a/vm/compiler/codegen/arm/ThumbUtil.c b/vm/compiler/codegen/arm/ThumbUtil.c
index 49e04b4..4065865 100644
--- a/vm/compiler/codegen/arm/ThumbUtil.c
+++ b/vm/compiler/codegen/arm/ThumbUtil.c
@@ -72,8 +72,7 @@
 
 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
-static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
-                        int value2);
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc);
 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
                         int rSrc2);
@@ -493,18 +492,9 @@
     return newLIR0(cUnit, opCode);
 }
 
-static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
-                        int value2)
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
 {
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_COND_BR:
-            opCode = THUMB_B_COND;
-            break;
-        default:
-            assert(0);
-    }
-    return newLIR2(cUnit, opCode, value1, value2);
+    return newLIR2(cUnit, THUMB_B_COND, 0 /* offset to be patched */, cc);
 }
 
 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
diff --git a/vm/compiler/template/armv5te-vfp/TemplateOpList.h b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
index c95163c..6d1ce67 100644
--- a/vm/compiler/template/armv5te-vfp/TemplateOpList.h
+++ b/vm/compiler/template/armv5te-vfp/TemplateOpList.h
@@ -50,3 +50,4 @@
 JIT_TEMPLATE(CMPG_FLOAT_VFP)
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
diff --git a/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S b/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S
new file mode 100644
index 0000000..b737798
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S
@@ -0,0 +1,6 @@
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
diff --git a/vm/compiler/template/armv5te/TemplateOpList.h b/vm/compiler/template/armv5te/TemplateOpList.h
index 39cd07a..20fb7fa 100644
--- a/vm/compiler/template/armv5te/TemplateOpList.h
+++ b/vm/compiler/template/armv5te/TemplateOpList.h
@@ -35,3 +35,4 @@
 JIT_TEMPLATE(SHL_LONG)
 JIT_TEMPLATE(SHR_LONG)
 JIT_TEMPLATE(USHR_LONG)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
index 3b0b149..c373250 100644
--- a/vm/compiler/template/armv5te/footer.S
+++ b/vm/compiler/template/armv5te/footer.S
@@ -31,15 +31,19 @@
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
-/* NOTE - this path can be exercised if the JIT threshold is set to 5 */
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
 .LhandleException:
-    ldr     r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
     ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
-    ldr     rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
-    mov     pc, r0                  @ branch to dvmMterpCommonExceptionThrown
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
 
     .align  2
 .LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/armv7-a/TemplateOpList.h b/vm/compiler/template/armv7-a/TemplateOpList.h
index c95163c..6d1ce67 100644
--- a/vm/compiler/template/armv7-a/TemplateOpList.h
+++ b/vm/compiler/template/armv7-a/TemplateOpList.h
@@ -50,3 +50,4 @@
 JIT_TEMPLATE(CMPG_FLOAT_VFP)
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
+JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
diff --git a/vm/compiler/template/config-armv5te-vfp b/vm/compiler/template/config-armv5te-vfp
index 628e75f..ab3ff90 100644
--- a/vm/compiler/template/config-armv5te-vfp
+++ b/vm/compiler/template/config-armv5te-vfp
@@ -42,6 +42,7 @@
     op TEMPLATE_SHL_LONG armv5te
     op TEMPLATE_SHR_LONG armv5te
     op TEMPLATE_USHR_LONG armv5te
+    op TEMPLATE_THROW_EXCEPTION_COMMON armv5te
 
 op-end
 
diff --git a/vm/compiler/template/config-armv7-a b/vm/compiler/template/config-armv7-a
index ecf0b3a..aed0fa7 100644
--- a/vm/compiler/template/config-armv7-a
+++ b/vm/compiler/template/config-armv7-a
@@ -42,6 +42,7 @@
     op TEMPLATE_SHL_LONG armv5te
     op TEMPLATE_SHR_LONG armv5te
     op TEMPLATE_USHR_LONG armv5te
+    op TEMPLATE_THROW_EXCEPTION_COMMON armv5te
 
 op-end
 
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 7b1d6aa..74d6936 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -1014,6 +1014,18 @@
 .Lsqrt:
     .word   sqrt
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
@@ -1049,15 +1061,19 @@
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
-/* NOTE - this path can be exercised if the JIT threshold is set to 5 */
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
 .LhandleException:
-    ldr     r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
     ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
-    ldr     rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
-    mov     pc, r0                  @ branch to dvmMterpCommonExceptionThrown
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
 
     .align  2
 .LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index 801c0c7..d2e6f54 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -748,6 +748,18 @@
     bx      lr
 
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
@@ -783,15 +795,19 @@
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
-/* NOTE - this path can be exercised if the JIT threshold is set to 5 */
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
 .LhandleException:
-    ldr     r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
     ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
-    ldr     rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
-    mov     pc, r0                  @ branch to dvmMterpCommonExceptionThrown
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
 
     .align  2
 .LdvmAsmInstructionStart:
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index 854871b..4ed5ea1 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -1014,6 +1014,18 @@
 .Lsqrt:
     .word   sqrt
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
+dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
+/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
+    /*
+     * Throw an exception from JIT'ed code.
+     * On entry:
+     *    r0    Dalvik PC that raises the exception
+     */
+    b       .LhandleException
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
@@ -1049,15 +1061,19 @@
     str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
     cmp     r1, #0                      @ null?
     str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
     bne     .LhandleException             @ no, handle exception
     bx      r2
 
-/* NOTE - this path can be exercised if the JIT threshold is set to 5 */
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
 .LhandleException:
-    ldr     r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
     ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
-    ldr     rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
-    mov     pc, r0                  @ branch to dvmMterpCommonExceptionThrown
+    mov     rPC, r0                 @ reload the faulting Dalvik address
+    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
 
     .align  2
 .LdvmAsmInstructionStart: