Adding Object::InstanceOf and Class::IsAssignableFrom
Summary:
- Add Object::InstanceOf and Class::IsAssignableFrom
- Fix Cloneable and Serializable interfaces on arrays to be == with FindSystemClass results
- Changed Object::Alloc(Class*) to be Class->NewInstance()
Details:
Add Object::InstanceOf and Class::IsAssignableFrom
object.h
common_test.h
object_test.cc
Fix bug where Cloneable and Serializable where created with AllocClass
and never inserted in the classes table with FindSystemClass by just
creating them directly with FindSystemClass
class_linker.cc
object_test.cc
Changed Object::Alloc(Class*) to be Class->NewInstance()
class_linker.cc
object.h
Change-Id: I528767fff43aff32c8dc4f7a2d4157598a7dbb89
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 46562ca..925a3b3 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -132,13 +132,10 @@
// Setup a single, global copy of "interfaces" and "iftable" for
// reuse across array classes
- Class* java_lang_Cloneable = AllocClass();
+ Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;");
CHECK(java_lang_Cloneable != NULL);
- java_lang_Cloneable->descriptor_ = "Ljava/lang/Cloneable;";
-
- Class* java_io_Serializable = AllocClass();
+ Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;");
CHECK(java_io_Serializable != NULL);
- java_io_Serializable->descriptor_ = "Ljava/io/Serializable;";
array_interfaces_ = AllocObjectArray<Class>(2);
CHECK(array_interfaces_ != NULL);
@@ -157,6 +154,8 @@
// run Object[] through FindClass to complete initialization
Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;");
CHECK_EQ(object_array_class, found_object_array_class);
+ CHECK_EQ(java_lang_Cloneable, object_array_class->GetInterface(0));
+ CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
// Setup the primitive type classes.
class_roots_->Set(kPrimitiveByte, CreatePrimitiveClass("B"));
@@ -209,7 +208,7 @@
}
Class* ClassLinker::AllocClass(Class* java_lang_Class) {
- return down_cast<Class*>(Object::Alloc(java_lang_Class));
+ return down_cast<Class*>(java_lang_Class->NewInstance());
}
Class* ClassLinker::AllocClass() {
@@ -217,20 +216,20 @@
}
StaticField* ClassLinker::AllocStaticField() {
- return down_cast<StaticField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
+ return down_cast<StaticField*>(GetClassRoot(kJavaLangReflectField)->NewInstance());
}
InstanceField* ClassLinker::AllocInstanceField() {
- return down_cast<InstanceField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
+ return down_cast<InstanceField*>(GetClassRoot(kJavaLangReflectField)->NewInstance());
}
Method* ClassLinker::AllocMethod() {
- return down_cast<Method*>(Object::Alloc(GetClassRoot(kJavaLangReflectMethod)));
+ return down_cast<Method*>(GetClassRoot(kJavaLangReflectMethod)->NewInstance());
}
// TODO remove once we can use java.lang.Class.getSystemClassLoader
PathClassLoader* ClassLinker::AllocPathClassLoader(std::vector<const DexFile*> dex_files) {
- PathClassLoader* cl = down_cast<PathClassLoader*>(Object::Alloc(GetClassRoot(kDalvikSystemPathClassLoader)));
+ PathClassLoader* cl = down_cast<PathClassLoader*>(GetClassRoot(kDalvikSystemPathClassLoader)->NewInstance());
cl->SetClassPath(dex_files);
return cl;
}
@@ -776,8 +775,7 @@
if (!DexVerify::VerifyClass(klass)) {
LG << "Verification failed"; // TODO: ThrowVerifyError
Object* exception = self->GetException();
- size_t field_offset = OFFSETOF_MEMBER(Class, verify_error_class_);
- klass->SetFieldObject(field_offset, exception->GetClass());
+ klass->SetVerifyErrorClass(exception->GetClass());
klass->SetStatus(Class::kStatusError);
return false;
}
diff --git a/src/common_test.h b/src/common_test.h
index 13f92d1..2555005 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -221,6 +221,20 @@
"AAMAAAADAAAA2AAAAAUAAAAEAAAA/AAAAAYAAAABAAAAHAEAAAEgAAADAAAAPAEAAAEQAAACAAAA"
"fAEAAAIgAAAQAAAAlAEAAAMgAAADAAAAJAIAAAAgAAABAAAAOgIAAAAQAAABAAAATAIAAA==";
+// class X {}
+// class Y extends X {}
+static const char kXandY[] =
+ "ZGV4CjAzNQAlLMqyB72TxJW4zl5w75F072u4Ig6KvCMEAgAAcAAAAHhWNBIAAAAAAAAAAHwBAAAG"
+ "AAAAcAAAAAQAAACIAAAAAQAAAJgAAAAAAAAAAAAAAAMAAACkAAAAAgAAALwAAAAIAQAA/AAAACwB"
+ "AAA0AQAAOQEAAD4BAABSAQAAVQEAAAEAAAACAAAAAwAAAAQAAAAEAAAAAwAAAAAAAAAAAAAAAAAA"
+ "AAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAABQAAAAAAAABnAQAAAAAAAAEAAAAAAAAA"
+ "AAAAAAAAAAAFAAAAAAAAAHEBAAAAAAAAAQABAAEAAABdAQAABAAAAHAQAgAAAA4AAQABAAEAAABi"
+ "AQAABAAAAHAQAAAAAA4ABjxpbml0PgADTFg7AANMWTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgAG"
+ "WC5qYXZhAAIABw4AAwAHDgAAAAEAAICABPwBAAABAAGAgASUAgALAAAAAAAAAAEAAAAAAAAAAQAA"
+ "AAYAAABwAAAAAgAAAAQAAACIAAAAAwAAAAEAAACYAAAABQAAAAMAAACkAAAABgAAAAIAAAC8AAAA"
+ "ASAAAAIAAAD8AAAAAiAAAAYAAAAsAQAAAyAAAAIAAABdAQAAACAAAAIAAABnAQAAABAAAAEAAAB8"
+ "AQAA";
+
static inline DexFile* OpenDexFileBase64(const char* base64) {
CHECK(base64 != NULL);
size_t length;
diff --git a/src/object.cc b/src/object.cc
index 2369954..514eef5 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -13,6 +13,100 @@
namespace art {
+bool Class::Implements(const Class* klass) const {
+ DCHECK(klass != NULL);
+ DCHECK(klass->IsInterface());
+ // All interfaces implemented directly and by our superclass, and
+ // recursively all super-interfaces of those interfaces, are listed
+ // in iftable_, so we can just do a linear scan through that.
+ for (size_t i = 0; i < iftable_count_; i++) {
+ if (iftable_[i].GetClass() == klass) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Determine whether "this" is assignable from "klazz", where both of these
+// are array classes.
+//
+// Consider an array class, e.g. Y[][], where Y is a subclass of X.
+// Y[][] = Y[][] --> true (identity)
+// X[][] = Y[][] --> true (element superclass)
+// Y = Y[][] --> false
+// Y[] = Y[][] --> false
+// Object = Y[][] --> true (everything is an object)
+// Object[] = Y[][] --> true
+// Object[][] = Y[][] --> true
+// Object[][][] = Y[][] --> false (too many []s)
+// Serializable = Y[][] --> true (all arrays are Serializable)
+// Serializable[] = Y[][] --> true
+// Serializable[][] = Y[][] --> false (unless Y is Serializable)
+//
+// Don't forget about primitive types.
+// int[] instanceof Object[] --> false
+//
+bool Class::IsArrayAssignableFromArray(const Class* klass) const {
+ DCHECK(IsArray());
+ DCHECK(klass->IsArray());
+ DCHECK_GT(array_rank_, 0);
+ DCHECK_GT(klass->array_rank_, 0);
+ DCHECK(component_type_ != NULL);
+ DCHECK(klass->component_type_ != NULL);
+ if (array_rank_ > klass->array_rank_) {
+ // Too many []s.
+ return false;
+ }
+ if (array_rank_ == klass->array_rank_) {
+ return component_type_->IsAssignableFrom(klass->component_type_);
+ }
+ DCHECK_LT(array_rank_, klass->array_rank_);
+ // The thing we might be assignable from has more dimensions. We
+ // must be an Object or array of Object, or a standard array
+ // interface or array of standard array interfaces (the standard
+ // interfaces being java/lang/Cloneable and java/io/Serializable).
+ if (component_type_->IsInterface()) {
+ // See if we implement our component type. We know the
+ // base element is an interface; if the array class implements
+ // it, we know it's a standard array interface.
+ return Implements(component_type_);
+ }
+ // See if this is an array of Object, Object[], etc. We know
+ // that the superclass of an array is always Object, so we
+ // just compare the element type to that.
+ Class* java_lang_Object = GetSuperClass();
+ DCHECK(java_lang_Object != NULL);
+ DCHECK(java_lang_Object->GetSuperClass() == NULL);
+ return (component_type_ == java_lang_Object);
+}
+
+bool Class::IsAssignableFromArray(const Class* klass) const {
+ DCHECK(!IsInterface()); // handled first in IsAssignableFrom
+ DCHECK(klass->IsArray());
+ if (!IsArray()) {
+ // If "this" is not also an array, it must be Object.
+ // klass's super should be java_lang_Object, since it is an array.
+ Class* java_lang_Object = klass->GetSuperClass();
+ DCHECK(java_lang_Object != NULL);
+ DCHECK(java_lang_Object->GetSuperClass() == NULL);
+ return this == java_lang_Object;
+ }
+ return IsArrayAssignableFromArray(klass);
+}
+
+bool Class::IsSubClass(const Class* klass) const {
+ DCHECK(!IsInterface());
+ DCHECK(!klass->IsArray());
+ const Class* current = this;
+ do {
+ if (current == klass) {
+ return true;
+ }
+ current = current->GetSuperClass();
+ } while (current != NULL);
+ return false;
+}
+
bool Class::IsInSamePackage(const StringPiece& descriptor1,
const StringPiece& descriptor2) {
size_t i = 0;
diff --git a/src/object.h b/src/object.h
index 5e6c175..c1682ec 100644
--- a/src/object.h
+++ b/src/object.h
@@ -110,12 +110,19 @@
class Object {
public:
- static Object* Alloc(Class* klass);
+ static bool InstanceOf(const Object* object, const Class* klass) {
+ if (object == NULL) {
+ return false;
+ }
+ return object->InstanceOf(klass);
+ }
Class* GetClass() const {
return klass_;
}
+ bool InstanceOf(const Class* klass) const;
+
void MonitorEnter() {
monitor_->Enter();
}
@@ -739,6 +746,10 @@
kPrimNot = -1
};
+ Object* NewInstance() {
+ return Heap::AllocObject(this, this->object_size_);
+ }
+
Class* GetSuperClass() const {
return super_class_;
}
@@ -751,6 +762,20 @@
return super_class_ != NULL;
}
+ bool IsAssignableFrom(const Class* klass) const {
+ DCHECK(klass != NULL);
+ if (this == klass) {
+ return true;
+ }
+ if (IsInterface()) {
+ return klass->Implements(this);
+ }
+ if (klass->IsArray()) {
+ return IsAssignableFromArray(klass);
+ }
+ return klass->IsSubClass(this);
+ }
+
ClassLoader* GetClassLoader() const {
return class_loader_;
}
@@ -898,7 +923,7 @@
return num_reference_instance_fields_;
}
- InstanceField* GetInstanceField(uint32_t i) { // TODO: uint16_t
+ InstanceField* GetInstanceField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
return ifields_->Get(i);
}
@@ -944,6 +969,18 @@
interfaces_->Set(i, f);
}
+ void SetVerifyErrorClass(Class* klass) {
+ // Note SetFieldObject is used rather than verify_error_class_ directly for the barrier
+ size_t field_offset = OFFSETOF_MEMBER(Class, verify_error_class_);
+ klass->SetFieldObject(field_offset, klass);
+ }
+
+ private:
+ bool Implements(const Class* klass) const;
+ bool IsArrayAssignableFromArray(const Class* klass) const;
+ bool IsAssignableFromArray(const Class* klass) const;
+ bool IsSubClass(const Class* klass) const;
+
public: // TODO: private
// leave space for instance data; we could access fields directly if
// we freeze the definition of java/lang/Class
@@ -970,8 +1007,9 @@
// state of class initialization
Status status_;
- // if class verify fails, we must return same error on subsequent tries
- Class* verify_error_class_;
+ // If class verify fails, we must return same error on subsequent tries.
+ // Update with SetVerifyErrorClass to ensure a write barrier is used.
+ const Class* verify_error_class_;
// threadId, used to check for recursive <clinit> invocation
uint32_t clinit_thread_id_;
@@ -1075,11 +1113,13 @@
};
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
-inline Object* Object::Alloc(Class* klass) {
+inline bool Object::InstanceOf(const Class* klass) const {
DCHECK(klass != NULL);
- return Heap::AllocObject(klass, klass->object_size_);
+ DCHECK(klass_ != NULL);
+ return klass->IsAssignableFrom(klass_);
}
+
class DataObject : public Object {
public:
uint32_t fields_[0];
@@ -1190,7 +1230,7 @@
static String* Alloc(Class* java_lang_String,
Class* char_array,
int32_t utf16_length) {
- String* string = down_cast<String*>(Object::Alloc(java_lang_String));
+ String* string = down_cast<String*>(java_lang_String->NewInstance());
CharArray* array = CharArray::Alloc(char_array, utf16_length);
string->array_ = array;
string->count_ = utf16_length;
diff --git a/src/object_test.cc b/src/object_test.cc
index cf59776..7167732 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -55,16 +55,23 @@
}
TEST_F(ObjectTest, AllocObjectArray) {
- ObjectArray<Object>* oa = class_linker_->AllocObjectArray<Object>(2);
- EXPECT_EQ(2U, oa->GetLength());
- EXPECT_TRUE(oa->Get(0) == NULL);
- EXPECT_TRUE(oa->Get(1) == NULL);
- oa->Set(0, oa);
- EXPECT_TRUE(oa->Get(0) == oa);
- EXPECT_TRUE(oa->Get(1) == NULL);
- oa->Set(1, oa);
- EXPECT_TRUE(oa->Get(0) == oa);
- EXPECT_TRUE(oa->Get(1) == oa);
+ ObjectArray<Object>* oa = class_linker_->AllocObjectArray<Object>(2);
+ EXPECT_EQ(2U, oa->GetLength());
+ EXPECT_TRUE(oa->Get(0) == NULL);
+ EXPECT_TRUE(oa->Get(1) == NULL);
+ oa->Set(0, oa);
+ EXPECT_TRUE(oa->Get(0) == oa);
+ EXPECT_TRUE(oa->Get(1) == NULL);
+ oa->Set(1, oa);
+ EXPECT_TRUE(oa->Get(0) == oa);
+ EXPECT_TRUE(oa->Get(1) == oa);
+
+ ASSERT_TRUE(oa->GetClass() != NULL);
+ ASSERT_EQ(2U, oa->GetClass()->NumInterfaces());
+ EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Cloneable;"),
+ oa->GetClass()->GetInterface(0));
+ EXPECT_EQ(class_linker_->FindSystemClass("Ljava/io/Serializable;"),
+ oa->GetClass()->GetInterface(1));
}
TEST_F(ObjectTest, String) {
@@ -169,4 +176,95 @@
EXPECT_EQ(64578U, String::AllocFromAscii("ABC")->GetHashCode());
}
+TEST_F(ObjectTest, InstanceOf) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ Class* X = class_linker_->FindClass("LX;", class_loader);
+ Class* Y = class_linker_->FindClass("LY;", class_loader);
+ ASSERT_TRUE(X != NULL);
+ ASSERT_TRUE(Y != NULL);
+
+ EXPECT_FALSE(Object::InstanceOf(NULL, X));
+ EXPECT_FALSE(Object::InstanceOf(NULL, Y));
+
+ Object* x = X->NewInstance();
+ Object* y = Y->NewInstance();
+ ASSERT_TRUE(x != NULL);
+ ASSERT_TRUE(y != NULL);
+
+ EXPECT_TRUE(Object::InstanceOf(x, X));
+ EXPECT_FALSE(Object::InstanceOf(x, Y));
+ EXPECT_TRUE(Object::InstanceOf(y, X));
+ EXPECT_TRUE(Object::InstanceOf(y, Y));
+
+ EXPECT_TRUE(x->InstanceOf(X));
+ EXPECT_FALSE(x->InstanceOf(Y));
+ EXPECT_TRUE(y->InstanceOf(X));
+ EXPECT_TRUE(y->InstanceOf(Y));
+}
+
+TEST_F(ObjectTest, IsAssignableFrom) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ Class* X = class_linker_->FindClass("LX;", class_loader);
+ Class* Y = class_linker_->FindClass("LY;", class_loader);
+
+ EXPECT_TRUE(X->IsAssignableFrom(X));
+ EXPECT_TRUE(X->IsAssignableFrom(Y));
+ EXPECT_FALSE(Y->IsAssignableFrom(X));
+ EXPECT_TRUE(Y->IsAssignableFrom(Y));
+}
+
+TEST_F(ObjectTest, IsAssignableFromArray) {
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ Class* X = class_linker_->FindClass("LX;", class_loader);
+ Class* Y = class_linker_->FindClass("LY;", class_loader);
+ ASSERT_TRUE(X != NULL);
+ ASSERT_TRUE(Y != NULL);
+
+ Class* YA = class_linker_->FindClass("[LY;", class_loader);
+ Class* YAA = class_linker_->FindClass("[[LY;", class_loader);
+ ASSERT_TRUE(YA != NULL);
+ ASSERT_TRUE(YAA != NULL);
+
+ Class* XAA = class_linker_->FindClass("[[LX;", class_loader);
+ ASSERT_TRUE(XAA != NULL);
+
+ Class* O = class_linker_->FindSystemClass("Ljava/lang/Object;");
+ Class* OA = class_linker_->FindSystemClass("[Ljava/lang/Object;");
+ Class* OAA = class_linker_->FindSystemClass("[[Ljava/lang/Object;");
+ Class* OAAA = class_linker_->FindSystemClass("[[[Ljava/lang/Object;");
+ ASSERT_TRUE(O != NULL);
+ ASSERT_TRUE(OA != NULL);
+ ASSERT_TRUE(OAA != NULL);
+ ASSERT_TRUE(OAAA != NULL);
+
+ Class* S = class_linker_->FindSystemClass("Ljava/io/Serializable;");
+ Class* SA = class_linker_->FindSystemClass("[Ljava/io/Serializable;");
+ Class* SAA = class_linker_->FindSystemClass("[[Ljava/io/Serializable;");
+ ASSERT_TRUE(S != NULL);
+ ASSERT_TRUE(SA != NULL);
+ ASSERT_TRUE(SAA != NULL);
+
+ Class* IA = class_linker_->FindSystemClass("[I");
+ ASSERT_TRUE(IA != NULL);
+
+ EXPECT_TRUE(YAA->IsAssignableFrom(YAA)); // identity
+ EXPECT_TRUE(XAA->IsAssignableFrom(YAA)); // element superclass
+ EXPECT_FALSE(YAA->IsAssignableFrom(XAA));
+ EXPECT_FALSE(Y->IsAssignableFrom(YAA));
+ EXPECT_FALSE(YA->IsAssignableFrom(YAA));
+ EXPECT_TRUE(O->IsAssignableFrom(YAA)); // everything is an Object
+ EXPECT_TRUE(OA->IsAssignableFrom(YAA));
+ EXPECT_TRUE(OAA->IsAssignableFrom(YAA));
+ EXPECT_TRUE(S->IsAssignableFrom(YAA)); // all arrays are Serializable
+ EXPECT_TRUE(SA->IsAssignableFrom(YAA));
+ EXPECT_FALSE(SAA->IsAssignableFrom(YAA)); // unless Y was Serializable
+
+ EXPECT_FALSE(IA->IsAssignableFrom(OA));
+ EXPECT_FALSE(OA->IsAssignableFrom(IA));
+ EXPECT_TRUE(O->IsAssignableFrom(IA));
+}
+
} // namespace art