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: