Clean up instanceof codegen in compiler.
Change-Id: I0179a0746bc5aaef02129169b6a6b1bbbe30dc7e
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index d81c200..173aa64 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -683,6 +683,7 @@
Get(mir->dalvikInsn.vC);
int classReg = r2; // Fixed usage
loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
+ loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
classReg);
loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
@@ -697,35 +698,34 @@
loadConstant(cUnit, r0, mir->dalvikInsn.vC);
callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
genRegCopy(cUnit, r2, r0); // Align usage with fast path
+ loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
// Rejoin code paths
ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
hopTarget->defMask = ENCODE_ALL;
hopBranch->generic.target = (LIR*)hopTarget;
}
- // At this point, r2 has class
- loadValueDirectFixed(cUnit, rlSrc, r3); /* Ref */
- /* When taken r0 has NULL which can be used for store directly */
- loadConstant(cUnit, r0, 0); /* Assume false */
- ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r3, 0);
+ /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
+ ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
/* load object->clazz */
DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
- loadWordDisp(cUnit, r3, Object::ClassOffset().Int32Value(), r1);
- /* r1 now contains object->clazz */
+ loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
+ /* r0 is ref, r1 is ref->clazz, r2 is class */
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, r3);
- genRegCopy(cUnit, r1, r2);
- callRuntimeHelper(cUnit, rLR);
+ opRegReg(cUnit, kOpCmp, r1, r2); // Same?
+ genBarrier(cUnit);
+ genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
+ loadConstant(cUnit, r0, 1); // .eq case - load true
+ genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
+ opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
+ genBarrier(cUnit);
+ oatClobberCalleeSave(cUnit);
/* branch target here */
ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
RegLocation rlResult = oatGetReturn(cUnit);
storeValue(cUnit, rlDest, rlResult);
branch1->generic.target = (LIR*)target;
- branch2->generic.target = (LIR*)target;
}
STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
diff --git a/src/object.h b/src/object.h
index 1eee2b8..51d7b84 100644
--- a/src/object.h
+++ b/src/object.h
@@ -191,11 +191,6 @@
// C++ mirror of java.lang.Object
class MANAGED Object {
public:
- static uint32_t InstanceOfFromCode(const Object* object, const Class* klass) {
- DCHECK(object != NULL);
- return object->InstanceOf(klass) ? 1 : 0;
- }
-
static MemberOffset ClassOffset() {
return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
}
@@ -1551,6 +1546,14 @@
}
}
+ // Assignable test for code, won't throw. Null and equality tests already performed
+ static uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class)
+ {
+ DCHECK(klass != NULL);
+ DCHECK(ref_class != NULL);
+ return klass->IsAssignableFrom(ref_class) ? 1 : 0;
+ }
+
Class* GetSuperClass() const {
// Can only get super class for loaded classes (hack for when runtime is
// initializing)
diff --git a/src/object_test.cc b/src/object_test.cc
index 79688a3..1451929 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -333,10 +333,10 @@
ASSERT_TRUE(x != NULL);
ASSERT_TRUE(y != NULL);
- EXPECT_EQ(1U, Object::InstanceOfFromCode(x, X));
- EXPECT_EQ(0U, Object::InstanceOfFromCode(x, Y));
- EXPECT_EQ(1U, Object::InstanceOfFromCode(y, X));
- EXPECT_EQ(1U, Object::InstanceOfFromCode(y, Y));
+ EXPECT_EQ(1U, Class::IsAssignableFromCode(X, x->GetClass()));
+ EXPECT_EQ(0U, Class::IsAssignableFromCode(Y, x->GetClass()));
+ EXPECT_EQ(1U, Class::IsAssignableFromCode(X, y->GetClass()));
+ EXPECT_EQ(1U, Class::IsAssignableFromCode(Y, y->GetClass()));
EXPECT_TRUE(x->InstanceOf(X));
EXPECT_FALSE(x->InstanceOf(Y));
diff --git a/src/thread.cc b/src/thread.cc
index 1bbe81c..0df4929 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -118,7 +118,7 @@
pSetObjStatic = Field::SetObjStaticFromCode;
pInitializeTypeFromCode = InitializeTypeFromCode;
pResolveMethodFromCode = ResolveMethodFromCode;
- pInstanceofNonTrivialFromCode = Object::InstanceOfFromCode;
+ pInstanceofNonTrivialFromCode = Class::IsAssignableFromCode;
pLockObjectFromCode = LockObjectFromCode;
pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
pCheckSuspendFromCode = artCheckSuspendFromCode;
diff --git a/src/thread.h b/src/thread.h
index 3a8abba..e9491dd 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -212,7 +212,7 @@
Object* (*pGetObjStatic)(uint32_t, const Method*);
void (*pSetObjStatic)(uint32_t, const Method*, Object*);
void (*pCanPutArrayElementFromCode)(void*, void*);
- uint32_t (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
+ uint32_t (*pInstanceofNonTrivialFromCode) (const Class*, const Class*);
void (*pCheckCastFromCode) (void*, void*);
Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
void (*pUnlockObjectFromCode)(void*, void*);