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)