Check-cast, instance-of, misc fixes
Support for check-cast and instanceof (largely untested). Added a bunch of
helper stubs, a debugging option to show the method name if we try to branch
to an uncompiled method, new tests and a missing call to reset the compiler's
arena storage.
Change-Id: I933ad1fbdbca110f92c9201cae2353bf4862a8ac
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 9c87659..44cbc0e 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -15,6 +15,7 @@
*/
#define FORCE_SLOW 0
+#define DISPLAY_MISSING_TARGETS
static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
INVALID_REG, INVALID_SREG, 0,
@@ -863,6 +864,19 @@
return callState;
}
+#ifdef DISPLAY_MISSING_TARGETS
+// Debugging routine - if null target, branch to DebugMe
+static void genShowTarget(CompilationUnit* cUnit)
+{
+ ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
+ ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = -1;
+ branchOver->generic.target = (LIR*)target;
+}
+#endif
+
static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
bool direct, bool range)
{
@@ -886,6 +900,9 @@
while (callState >= 0) {
callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
}
+#ifdef DISPLAY_MISSING_TARGETS
+ genShowTarget(cUnit);
+#endif
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -914,6 +931,9 @@
while (callState >= 0) {
callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
}
+#ifdef DISPLAY_MISSING_TARGETS
+ genShowTarget(cUnit);
+#endif
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -963,6 +983,9 @@
while (callState >= 0) {
callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
}
+#ifdef DISPLAY_MISSING_TARGETS
+ genShowTarget(cUnit);
+#endif
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -999,6 +1022,9 @@
while (callState >= 0) {
callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
}
+#ifdef DISPLAY_MISSING_TARGETS
+ genShowTarget(cUnit);
+#endif
newLIR1(cUnit, kThumbBlxR, rLR);
}
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index b9e135c..dbaf9ea 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -513,7 +513,7 @@
int mReg = loadCurrMethod(cUnit);
int resReg = oatAllocTemp(cUnit);
RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
- loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(),
+ loadWordDisp(cUnit, mReg, Method::DexCacheResolvedTypesOffset().Int32Value(),
resReg);
loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
(sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
@@ -595,35 +595,52 @@
static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
RegLocation rlSrc)
{
- // May generate a call - use explicit registers
- RegLocation rlResult;
- Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
- GetResolvedType(mir->dalvikInsn.vC);
+ // May generate a call - use explicit registers
+ oatLockCallTemps(cUnit);
+ art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
+ Get(mir->dalvikInsn.vC);
+ int classReg = r2; // Fixed usage
+ loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
+ loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
+ classReg);
+ loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
+ (sizeof(String*) * mir->dalvikInsn.vC), classReg);
if (classPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Handle null class pointer";
+ // Generate a runtime test
+ ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
+ // Not resolved
+ // Call out to helper, which will return resolved type in r0
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
+ loadConstant(cUnit, r0, mir->dalvikInsn.vC);
+ opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+ genRegCopy(cUnit, r2, r0); // Align usage with fast path
+ // Rejoin code paths
+ ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+ hopTarget->defMask = ENCODE_ALL;
+ hopBranch->generic.target = (LIR*)hopTarget;
}
- oatFlushAllRegs(cUnit); /* Everything to home location */
- loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
- loadConstant(cUnit, r2, (int) classPtr );
+ // At this point, r2 has class
+ loadValueDirectFixed(cUnit, rlSrc, r3); /* Ref */
/* When taken r0 has NULL which can be used for store directly */
- ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
- /* r1 now contains object->clazz */
+ ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r3, 0);
+ /* load object->clazz */
assert(Object::ClassOffset().Int32Value() == 0);
- loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
+ loadWordDisp(cUnit, r3, Object::ClassOffset().Int32Value(), r1);
/* r1 now contains object->clazz */
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
loadConstant(cUnit, r0, 1); /* Assume true */
opRegReg(cUnit, kOpCmp, r1, r2);
ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
- genRegCopy(cUnit, r0, r1);
+ genRegCopy(cUnit, r0, r3);
genRegCopy(cUnit, r1, r2);
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);
/* branch target here */
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
- rlResult = oatGetReturn(cUnit);
+ RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
branch1->generic.target = (LIR*)target;
branch2->generic.target = (LIR*)target;
@@ -631,32 +648,48 @@
static void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
{
- Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
- GetResolvedType(mir->dalvikInsn.vB);
+ // May generate a call - use explicit registers
+ oatLockCallTemps(cUnit);
+ art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
+ Get(mir->dalvikInsn.vB);
+ int classReg = r2; // Fixed usage
+ loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
+ loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
+ classReg);
+ loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
+ (sizeof(String*) * mir->dalvikInsn.vB), classReg);
if (classPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Unimplemented null class pointer";
+ // Generate a runtime test
+ ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
+ // Not resolved
+ // Call out to helper, which will return resolved type in r0
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
+ loadConstant(cUnit, r0, mir->dalvikInsn.vB);
+ opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+ genRegCopy(cUnit, r2, r0); // Align usage with fast path
+ // Rejoin code paths
+ ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+ hopTarget->defMask = ENCODE_ALL;
+ hopBranch->generic.target = (LIR*)hopTarget;
}
- oatFlushAllRegs(cUnit); /* Everything to home location */
- loadConstant(cUnit, r1, (int) classPtr );
- rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
- /* Null? */
- ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq,
- rlSrc.lowReg, 0);
- /*
- * rlSrc.lowReg now contains object->clazz. Note that
- * it could have been allocated r0, but we're okay so long
- * as we don't do anything desctructive until r0 is loaded
- * with clazz.
- */
- /* r0 now contains object->clazz */
- loadWordDisp(cUnit, rlSrc.lowReg, Object::ClassOffset().Int32Value(), r0);
+ // At this point, r2 has class
+ loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
+ /* Null is OK - continue */
+ ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
+ /* load object->clazz */
+ assert(Object::ClassOffset().Int32Value() == 0);
+ loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
+ /* r1 now contains object->clazz */
loadWordDisp(cUnit, rSELF,
- OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
- opRegReg(cUnit, kOpCmp, r0, r1);
- ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
- // Assume success - if not, artInstanceOfNonTrivial will handle throw
+ OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
+ opRegReg(cUnit, kOpCmp, r1, r2);
+ ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
+ genRegCopy(cUnit, r0, r1);
+ genRegCopy(cUnit, r1, r2);
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);
+ /* branch target here */
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
branch1->generic.target = (LIR*)target;