summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2011-09-18 01:38:59 -0700
committerBrian Carlstrom <bdc@google.com>2011-09-18 01:56:40 -0700
commit5b8e4c810a97c9dc417142b8c6e07871ae15c797 (patch)
tree1a28a30bfca5e29d2abb33ad8fa27e66ab9beae9
parent3a7b4f26387b3529899f3cf16cdd6f1e200ded80 (diff)
downloadart-5b8e4c810a97c9dc417142b8c6e07871ae15c797.zip
art-5b8e4c810a97c9dc417142b8c6e07871ae15c797.tar.gz
art-5b8e4c810a97c9dc417142b8c6e07871ae15c797.tar.bz2
Change Class::component_type_ and implement reflect.Array
Change-Id: I9e06f31577551c738eca2621146c8d2328119442
-rw-r--r--build/Android.common.mk1
-rw-r--r--src/class_linker.cc79
-rw-r--r--src/class_linker.h8
-rw-r--r--src/class_linker_test.cc235
-rw-r--r--src/dex_file.cc2
-rw-r--r--src/dex_verifier.cc259
-rw-r--r--src/java_lang_Class.cc19
-rw-r--r--src/java_lang_System.cc6
-rw-r--r--src/java_lang_reflect_Array.cc160
-rw-r--r--src/jni_internal_test.cc2
-rw-r--r--src/object.cc41
-rw-r--r--src/object.h45
-rw-r--r--src/object_test.cc5
-rw-r--r--src/runtime.cc2
14 files changed, 445 insertions, 419 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk
index ae96dab..94c7b15 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -106,6 +106,7 @@ LIBART_COMMON_SRC_FILES := \
src/java_lang_System.cc \
src/java_lang_Thread.cc \
src/java_lang_Throwable.cc \
+ src/java_lang_reflect_Array.cc \
src/java_lang_reflect_Field.cc \
src/java_lang_reflect_Method.cc \
src/java_util_concurrent_atomic_AtomicLong.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e3b4eea..0f02d09 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -129,12 +129,14 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
// Object[] next to hold class roots
Class* object_array_class = AllocClass(java_lang_Class, sizeof(Class));
- object_array_class->SetArrayRank(1);
object_array_class->SetComponentType(java_lang_Object);
+ // Setup the char class to be used for char[]
+ Class* char_class = AllocClass(java_lang_Class, sizeof(Class));
+
// Setup the char[] class to be used for String
Class* char_array_class = AllocClass(java_lang_Class, sizeof(Class));
- char_array_class->SetArrayRank(1);
+ char_array_class->SetComponentType(char_class);
CharArray::SetArrayClass(char_array_class);
// Setup String
@@ -162,7 +164,6 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
// Setup the primitive type classes.
SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z", Class::kPrimBoolean));
SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B", Class::kPrimByte));
- SetClassRoot(kPrimitiveChar, CreatePrimitiveClass("C", Class::kPrimChar));
SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S", Class::kPrimShort));
SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I", Class::kPrimInt));
SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J", Class::kPrimLong));
@@ -170,16 +171,12 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D", Class::kPrimDouble));
SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Class::kPrimVoid));
- // Backfill component type of char[]
- char_array_class->SetComponentType(GetClassRoot(kPrimitiveChar));
-
// Create array interface entries to populate once we can load system classes
array_interfaces_ = AllocObjectArray<Class>(2);
array_iftable_ = AllocObjectArray<InterfaceEntry>(2);
// Create int array type for AllocDexCache (done in AppendToBootClassPath)
Class* int_array_class = AllocClass(java_lang_Class, sizeof(Class));
- int_array_class->SetArrayRank(1);
int_array_class->SetDescriptor(intern_table_->InternStrong("[I"));
int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
IntArray::SetArrayClass(int_array_class);
@@ -220,6 +217,10 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
// now we can use FindSystemClass
+ // run char class through InitializePrimitiveClass to finish init
+ InitializePrimitiveClass(char_class, "C", Class::kPrimChar);
+ SetClassRoot(kPrimitiveChar, char_class); // needs descriptor
+
// Object and String need to be rerun through FindSystemClass to finish init
java_lang_Object->SetStatus(Class::kStatusNotReady);
Class* Object_class = FindSystemClass("Ljava/lang/Object;");
@@ -614,7 +615,7 @@ Class* ClassLinker::FindClass(const StringPiece& descriptor,
Class* klass = LookupClass(descriptor, class_loader);
if (klass == NULL) {
// Class is not yet loaded.
- if (descriptor[0] == '[') {
+ if (descriptor[0] == '[' && descriptor[1] != '\0') {
return CreateArrayClass(descriptor, class_loader);
}
const DexFile::ClassPath& class_path = ((class_loader != NULL)
@@ -979,18 +980,18 @@ DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
return NULL;
}
-Class* ClassLinker::CreatePrimitiveClass(const char* descriptor,
- Class::PrimitiveType type) {
+Class* ClassLinker::InitializePrimitiveClass(Class* primitive_class,
+ const char* descriptor,
+ Class::PrimitiveType type) {
// TODO: deduce one argument from the other
- Class* klass = AllocClass(sizeof(Class));
- CHECK(klass != NULL);
- klass->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
- klass->SetDescriptor(intern_table_->InternStrong(descriptor));
- klass->SetPrimitiveType(type);
- klass->SetStatus(Class::kStatusInitialized);
- bool success = InsertClass(descriptor, klass);
- CHECK(success) << "CreatePrimitiveClass(" << descriptor << ") failed";
- return klass;
+ CHECK(primitive_class != NULL);
+ primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
+ primitive_class->SetDescriptor(intern_table_->InternStrong(descriptor));
+ primitive_class->SetPrimitiveType(type);
+ primitive_class->SetStatus(Class::kStatusInitialized);
+ bool success = InsertClass(descriptor, primitive_class);
+ CHECK(success) << "InitPrimitiveClass(" << descriptor << ") failed";
+ return primitive_class;
}
// Create an array class (i.e. the class object for the array, not the
@@ -1000,44 +1001,20 @@ Class* ClassLinker::CreatePrimitiveClass(const char* descriptor,
// If "descriptor" refers to an array of primitives, look up the
// primitive type's internally-generated class object.
//
-// "loader" is the class loader of the class that's referring to us. It's
-// used to ensure that we're looking for the element type in the right
-// context. It does NOT become the class loader for the array class; that
-// always comes from the base element class.
+// "class_loader" is the class loader of the class that's referring to
+// us. It's used to ensure that we're looking for the element type in
+// the right context. It does NOT become the class loader for the
+// array class; that always comes from the base element class.
//
// Returns NULL with an exception raised on failure.
Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
const ClassLoader* class_loader) {
CHECK_EQ('[', descriptor[0]);
- // Identify the underlying element class and the array dimension depth.
- Class* component_type = NULL;
- int array_rank;
- if (descriptor[1] == '[') {
- // array of arrays; keep descriptor and grab stuff from parent
- Class* outer = FindClass(descriptor.substr(1), class_loader);
- if (outer != NULL) {
- // want the base class, not "outer", in our component_type
- component_type = outer->GetComponentType();
- array_rank = outer->GetArrayRank() + 1;
- } else {
- DCHECK(component_type == NULL); // make sure we fail
- }
- } else {
- array_rank = 1;
- if (descriptor[1] == 'L') {
- // array of objects; strip off "[" and look up descriptor.
- const StringPiece subDescriptor = descriptor.substr(1);
- component_type = FindClass(subDescriptor, class_loader);
- } else {
- // array of a primitive type
- component_type = FindPrimitiveClass(descriptor[1]);
- }
- }
-
+ // Identify the underlying component type
+ Class* component_type = FindClass(descriptor.substr(1), class_loader);
if (component_type == NULL) {
- // failed
- // DCHECK(Thread::Current()->IsExceptionPending()); // TODO
+ DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
}
@@ -1090,10 +1067,8 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
if (new_class == NULL) {
return NULL;
}
- new_class->SetArrayRank(array_rank);
new_class->SetComponentType(component_type);
}
- DCHECK_LE(1, new_class->GetArrayRank());
DCHECK(new_class->GetComponentType() != NULL);
if (new_class->GetDescriptor() != NULL) {
DCHECK(new_class->GetDescriptor()->Equals(descriptor));
diff --git a/src/class_linker.h b/src/class_linker.h
index 53291b5..02e6d6f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -193,7 +193,13 @@ class ClassLinker {
InterfaceEntry* AllocInterfaceEntry(Class* interface);
Class* CreatePrimitiveClass(const char* descriptor,
- Class::PrimitiveType type);
+ Class::PrimitiveType type) {
+ return InitializePrimitiveClass(AllocClass(sizeof(Class)), descriptor, type);
+ }
+ Class* InitializePrimitiveClass(Class* primitive_class,
+ const char* descriptor,
+ Class::PrimitiveType type);
+
Class* CreateArrayClass(const StringPiece& descriptor,
const ClassLoader* class_loader);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 32f2eec..5e605c4 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -43,7 +43,7 @@ class ClassLinkerTest : public CommonTest {
EXPECT_TRUE(primitive->IsResolved());
EXPECT_FALSE(primitive->IsArrayInstance());
EXPECT_FALSE(primitive->IsArrayClass());
- EXPECT_EQ(0, primitive->GetArrayRank());
+ EXPECT_TRUE(primitive->GetComponentType() == NULL);
EXPECT_FALSE(primitive->IsInterface());
EXPECT_TRUE(primitive->IsPublic());
EXPECT_TRUE(primitive->IsFinal());
@@ -60,11 +60,9 @@ class ClassLinkerTest : public CommonTest {
}
void AssertArrayClass(const StringPiece& array_descriptor,
- int32_t array_rank,
const StringPiece& component_type,
const ClassLoader* class_loader) {
Class* array = class_linker_->FindClass(array_descriptor, class_loader);
- EXPECT_EQ(array_rank, array->GetArrayRank());
EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
EXPECT_EQ(class_loader, array->GetClassLoader());
AssertArrayClass(array_descriptor, array);
@@ -87,7 +85,6 @@ class ClassLinkerTest : public CommonTest {
EXPECT_TRUE(array->IsResolved());
EXPECT_FALSE(array->IsArrayInstance());
EXPECT_TRUE(array->IsArrayClass());
- EXPECT_LE(1, array->GetArrayRank());
EXPECT_FALSE(array->IsInterface());
EXPECT_EQ(array->GetComponentType()->IsPublic(), array->IsPublic());
EXPECT_TRUE(array->IsFinal());
@@ -156,7 +153,7 @@ class ClassLinkerTest : public CommonTest {
EXPECT_TRUE(klass->IsResolved());
EXPECT_TRUE(klass->IsLoaded());
EXPECT_FALSE(klass->IsArrayClass());
- EXPECT_EQ(0, klass->GetArrayRank());
+ EXPECT_TRUE(klass->GetComponentType() == NULL);
EXPECT_TRUE(klass->IsInSamePackage(klass));
EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
if (klass->IsInterface()) {
@@ -292,113 +289,6 @@ class ClassLinkerTest : public CommonTest {
}
};
-TEST_F(ClassLinkerTest, FindClassNonexistent) {
- AssertNonExistentClass("NoSuchClass;");
- AssertNonExistentClass("LNoSuchClass;");
-}
-
-TEST_F(ClassLinkerTest, FindClassNested) {
- const ClassLoader* class_loader = LoadDex("Nested");
-
- Class* outer = class_linker_->FindClass("LNested;", class_loader);
- ASSERT_TRUE(outer != NULL);
- EXPECT_EQ(0U, outer->NumVirtualMethods());
- EXPECT_EQ(1U, outer->NumDirectMethods());
-
- Class* inner = class_linker_->FindClass("LNested$Inner;", class_loader);
- ASSERT_TRUE(inner != NULL);
- EXPECT_EQ(0U, inner->NumVirtualMethods());
- EXPECT_EQ(1U, inner->NumDirectMethods());
-}
-
-TEST_F(ClassLinkerTest, FindClass_Primitives) {
- StringPiece expected = "BCDFIJSZV";
- for (int ch = 0; ch < 255; ch++) {
- char* s = reinterpret_cast<char*>(&ch);
- StringPiece descriptor(s, 1);
- if (expected.find(ch) == StringPiece::npos) {
- AssertNonExistentClass(descriptor);
- } else {
- AssertPrimitiveClass(descriptor);
- }
- }
-}
-
-TEST_F(ClassLinkerTest, FindClass) {
- Class* JavaLangObject = class_linker_->FindSystemClass("Ljava/lang/Object;");
- ASSERT_TRUE(JavaLangObject != NULL);
- ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
- ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
- EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
- ASSERT_TRUE(JavaLangObject->GetDescriptor()->Equals("Ljava/lang/Object;"));
- EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
- EXPECT_FALSE(JavaLangObject->HasSuperClass());
- EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
- EXPECT_FALSE(JavaLangObject->IsErroneous());
- EXPECT_TRUE(JavaLangObject->IsVerified());
- EXPECT_TRUE(JavaLangObject->IsResolved());
- EXPECT_FALSE(JavaLangObject->IsArrayInstance());
- EXPECT_FALSE(JavaLangObject->IsArrayClass());
- EXPECT_EQ(0, JavaLangObject->GetArrayRank());
- EXPECT_FALSE(JavaLangObject->IsInterface());
- EXPECT_TRUE(JavaLangObject->IsPublic());
- EXPECT_FALSE(JavaLangObject->IsFinal());
- EXPECT_FALSE(JavaLangObject->IsPrimitive());
- EXPECT_FALSE(JavaLangObject->IsSynthetic());
- EXPECT_EQ(2U, JavaLangObject->NumDirectMethods());
- EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods());
- EXPECT_EQ(2U, JavaLangObject->NumInstanceFields());
- EXPECT_TRUE(JavaLangObject->GetInstanceField(0)->GetName()->Equals("shadow$_klass_"));
- EXPECT_TRUE(JavaLangObject->GetInstanceField(1)->GetName()->Equals("shadow$_monitor_"));
-
- EXPECT_EQ(0U, JavaLangObject->NumStaticFields());
- EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
-
- const ClassLoader* class_loader = LoadDex("MyClass");
- AssertNonExistentClass("LMyClass;");
- Class* MyClass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(MyClass != NULL);
- ASSERT_TRUE(MyClass->GetClass() != NULL);
- ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
- EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
- ASSERT_TRUE(MyClass->GetDescriptor()->Equals("LMyClass;"));
- EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
- EXPECT_TRUE(MyClass->HasSuperClass());
- EXPECT_EQ(class_loader, MyClass->GetClassLoader());
- EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
- EXPECT_FALSE(MyClass->IsErroneous());
- EXPECT_FALSE(MyClass->IsVerified());
- EXPECT_TRUE(MyClass->IsResolved());
- EXPECT_FALSE(MyClass->IsArrayInstance());
- EXPECT_FALSE(MyClass->IsArrayClass());
- EXPECT_EQ(0, JavaLangObject->GetArrayRank());
- EXPECT_FALSE(MyClass->IsInterface());
- EXPECT_FALSE(MyClass->IsPublic());
- EXPECT_FALSE(MyClass->IsFinal());
- EXPECT_FALSE(MyClass->IsPrimitive());
- EXPECT_FALSE(MyClass->IsSynthetic());
- EXPECT_EQ(1U, MyClass->NumDirectMethods());
- EXPECT_EQ(0U, MyClass->NumVirtualMethods());
- EXPECT_EQ(0U, MyClass->NumInstanceFields());
- EXPECT_EQ(0U, MyClass->NumStaticFields());
- EXPECT_EQ(0U, MyClass->NumInterfaces());
-
- EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
-
- // created by class_linker
- AssertArrayClass("[C", 1, "C", NULL);
- AssertArrayClass("[Ljava/lang/Object;", 1, "Ljava/lang/Object;", NULL);
- // synthesized on the fly
- AssertArrayClass("[[C", 2, "C", NULL);
- AssertArrayClass("[[[LMyClass;", 3, "LMyClass;", class_loader);
- // or not available at all
- AssertNonExistentClass("[[[[LNonExistentClass;");
-}
-
-TEST_F(ClassLinkerTest, LibCore) {
- AssertDexFile(java_lang_dex_file_.get(), NULL);
-}
-
struct CheckOffset {
size_t cpp_offset;
const char* java_name;
@@ -480,6 +370,9 @@ struct CheckOffsets {
};
};
+// Note that ClassLinkerTest.ValidateFieldOrderOfJavaCppUnionClasses
+// is first since if it is failing, others are unlikely to succeed.
+
struct ObjectOffsets : public CheckOffsets {
ObjectOffsets() {
instance = true;
@@ -601,7 +494,6 @@ struct ClassOffsets : public CheckOffsets {
// alphabetical 32-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_), "shadow$_access_flags_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, array_rank_), "shadow$_array_rank_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_), "shadow$_class_size_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_), "shadow$_clinit_thread_id_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
@@ -698,6 +590,10 @@ struct ClassClassOffsets : public CheckOffsets {
size = sizeof(ClassClass);
class_descriptor = "Ljava/lang/Class;";
+ // padding 32-bit
+ CHECK_EQ(OFFSETOF_MEMBER(ClassClass, padding_) + 4,
+ OFFSETOF_MEMBER(ClassClass, serialVersionUID_));
+
// alphabetical 64-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassClass, serialVersionUID_), "serialVersionUID"));
};
@@ -713,11 +609,11 @@ struct StringClassOffsets : public CheckOffsets {
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, ASCII_), "ASCII"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER"));
+ // padding 32-bit
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR"));
+
// alphabetical 64-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, serialVersionUID_), "serialVersionUID"));
-
- // alphabetical 32-bit
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR"));
};
};
@@ -776,6 +672,113 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
EXPECT_TRUE(MethodClassOffsets().Check());
}
+TEST_F(ClassLinkerTest, FindClassNonexistent) {
+ AssertNonExistentClass("NoSuchClass;");
+ AssertNonExistentClass("LNoSuchClass;");
+}
+
+TEST_F(ClassLinkerTest, FindClassNested) {
+ const ClassLoader* class_loader = LoadDex("Nested");
+
+ Class* outer = class_linker_->FindClass("LNested;", class_loader);
+ ASSERT_TRUE(outer != NULL);
+ EXPECT_EQ(0U, outer->NumVirtualMethods());
+ EXPECT_EQ(1U, outer->NumDirectMethods());
+
+ Class* inner = class_linker_->FindClass("LNested$Inner;", class_loader);
+ ASSERT_TRUE(inner != NULL);
+ EXPECT_EQ(0U, inner->NumVirtualMethods());
+ EXPECT_EQ(1U, inner->NumDirectMethods());
+}
+
+TEST_F(ClassLinkerTest, FindClass_Primitives) {
+ StringPiece expected = "BCDFIJSZV";
+ for (int ch = 0; ch < 255; ch++) {
+ char* s = reinterpret_cast<char*>(&ch);
+ StringPiece descriptor(s, 1);
+ if (expected.find(ch) == StringPiece::npos) {
+ AssertNonExistentClass(descriptor);
+ } else {
+ AssertPrimitiveClass(descriptor);
+ }
+ }
+}
+
+TEST_F(ClassLinkerTest, FindClass) {
+ Class* JavaLangObject = class_linker_->FindSystemClass("Ljava/lang/Object;");
+ ASSERT_TRUE(JavaLangObject != NULL);
+ ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
+ ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
+ EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
+ ASSERT_TRUE(JavaLangObject->GetDescriptor()->Equals("Ljava/lang/Object;"));
+ EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
+ EXPECT_FALSE(JavaLangObject->HasSuperClass());
+ EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
+ EXPECT_FALSE(JavaLangObject->IsErroneous());
+ EXPECT_TRUE(JavaLangObject->IsVerified());
+ EXPECT_TRUE(JavaLangObject->IsResolved());
+ EXPECT_FALSE(JavaLangObject->IsArrayInstance());
+ EXPECT_FALSE(JavaLangObject->IsArrayClass());
+ EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
+ EXPECT_FALSE(JavaLangObject->IsInterface());
+ EXPECT_TRUE(JavaLangObject->IsPublic());
+ EXPECT_FALSE(JavaLangObject->IsFinal());
+ EXPECT_FALSE(JavaLangObject->IsPrimitive());
+ EXPECT_FALSE(JavaLangObject->IsSynthetic());
+ EXPECT_EQ(2U, JavaLangObject->NumDirectMethods());
+ EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods());
+ EXPECT_EQ(2U, JavaLangObject->NumInstanceFields());
+ EXPECT_TRUE(JavaLangObject->GetInstanceField(0)->GetName()->Equals("shadow$_klass_"));
+ EXPECT_TRUE(JavaLangObject->GetInstanceField(1)->GetName()->Equals("shadow$_monitor_"));
+
+ EXPECT_EQ(0U, JavaLangObject->NumStaticFields());
+ EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
+
+ const ClassLoader* class_loader = LoadDex("MyClass");
+ AssertNonExistentClass("LMyClass;");
+ Class* MyClass = class_linker_->FindClass("LMyClass;", class_loader);
+ ASSERT_TRUE(MyClass != NULL);
+ ASSERT_TRUE(MyClass->GetClass() != NULL);
+ ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
+ EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
+ ASSERT_TRUE(MyClass->GetDescriptor()->Equals("LMyClass;"));
+ EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
+ EXPECT_TRUE(MyClass->HasSuperClass());
+ EXPECT_EQ(class_loader, MyClass->GetClassLoader());
+ EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
+ EXPECT_FALSE(MyClass->IsErroneous());
+ EXPECT_FALSE(MyClass->IsVerified());
+ EXPECT_TRUE(MyClass->IsResolved());
+ EXPECT_FALSE(MyClass->IsArrayInstance());
+ EXPECT_FALSE(MyClass->IsArrayClass());
+ EXPECT_TRUE(MyClass->GetComponentType() == NULL);
+ EXPECT_FALSE(MyClass->IsInterface());
+ EXPECT_FALSE(MyClass->IsPublic());
+ EXPECT_FALSE(MyClass->IsFinal());
+ EXPECT_FALSE(MyClass->IsPrimitive());
+ EXPECT_FALSE(MyClass->IsSynthetic());
+ EXPECT_EQ(1U, MyClass->NumDirectMethods());
+ EXPECT_EQ(0U, MyClass->NumVirtualMethods());
+ EXPECT_EQ(0U, MyClass->NumInstanceFields());
+ EXPECT_EQ(0U, MyClass->NumStaticFields());
+ EXPECT_EQ(0U, MyClass->NumInterfaces());
+
+ EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
+
+ // created by class_linker
+ AssertArrayClass("[C", "C", NULL);
+ AssertArrayClass("[Ljava/lang/Object;", "Ljava/lang/Object;", NULL);
+ // synthesized on the fly
+ AssertArrayClass("[[C", "[C", NULL);
+ AssertArrayClass("[[[LMyClass;", "[[LMyClass;", class_loader);
+ // or not available at all
+ AssertNonExistentClass("[[[[LNonExistentClass;");
+}
+
+TEST_F(ClassLinkerTest, LibCore) {
+ AssertDexFile(java_lang_dex_file_.get(), NULL);
+}
+
// The first reference array element must be a multiple of 8 bytes from the
// start of the object
TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) {
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 10ffab3..c17a225 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -435,7 +435,7 @@ void DexFile::InitIndex() {
}
const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const {
- CHECK(descriptor != NULL);
+ CHECK(!descriptor.empty());
Index::const_iterator it = index_.find(descriptor);
if (it == index_.end()) {
return NULL;
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index b15e7bd..e0032b2 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -505,7 +505,7 @@ bool DexVerifier::CheckArrayData(const DexFile::CodeItem* code_item,
const uint16_t* array_data;
int32_t array_data_offset;
- assert(cur_offset < insn_count);
+ DCHECK_LT(cur_offset, insn_count);
/* make sure the start of the array data table is in range */
array_data_offset = insns[1] | (((int32_t) insns[2]) << 16);
@@ -839,7 +839,7 @@ bool DexVerifier::InitRegisterTable(VerifierData* vdata,
reg_table->insn_reg_count_plus_ = registers_size + kExtraRegs;
reg_table->register_lines_.reset(new RegisterLine[insns_size]());
- assert(insns_size > 0);
+ DCHECK_GT(insns_size, 0U);
bool track_monitors;
//if (gDvm.monitorVerification) {
@@ -929,7 +929,7 @@ DexVerifier::UninitInstanceMap* DexVerifier::CreateUninitInstanceMap(
inst = inst->Next();
}
- assert(idx == new_instance_count);
+ CHECK_EQ(idx, new_instance_count);
return uninit_map;
}
@@ -966,7 +966,7 @@ Class* DexVerifier::LookupClassByDescriptor(const Method* method,
}
/* Check if the descriptor is an array. */
- if (descriptor[0] == '[') {
+ if (descriptor[0] == '[' && descriptor[1] != '\0') {
/*
* There should never be a problem loading primitive arrays.
*/
@@ -1012,7 +1012,7 @@ Class* DexVerifier::LookupClassByDescriptor(const Method* method,
Class* DexVerifier::LookupSignatureClass(const Method* method, std::string sig,
VerifyError* failure) {
- assert(sig[0] == 'L');
+ DCHECK_EQ(sig[0], 'L');
size_t end = sig.find(';');
if (end == std::string::npos) {
@@ -1027,7 +1027,7 @@ Class* DexVerifier::LookupSignatureClass(const Method* method, std::string sig,
Class* DexVerifier::LookupSignatureArrayClass(const Method* method,
std::string sig, VerifyError* failure) {
- assert(sig[0] == '[');
+ DCHECK_EQ(sig[0], '[');
size_t end = 0;
while (sig[end] == '[')
@@ -1058,7 +1058,7 @@ bool DexVerifier::SetTypesFromSignature(VerifierData* vdata, RegType* reg_types)
int expected_args = code_item->ins_size_; /* long/double count as two */
int actual_args = 0;
- assert(arg_start >= 0); /* should have been verified earlier */
+ DCHECK_GE(arg_start, 0); /* should have been verified earlier */
/*
* Include the "this" pointer.
@@ -1074,7 +1074,7 @@ bool DexVerifier::SetTypesFromSignature(VerifierData* vdata, RegType* reg_types)
if (IsInitMethod(method) && method->GetDeclaringClass() != klass_object) {
int idx = SetUninitInstance(uninit_map, kUninitThisArgAddr,
method->GetDeclaringClass());
- assert(idx == 0);
+ DCHECK_EQ(idx, 0);
reg_types[arg_start + actual_args] = RegTypeFromUninitIndex(idx);
} else {
reg_types[arg_start + actual_args] =
@@ -1218,7 +1218,7 @@ bool DexVerifier::SetTypesFromSignature(VerifierData* vdata, RegType* reg_types)
int DexVerifier::SetUninitInstance(UninitInstanceMap* uninit_map, int addr,
Class* klass) {
int idx;
- assert(klass != NULL);
+ DCHECK(klass != NULL);
/* TODO: binary search when num_entries > 8 */
for (idx = uninit_map->num_entries_ - 1; idx >= 0; idx--) {
@@ -1235,8 +1235,7 @@ int DexVerifier::SetUninitInstance(UninitInstanceMap* uninit_map, int addr,
}
}
- LOG(ERROR) << "VFY: addr " << addr << " not found in uninit map";
- assert(false); // shouldn't happen
+ LOG(FATAL) << "VFY: addr " << addr << " not found in uninit map";
return -1;
}
@@ -1508,7 +1507,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
*/
res_class = GetCaughtExceptionType(vdata, insn_idx, &failure);
if (res_class == NULL) {
- assert(failure != VERIFY_ERROR_NONE);
+ DCHECK(failure != VERIFY_ERROR_NONE);
} else {
SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(res_class));
}
@@ -1583,8 +1582,8 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
}
/* return_type is the *expected* return type, not register value */
- assert(return_type != kRegTypeZero);
- assert(!RegTypeIsUninitReference(return_type));
+ DCHECK(return_type != kRegTypeZero);
+ DCHECK(!RegTypeIsUninitReference(return_type));
/*
* Verify that the reference in vAA is an instance of the type
@@ -1649,7 +1648,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve const-class " << dec_insn.vB_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else {
SetRegisterType(work_line, dec_insn.vA_, RegTypeFromClass(
class_linker->FindSystemClass("Ljava/lang/Class;")));
@@ -1700,7 +1699,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve check-cast " << dec_insn.vB_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else {
RegType orig_type;
@@ -1729,7 +1728,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve instanceof " << dec_insn.vC_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else {
/* result is boolean */
SetRegisterType(work_line, dec_insn.vA_, kRegTypeBoolean);
@@ -1755,7 +1754,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve new-instance " << dec_insn.vB_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else {
RegType uninit_type;
@@ -1769,7 +1768,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
/* add resolved class to uninit map if not already there */
int uidx = SetUninitInstance(uninit_map, insn_idx, res_class);
- assert(uidx >= 0);
+ DCHECK_GE(uidx, 0);
uninit_type = RegTypeFromUninitIndex(uidx);
/*
@@ -1790,7 +1789,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve new-array " << dec_insn.vC_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else if (!res_class->IsArrayClass()) {
LOG(ERROR) << "VFY: new-array on non-array class";
failure = VERIFY_ERROR_GENERIC;
@@ -1809,7 +1808,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
LOG(ERROR) << "VFY: unable to resolve filled-array " << dec_insn.vB_
<< " (" << bad_class_desc << ") in "
<< klass->GetDescriptor()->ToModifiedUtf8();
- assert(failure != VERIFY_ERROR_GENERIC);
+ DCHECK(failure != VERIFY_ERROR_GENERIC);
} else if (!res_class->IsArrayClass()) {
LOG(ERROR) << "VFY: filled-new-array on non-array class";
failure = VERIFY_ERROR_GENERIC;
@@ -1888,7 +1887,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
Class::PrimitiveType prim_type =
res_class->GetComponentType()->GetPrimitiveType();
- if (!res_class->IsArrayClass() || res_class->GetArrayRank() != 1 ||
+ if (!res_class->IsArrayClass() ||
prim_type == Class::kPrimNot || prim_type == Class::kPrimVoid) {
LOG(ERROR) << "VFY: invalid fill-array-data on " <<
res_class->GetDescriptor()->ToModifiedUtf8();
@@ -1897,7 +1896,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(VerifierData* vdata,
}
value_type = PrimitiveTypeToRegType(prim_type);
- assert(value_type != kRegTypeUnknown);
+ DCHECK(value_type != kRegTypeUnknown);
/*
* Now verify if the element width in the table matches the element
@@ -2033,8 +2032,7 @@ aget_1nr_common:
/* verify the class */
Class::PrimitiveType prim_type =
res_class->GetComponentType()->GetPrimitiveType();
- if (!res_class->IsArrayClass() || res_class->GetArrayRank() != 1 ||
- prim_type == Class::kPrimNot) {
+ if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
LOG(ERROR) << "VFY: invalid aget-1nr target "
<< res_class->GetDescriptor()->ToModifiedUtf8();
failure = VERIFY_ERROR_GENERIC;
@@ -2077,8 +2075,7 @@ aget_1nr_common:
/* verify the class */
Class::PrimitiveType prim_type =
res_class->GetComponentType()->GetPrimitiveType();
- if (!res_class->IsArrayClass() || res_class->GetArrayRank() != 1 ||
- prim_type == Class::kPrimNot) {
+ if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
LOG(ERROR) << "VFY: invalid aget-wide target "
<< res_class->GetDescriptor()->ToModifiedUtf8();
failure = VERIFY_ERROR_GENERIC;
@@ -2127,29 +2124,19 @@ aget_1nr_common:
if (res_class != NULL) {
Class* element_class;
- assert(res_class != NULL);
+ DCHECK(res_class != NULL);
if (!res_class->IsArrayClass()) {
LOG(ERROR) << "VFY: aget-object on non-array class";
failure = VERIFY_ERROR_GENERIC;
break;
}
- assert(res_class->GetComponentType() != NULL);
+ DCHECK(res_class->GetComponentType() != NULL);
/*
- * Find the element class. res_class->GetComponentType() indicates
- * the basic type, which won't be what we want for a
- * multi-dimensional array.
+ * Find the element class.
*/
- if (res_class->GetDescriptor()->CharAt(1) == '[') {
- assert(res_class->GetArrayRank() > 1);
- std::string descriptor =
- res_class->GetDescriptor()->ToModifiedUtf8();
- element_class = class_linker->FindClass(descriptor.c_str() + 1,
- res_class->GetClassLoader());
- } else if (res_class->GetDescriptor()->CharAt(1) == 'L') {
- assert(res_class->GetArrayRank() == 1);
- element_class = res_class->GetComponentType();
- } else {
+ element_class = res_class->GetComponentType();
+ if (element_class->IsPrimitive()) {
LOG(ERROR) << "VFY: aget-object on non-ref array class ("
<< res_class->GetDescriptor()->ToModifiedUtf8() << ")";
failure = VERIFY_ERROR_GENERIC;
@@ -2204,8 +2191,7 @@ aput_1nr_common:
Class::PrimitiveType prim_type =
res_class->GetComponentType()->GetPrimitiveType();
- if (!res_class->IsArrayClass() || res_class->GetArrayRank() != 1 ||
- prim_type == Class::kPrimNot) {
+ if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot) {
LOG(ERROR) << "VFY: invalid aput-1nr on "
<< res_class->GetDescriptor()->ToModifiedUtf8();
failure = VERIFY_ERROR_GENERIC;
@@ -2253,8 +2239,7 @@ aput_1nr_common:
Class::PrimitiveType prim_type =
res_class->GetComponentType()->GetPrimitiveType();
/* verify the class and try to refine "dst_type" */
- if (!res_class->IsArrayClass() || res_class->GetArrayRank() != 1 ||
- prim_type == Class::kPrimNot)
+ if (!res_class->IsArrayClass() || prim_type == Class::kPrimNot)
{
LOG(ERROR) << "VFY: invalid aput-wide on "
<< res_class->GetDescriptor()->ToModifiedUtf8();
@@ -2310,26 +2295,15 @@ aput_1nr_common:
}
/*
- * Find the element class. res_class->GetComponentType() indicates
- * the basic type, which won't be what we want for a
- * multi-dimensional array.
+ * Find the element class.
*
* All we want to check here is that the element type is a
* reference class. We *don't* check instanceof here, because
* you can still put a String into a String[] after the latter
* has been cast to an Object[].
*/
- if (array_class->GetDescriptor()->CharAt(1) == '[') {
- assert(array_class->GetArrayRank() > 1);
- std::string descriptor =
- array_class->GetDescriptor()->ToModifiedUtf8();
- element_class = class_linker->FindClass(descriptor.c_str() + 1,
- array_class->GetClassLoader());
- } else {
- assert(array_class->GetArrayRank() == 1);
- element_class = array_class->GetComponentType();
- }
- if (element_class->GetPrimitiveType() != Class::kPrimNot) {
+ element_class = array_class->GetComponentType();
+ if (element_class->IsPrimitive()) {
LOG(ERROR) << "VFY: invalid aput-object of "
<< res_class->GetDescriptor()->ToModifiedUtf8()
<< " into "
@@ -2438,7 +2412,7 @@ iget_1nr_common:
break;
}
if (failure == VERIFY_ERROR_NONE) {
- assert(!field_class->IsPrimitive());
+ DCHECK(!field_class->IsPrimitive()) << PrettyClass(field_class);
SetRegisterType(work_line, dec_insn.vA_,
RegTypeFromClass(field_class));
}
@@ -2925,7 +2899,7 @@ sput_1nr_common:
Class* this_class;
this_class = RegTypeReferenceToClass(this_type, uninit_map);
- assert(this_class != NULL);
+ DCHECK(this_class != NULL);
/* must be in same class or in superclass */
if (called_method->GetDeclaringClass() == this_class->GetSuperClass())
@@ -3492,8 +3466,7 @@ sput_1nr_common:
LOG(ERROR) << "VFY: bad branch at 0x" << std::hex << insn_idx << std::dec;
return false;
}
- assert(isConditional || (opcode_flag & Instruction::kContinue) == 0);
- assert(!isConditional || (opcode_flag & Instruction::kContinue) != 0);
+ DCHECK_EQ(isConditional, (opcode_flag & Instruction::kContinue) != 0);
if (!CheckMoveException(code_item->insns_, insn_idx + branch_target))
return false;
@@ -3521,7 +3494,7 @@ sput_1nr_common:
offset_to_targets = 4;
} else {
/* 0 = sig, 1 = count, 2..count * 2 = keys */
- assert((*insns & 0xff) == Instruction::SPARSE_SWITCH);
+ DCHECK((*insns & 0xff) == Instruction::SPARSE_SWITCH);
offset_to_targets = 2 + 2 * switch_count;
}
@@ -3535,7 +3508,7 @@ sput_1nr_common:
(((int32_t) switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
abs_offset = insn_idx + offset;
- assert(abs_offset < insns_size);
+ DCHECK_LT(abs_offset, insns_size);
if (!CheckMoveException(code_item->insns_, abs_offset))
return false;
@@ -3615,8 +3588,8 @@ sput_1nr_common:
*start_guess = insn_idx + branch_target;
}
- assert(*start_guess < insns_size &&
- InsnGetWidth(insn_flags, *start_guess) != 0);
+ DCHECK_LT(*start_guess, insns_size);
+ DCHECK(InsnGetWidth(insn_flags, *start_guess) != 0);
return true;
}
@@ -3696,7 +3669,7 @@ bool DexVerifier::ReplaceFailingInstruction(const DexFile::CodeItem* code_item,
return false;
}
- assert(inst->IsThrow());
+ DCHECK(inst->IsThrow());
/* write a NOP over the third code unit, if necessary */
int width = InsnGetWidth(insn_flags, insn_idx);
@@ -3716,7 +3689,7 @@ bool DexVerifier::ReplaceFailingInstruction(const DexFile::CodeItem* code_item,
/* encode the opcode, with the failure code in the high byte */
// TODO: REPLACE FAILING OPCODES
- //assert(width == 2 || width == 3);
+ //DCHECK(width == 2 || width == 3);
//uint16_t new_val = Instruction::THROW_VERIFICATION_ERROR |
//uint16_t new_val = Instruction::UNUSED_ED |
//(failure << 8) | (ref_type << (8 + kVerifyErrorRefTypeShift));
@@ -3835,7 +3808,7 @@ Field* DexVerifier::GetInstField(VerifierData* vdata, RegType obj_type,
* declared by this class.
*/
obj_class = RegTypeReferenceToClass(obj_type, uninit_map);
- assert(obj_class != NULL);
+ DCHECK(obj_class != NULL);
if (RegTypeIsUninitReference(obj_type)) {
if (!IsInitMethod(method) || method->GetDeclaringClass() != obj_class) {
LOG(ERROR) << "VFY: attempt to access field via uninitialized ref";
@@ -4135,15 +4108,14 @@ void DexVerifier::VerifyRegisterType(RegisterLine* register_line, uint32_t vsrc,
case kRegTypeUnknown:
case kRegTypeConflict:
/* should never be checking for these explicitly */
- assert(false);
+ DCHECK(false);
*failure = VERIFY_ERROR_GENERIC;
return;
case kRegTypeUninit:
default:
/* make sure check_type is initialized reference */
if (!RegTypeIsReference(check_type)) {
- LOG(ERROR) << "VFY: unexpected check type " << check_type;
- assert(false);
+ LOG(FATAL) << "VFY: unexpected check type " << check_type;
*failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4168,8 +4140,8 @@ void DexVerifier::VerifyRegisterType(RegisterLine* register_line, uint32_t vsrc,
if (src_type != kRegTypeZero) {
Class* src_class = RegTypeInitializedReferenceToClass(src_type);
Class* check_class = RegTypeInitializedReferenceToClass(check_type);
- assert(src_class != NULL);
- assert(check_class != NULL);
+ DCHECK(src_class != NULL);
+ DCHECK(check_class != NULL);
if (!check_class->IsAssignableFrom(src_class)) {
LOG(ERROR) << "VFY: " << src_class->GetDescriptor()->ToModifiedUtf8()
@@ -4210,7 +4182,7 @@ void DexVerifier::MarkRefsAsInitialized(RegisterLine* register_line,
changed++;
}
}
- assert(changed > 0);
+ DCHECK_GT(changed, 0);
return;
}
@@ -4230,7 +4202,7 @@ void DexVerifier::MarkUninitRefsAsInvalid(RegisterLine* register_line,
void DexVerifier::CopyRegister1(RegisterLine* register_line, uint32_t vdst,
uint32_t vsrc, TypeCategory cat, VerifyError* failure) {
- assert(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
+ DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
RegType type = GetRegisterType(register_line, vsrc);
CheckTypeCategory(type, cat, failure);
if (*failure != VERIFY_ERROR_NONE) {
@@ -4263,7 +4235,7 @@ void DexVerifier::CopyRegister2(RegisterLine* register_line, uint32_t vdst,
void DexVerifier::CopyResultRegister1(RegisterLine* register_line,
const int insn_reg_count, uint32_t vdst, TypeCategory cat,
VerifyError* failure) {
- assert(vdst < (uint32_t) insn_reg_count);
+ DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
RegType type = GetRegisterType(register_line, vsrc);
@@ -4283,7 +4255,7 @@ void DexVerifier::CopyResultRegister1(RegisterLine* register_line,
*/
void DexVerifier::CopyResultRegister2(RegisterLine* register_line,
const int insn_reg_count, uint32_t vdst, VerifyError* failure) {
- assert(vdst < (uint32_t) insn_reg_count);
+ DCHECK_LT(vdst, static_cast<uint32_t>(insn_reg_count));
uint32_t vsrc = RESULT_REGISTER(insn_reg_count);
RegType type_l = GetRegisterType(register_line, vsrc);
@@ -4332,77 +4304,33 @@ Class* DexVerifier::DigForSuperclass(Class* c1, Class* c2) {
while (c1 != c2) {
c1 = c1->GetSuperClass();
c2 = c2->GetSuperClass();
-
- assert(c1 != NULL && c2 != NULL);
+ DCHECK(c1 != NULL);
+ DCHECK(c2 != NULL);
}
return c1;
}
Class* DexVerifier::FindCommonArraySuperclass(Class* c1, Class* c2) {
- Class* array_class = NULL;
- Class* common_elem;
- int array_dim1, array_dim2;
- int i, num_dims;
- bool has_primitive = false;
-
- array_dim1 = c1->GetArrayRank();
- array_dim2 = c2->GetArrayRank();
- assert(c1->GetArrayRank() > 0);
- assert(c2->GetArrayRank() > 0);
-
- if (c1->GetComponentType()->IsPrimitive()) {
- array_dim1--;
- has_primitive = true;
- }
- if (c2->GetComponentType()->IsPrimitive()) {
- array_dim2--;
- has_primitive = true;
- }
-
- if (!has_primitive && array_dim1 == array_dim2) {
- /*
- * Two arrays of reference types with equal dimensions. Try to
- * find a good match.
- */
- common_elem = FindCommonSuperclass(c1->GetComponentType(),
- c2->GetComponentType());
- num_dims = array_dim1;
- } else {
- /*
- * Mismatched array depths and/or array(s) of primitives. We want
- * Object, or an Object array with appropriate dimensions.
- *
- * We initialize array_class to Object here, because it's possible
- * for us to set num_dims=0.
- */
- if (array_dim1 < array_dim2)
- num_dims = array_dim1;
- else
- num_dims = array_dim2;
- array_class = common_elem = c1->GetSuperClass(); // == java.lang.Object
- }
-
- /*
- * Find an appropriately-dimensioned array class. This is easiest
- * to do iteratively, using the array class found by the current round
- * as the element type for the next round.
- */
- for (i = 0; i < num_dims; i++) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const ClassLoader* class_loader = c1->GetClassLoader();
- std::string descriptor = "[" +
- common_elem->GetDescriptor()->ToModifiedUtf8();
- array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
- common_elem = array_class;
- }
- assert(array_class != NULL);
-
+ DCHECK(c1->IsArrayClass());
+ DCHECK(c2->IsArrayClass());
+ Class* e1 = c1->GetComponentType();
+ Class* e2 = c2->GetComponentType();
+ if (e1->IsPrimitive() || e2->IsPrimitive()) {
+ return c1->GetSuperClass(); // == java.lang.Object
+ }
+ Class* common_elem = FindCommonSuperclass(c1->GetComponentType(), c2->GetComponentType());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const ClassLoader* class_loader = c1->GetClassLoader();
+ std::string descriptor = "[" + common_elem->GetDescriptor()->ToModifiedUtf8();
+ Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
+ DCHECK(array_class != NULL);
return array_class;
}
Class* DexVerifier::FindCommonSuperclass(Class* c1, Class* c2) {
- assert(!c1->IsPrimitive() && !c2->IsPrimitive());
+ DCHECK(!c1->IsPrimitive()) << PrettyClass(c1);
+ DCHECK(!c2->IsPrimitive()) << PrettyClass(c2);
if (c1 == c2)
return c1;
@@ -4487,7 +4415,7 @@ DexVerifier::RegType DexVerifier::MergeTypes(RegType type1, RegType type2,
Class* klass1 = RegTypeInitializedReferenceToClass(type1);
Class* klass2 = RegTypeInitializedReferenceToClass(type2);
Class* merged_class = FindCommonSuperclass(klass1, klass2);
- assert(merged_class != NULL);
+ DCHECK(merged_class != NULL);
result = RegTypeFromClass(merged_class);
}
}
@@ -4509,7 +4437,7 @@ DexVerifier::MonitorEntries DexVerifier::MergeMonitorEntries(
bool DexVerifier::UpdateRegisters(InsnFlags* insn_flags,
RegisterTable* reg_table, int next_insn, const RegisterLine* work_line) {
const size_t insn_reg_count_plus = reg_table->insn_reg_count_plus_;
- assert(work_line != NULL);
+ DCHECK(work_line != NULL);
const RegType* work_regs = work_line->reg_types_.get();
if (!InsnIsVisitedOrChanged(insn_flags, next_insn)) {
@@ -4531,7 +4459,7 @@ bool DexVerifier::UpdateRegisters(InsnFlags* insn_flags,
bool changed = false;
unsigned int idx;
- assert(target_regs != NULL);
+ DCHECK(target_regs != NULL);
if (target_mon_ents != NULL) {
/* Monitor stacks must be identical. */
if (target_line->monitor_stack_top_ != work_line->monitor_stack_top_) {
@@ -4589,7 +4517,8 @@ bool DexVerifier::CanConvertTo1nr(RegType src_type, RegType check_type) {
{ /*F*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
};
- assert(check_type >= kRegType1nrSTART && check_type <= kRegType1nrEND);
+ DCHECK(check_type >= kRegType1nrSTART);
+ DCHECK(check_type <= kRegType1nrEND);
if (src_type >= kRegType1nrSTART && src_type <= kRegType1nrEND)
return (bool) conv_tab[src_type - kRegType1nrSTART]
@@ -4755,7 +4684,7 @@ void DexVerifier::CheckTypeCategory(RegType type, TypeCategory cat,
*failure = VERIFY_ERROR_GENERIC;
break;
default:
- assert(false);
+ DCHECK(false);
*failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4794,7 +4723,7 @@ void DexVerifier::CheckLitop(RegisterLine* register_line,
VerifyRegisterType(register_line, dec_insn->vB_, src_type, failure);
if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
- assert(dst_type == kRegTypeInteger);
+ DCHECK(dst_type == kRegTypeInteger);
/* check vB with the call, then check the constant manually */
if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vB_)
@@ -4814,7 +4743,7 @@ void DexVerifier::CheckBinop(RegisterLine* register_line,
VerifyRegisterType(register_line, dec_insn->vC_, src_type2, failure);
if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
- assert(dst_type == kRegTypeInteger);
+ DCHECK(dst_type == kRegTypeInteger);
if (UpcastBooleanOp(register_line, dec_insn->vB_, dec_insn->vC_))
dst_type = kRegTypeBoolean;
}
@@ -4830,7 +4759,7 @@ void DexVerifier::CheckBinop2addr(RegisterLine* register_line,
VerifyRegisterType(register_line, dec_insn->vB_, src_type2, failure);
if ((*failure == VERIFY_ERROR_NONE) && check_boolean_op) {
- assert(dst_type == kRegTypeInteger);
+ DCHECK(dst_type == kRegTypeInteger);
if (UpcastBooleanOp(register_line, dec_insn->vA_, dec_insn->vB_))
dst_type = kRegTypeBoolean;
}
@@ -4908,7 +4837,7 @@ DexVerifier::RegType DexVerifier::AdjustForRightShift(
break;
default:
/* long, double, references; shouldn't be here! */
- assert(false);
+ DCHECK(false);
break;
}
@@ -4924,7 +4853,7 @@ void DexVerifier::VerifyFilledNewArrayRegs(const Method* method,
Class::PrimitiveType elem_type;
unsigned int ui;
- assert(res_class->IsArrayClass());
+ DCHECK(res_class->IsArrayClass()) << PrettyClass(res_class);
elem_type = res_class->GetComponentType()->GetPrimitiveType();
if (elem_type == Class::kPrimNot) {
expected_type = RegTypeFromClass(res_class->GetComponentType());
@@ -5039,7 +4968,7 @@ Method* DexVerifier::VerifyInvocationArgs(VerifierData* vdata,
* method's class' superclass has a vtable entry for the target method.
*/
if (is_super) {
- assert(method_type == METHOD_VIRTUAL);
+ DCHECK(method_type == METHOD_VIRTUAL);
Class* super = method->GetDeclaringClass()->GetSuperClass();
if (super == NULL || res_method->GetMethodIndex() > super->GetVTable()->GetLength()) {
if (super == NULL) {
@@ -5071,7 +5000,7 @@ Method* DexVerifier::VerifyInvocationArgs(VerifierData* vdata,
actual_args = 0;
/* caught by static verifier */
- assert(is_range || expected_args <= 5);
+ DCHECK(is_range || expected_args <= 5);
if (expected_args > code_item->outs_size_) {
LOG(ERROR) << "VFY: invalid arg count (" << expected_args
@@ -5300,7 +5229,7 @@ DexVerifier::RegisterMap* DexVerifier::GenerateRegisterMapV(VerifierData* vdata)
uint8_t* map_data = map->data_;
for (i = 0; i < (int) vdata->code_item_->insns_size_; i++) {
if (InsnIsGcPoint(vdata->insn_flags_.get(), i)) {
- assert(vdata->register_lines_[i].reg_types_.get() != NULL);
+ DCHECK(vdata->register_lines_[i].reg_types_.get() != NULL);
if (format == kRegMapFormatCompact8) {
*map_data++ = i;
} else /*kRegMapFormatCompact16*/ {
@@ -5313,7 +5242,7 @@ DexVerifier::RegisterMap* DexVerifier::GenerateRegisterMapV(VerifierData* vdata)
}
}
- assert((uint32_t) map_data - (uint32_t) map->data_ == data_size);
+ DCHECK_EQ((uint32_t) map_data - (uint32_t) map->data_, data_size);
// TODO: Remove this check when it's really running...
#if 1
@@ -5410,7 +5339,7 @@ const uint8_t* DexVerifier::RegisterMapGetLine(const RegisterMap* map, int addr)
uint8_t format = map->header_->format_;
uint16_t num_entries = map->header_->num_entries_;
- assert(num_entries > 0);
+ DCHECK_GT(num_entries, 0);
switch (format) {
case kRegMapFormatNone:
@@ -5447,7 +5376,7 @@ const uint8_t* DexVerifier::RegisterMapGetLine(const RegisterMap* map, int addr)
data += line_width;
}
- assert(data == map->data_ + line_width * num_entries);
+ DCHECK_EQ(data, map->data_ + line_width * num_entries);
} else {
int hi, lo, mid;
@@ -5588,7 +5517,7 @@ size_t DexVerifier::ComputeRegisterMapSize(const RegisterMap* map) {
uint8_t format = map->header_->format_;
uint16_t num_entries = map->header_->num_entries_;
- assert(map != NULL);
+ DCHECK(map != NULL);
switch (format) {
case kRegMapFormatNone:
@@ -5647,13 +5576,17 @@ int DexVerifier::ComputeBitDiff(const uint8_t* bits1, const uint8_t* bits2,
}
}
- if (num_bits_changed > 0)
- assert(first_bit_changed >= 0);
+ if (num_bits_changed > 0) {
+ DCHECK_GE(first_bit_changed, 0);
+ }
- if (first_bit_changed_ptr != NULL)
+ if (first_bit_changed_ptr != NULL) {
*first_bit_changed_ptr = first_bit_changed;
- if (num_bits_changed_ptr != NULL)
+ }
+
+ if (num_bits_changed_ptr != NULL) {
*num_bits_changed_ptr = num_bits_changed;
+ }
return leb_size;
}
@@ -5744,7 +5677,7 @@ DexVerifier::RegisterMap* DexVerifier::CompressMapDifferential(
addr |= (*map_data++) << 8;
addr_diff = addr - prev_addr;
- assert(addr_diff > 0);
+ DCHECK_GT(addr_diff, 0);
if (addr_diff < 8) {
/* Small difference, encode in 3 bits. */
key = addr_diff -1; /* set 00000AAA */
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 0c6bbe5..3e80c6b 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -35,24 +35,7 @@ jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
}
jclass Class_getComponentType(JNIEnv* env, jobject javaThis) {
- Class* c = Decode<Class*>(env, javaThis);
- if (!c->IsArrayClass()) {
- return NULL;
- }
-
- /*
- * We can't just return c->GetComponentType(), because that gives
- * us the base type (e.g. X[][][] returns X). If this is a multi-
- * dimensional array, we have to do the lookup by name.
- */
- Class* result;
- std::string descriptor(c->GetDescriptor()->ToModifiedUtf8());
- if (descriptor[1] == '[') {
- result = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str() + 1, c->GetClassLoader());
- } else {
- result = c->GetComponentType();
- }
- return AddLocalReference<jclass>(env, result);
+ return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType());
}
jobjectArray Class_getDeclaredClasses(JNIEnv* env, jclass java_lang_Class_class, jclass c, jboolean publicOnly) {
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index fc13839..4eaaa66 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -182,10 +182,10 @@ void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject
}
// Neither class is primitive. Are the types trivially compatible?
- const int width = sizeof(Object*);
- bool sameDimensions = srcArray->GetClass()->GetArrayRank() == dstArray->GetClass()->GetArrayRank();
- if (sameDimensions && srcComponentType->InstanceOf(dstComponentType)) {
+ const size_t width = sizeof(Object*);
+ if (dstComponentType->IsAssignableFrom(srcComponentType)) {
// Yes. Bulk copy.
+ DCHECK_EQ(width, sizeof(uint32_t));
move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width);
Heap::WriteBarrier(dstArray);
return;
diff --git a/src/java_lang_reflect_Array.cc b/src/java_lang_reflect_Array.cc
new file mode 100644
index 0000000..b1ae682
--- /dev/null
+++ b/src/java_lang_reflect_Array.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "class_linker.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+
+// Recursively create an array with multiple dimensions. Elements may be
+// Objects or primitive types.
+//
+// The dimension we're creating is in dimensions[0], so when we recurse
+// we advance the pointer.
+Array* CreateMultiArray(Class* array_class, int current_dimension, IntArray* dimensions) {
+ int32_t array_length = dimensions->Get(current_dimension++);
+ Array* new_array = Array::Alloc(array_class, array_length);
+ if (new_array == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ if (current_dimension == dimensions->GetLength()) {
+ return new_array;
+ }
+
+ if (!array_class->GetComponentType()->IsArrayClass()) {
+ // TODO: throw an exception, not relying on class_linker->FindClass to throw.
+ // old code assumed this but if you recurse from "[Foo" to "Foo" to "oo",
+ // you shouldn't assume there isn't a class "oo".
+ }
+ std::string sub_array_descriptor(array_class->GetDescriptor()->ToModifiedUtf8(), 1);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* sub_array_class = class_linker->FindClass(sub_array_descriptor,
+ array_class->GetClassLoader());
+ if (sub_array_class == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ DCHECK(sub_array_class->IsArrayClass());
+ // Create a new sub-array in every element of the array.
+ ObjectArray<Array>* object_array = new_array->AsObjectArray<Array>();
+ for (int32_t i = 0; i < array_length; i++) {
+ Array* sub_array = CreateMultiArray(sub_array_class, current_dimension, dimensions);
+ if (sub_array == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ object_array->Set(i, sub_array);
+ }
+ return new_array;
+}
+
+// Create a multi-dimensional array of Objects or primitive types.
+//
+// We have to generate the names for X[], X[][], X[][][], and so on. The
+// easiest way to deal with that is to create the full name once and then
+// subtract pieces off. Besides, we want to start with the outermost
+// piece and work our way in.
+jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
+ DCHECK(javaElementClass != NULL);
+ Class* element_class = Decode<Class*>(env, javaElementClass);
+ DCHECK(element_class->IsClass());
+ DCHECK(javaDimArray != NULL);
+ Object* dimensions_obj = Decode<Class*>(env, javaDimArray);
+ DCHECK(dimensions_obj->IsArrayInstance());
+ DCHECK(dimensions_obj->GetClass()->GetDescriptor()->Equals("[I"));
+ IntArray* dimensions_array = down_cast<IntArray*>(dimensions_obj);
+
+ // Verify dimensions.
+ //
+ // The caller is responsible for verifying that "dimArray" is non-null
+ // and has a length > 0 and <= 255.
+ int num_dimensions = dimensions_array->GetLength();
+ DCHECK_GT(num_dimensions, 0);
+ DCHECK_LE(num_dimensions, 255);
+
+ for (int i = 0; i < num_dimensions; i++) {
+ if (dimensions_array->Get(i) < 0) {
+ UNIMPLEMENTED(FATAL) << "ThrowNegativeArraySizeException(dimensions[i])";
+ return NULL;
+ }
+ }
+
+ // Generate the full name of the array class.
+ std::string descriptor(num_dimensions, '[');
+ descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+
+ // Find/generate the array class.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* array_class = class_linker->FindClass(descriptor, element_class->GetClassLoader());
+ if (array_class == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ // create the array
+ Array* new_array = CreateMultiArray(array_class, 0, dimensions_array);
+ if (new_array == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ return AddLocalReference<jobject>(env, new_array);
+}
+
+jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementClass, jint length)
+{
+ DCHECK(javaElementClass != NULL);
+ Class* element_class = Decode<Class*>(env, javaElementClass);
+ if (length < 0) {
+ UNIMPLEMENTED(FATAL) << "ThrowNegativeArraySizeException(length)";
+ return NULL;
+ }
+ std::string descriptor;
+ descriptor += '[';
+ descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Class* array_class = class_linker->FindClass(descriptor, element_class->GetClassLoader());
+ if (array_class == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ DCHECK(array_class->IsArrayClass());
+ Array* new_array = Array::Alloc(array_class, length);
+ if (new_array == NULL) {
+ CHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+ return AddLocalReference<jobject>(env, new_array);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Array, createMultiArray, "(Ljava/lang/Class;[I)Ljava/lang/Object;"),
+ NATIVE_METHOD(Array, createObjectArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
+};
+
+} // namespace
+
+void register_java_lang_reflect_Array(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/reflect/Array", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 8572e40..067d36b 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -605,7 +605,7 @@ TEST_F(JniInternalTest, GetStringCritical_ReleaseStringCritical) {
}
TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
- jclass c = env_->FindClass("[Ljava/lang/Object;");
+ jclass c = env_->FindClass("java/lang/Object");
ASSERT_TRUE(c != NULL);
jobjectArray array = env_->NewObjectArray(1, c, NULL);
diff --git a/src/object.cc b/src/object.cc
index 7f247c7..6490797 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -794,52 +794,29 @@ void Class::CanPutArrayElementFromCode(const Object* element, const Class* array
// Don't forget about primitive types.
// Object[] = int[] --> false
//
-bool Class::IsArrayAssignableFromArray(const Class* klass) const {
+bool Class::IsArrayAssignableFromArray(const Class* src) const {
DCHECK(IsArrayClass());
- DCHECK(klass->IsArrayClass());
- DCHECK_GT(GetArrayRank(), 0);
- DCHECK_GT(klass->GetArrayRank(), 0);
- DCHECK(GetComponentType() != NULL);
- DCHECK(klass->GetComponentType() != NULL);
- if (GetArrayRank() > klass->GetArrayRank()) {
- // Too many []s.
- return false;
- }
- if (GetArrayRank() == klass->GetArrayRank()) {
- return GetComponentType()->IsAssignableFrom(klass->GetComponentType());
- }
- DCHECK_LT(GetArrayRank(), klass->GetArrayRank());
- // 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 (GetComponentType()->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(GetComponentType());
- }
- // See if this is an array of Object, Object[], etc.
- return GetComponentType()->IsObjectClass();
+ DCHECK(src->IsArrayClass());
+ return GetComponentType()->IsAssignableFrom(src->GetComponentType());
}
-bool Class::IsAssignableFromArray(const Class* klass) const {
+bool Class::IsAssignableFromArray(const Class* src) const {
DCHECK(!IsInterface()); // handled first in IsAssignableFrom
- DCHECK(klass->IsArrayClass());
+ DCHECK(src->IsArrayClass());
if (!IsArrayClass()) {
// 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();
+ // src's super should be java_lang_Object, since it is an array.
+ Class* java_lang_Object = src->GetSuperClass();
DCHECK(java_lang_Object != NULL);
DCHECK(java_lang_Object->GetSuperClass() == NULL);
return this == java_lang_Object;
}
- return IsArrayAssignableFromArray(klass);
+ return IsArrayAssignableFromArray(src);
}
bool Class::IsSubClass(const Class* klass) const {
DCHECK(!IsInterface());
- DCHECK(!klass->IsArrayClass());
+ DCHECK(!IsArrayClass());
const Class* current = this;
do {
if (current == klass) {
diff --git a/src/object.h b/src/object.h
index 055e6a9..a04fcbb 100644
--- a/src/object.h
+++ b/src/object.h
@@ -413,7 +413,7 @@ class MANAGED Object {
uint32_t monitor_;
friend class ImageWriter; // for abusing monitor_ directly
- friend class ObjectOffsets; // for verifying offset information
+ friend struct ObjectOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
@@ -1386,23 +1386,10 @@ class MANAGED Class : public StaticStorageBase {
size_t PrimitiveSize() const;
bool IsArrayClass() const {
- return GetArrayRank() != 0;
- }
-
- int32_t GetArrayRank() const {
- int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, array_rank_),
- false);
- return result;
- }
-
- void SetArrayRank(int32_t new_array_rank) {
- DCHECK_EQ(0, GetArrayRank());
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, array_rank_), new_array_rank,
- false);
+ return GetComponentType() != NULL;
}
Class* GetComponentType() const {
- DCHECK(IsArrayClass());
return GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
}
@@ -1499,20 +1486,20 @@ class MANAGED Class : public StaticStorageBase {
return that->IsPublic() || this->IsInSamePackage(that);
}
- bool IsAssignableFrom(const Class* klass) const {
- DCHECK(klass != NULL);
- if (this == klass) {
+ bool IsAssignableFrom(const Class* src) const {
+ DCHECK(src != NULL);
+ if (this == src) {
// Can always assign to things of the same type
return true;
} else if (IsObjectClass()) {
// Can assign any reference to java.lang.Object
- return !klass->IsPrimitive();
+ return !src->IsPrimitive();
} else if (IsInterface()) {
- return klass->Implements(this);
- } else if (klass->IsArrayClass()) {
- return IsAssignableFromArray(klass);
+ return src->Implements(this);
+ } else if (src->IsArrayClass()) {
+ return IsAssignableFromArray(src);
} else {
- return klass->IsSubClass(this);
+ return src->IsSubClass(this);
}
}
@@ -1912,9 +1899,8 @@ class MANAGED Class : public StaticStorageBase {
// defining class loader, or NULL for the "bootstrap" system loader
const ClassLoader* class_loader_;
- // For array classes, the class object for base element, for
- // instanceof/checkcast (for String[][][], this will be String).
- // Otherwise, NULL.
+ // For array classes, the component class object for instanceof/checkcast
+ // (for String[][][], this will be String[][]). NULL for non-array classes.
Class* component_type_;
// descriptor for the class such as "Ljava/lang/Class;" or "[C"
@@ -1988,10 +1974,6 @@ class MANAGED Class : public StaticStorageBase {
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_;
- // For array classes, the number of array dimensions, e.g. int[][]
- // is 2. Otherwise 0.
- int32_t array_rank_;
-
// Total class size; used when allocating storage on gc heap.
size_t class_size_;
@@ -2243,6 +2225,7 @@ void ObjectArray<T>::Copy(const ObjectArray<T>* src, int src_pos,
class MANAGED ClassClass : public Class {
private:
+ int32_t padding_;
int64_t serialVersionUID_;
friend struct ClassClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
@@ -2252,8 +2235,8 @@ class MANAGED StringClass : public Class {
private:
CharArray* ASCII_;
Object* CASE_INSENSITIVE_ORDER_;
- int64_t serialVersionUID_;
uint32_t REPLACEMENT_CHAR_;
+ int64_t serialVersionUID_;
friend struct StringClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
};
diff --git a/src/object_test.cc b/src/object_test.cc
index 3c8ba5c..9b6897d 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -321,6 +321,11 @@ TEST_F(ObjectTest, InstanceOf) {
EXPECT_FALSE(x->InstanceOf(Y));
EXPECT_TRUE(y->InstanceOf(X));
EXPECT_TRUE(y->InstanceOf(Y));
+
+ Class* Class_class = class_linker_->FindSystemClass("Ljava/lang/Class;");
+ Class* Object_array_class = class_linker_->FindSystemClass("[Ljava/lang/Object;");
+ EXPECT_FALSE(Class_class->InstanceOf(Object_array_class));
+ EXPECT_TRUE(Object_array_class->InstanceOf(Class_class));
}
TEST_F(ObjectTest, IsAssignableFrom) {
diff --git a/src/runtime.cc b/src/runtime.cc
index b9120fa..de94b3d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -465,7 +465,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
REGISTER(register_java_lang_Throwable);
//REGISTER(register_java_lang_VMClassLoader);
//REGISTER(register_java_lang_reflect_AccessibleObject);
- //REGISTER(register_java_lang_reflect_Array);
+ REGISTER(register_java_lang_reflect_Array);
//REGISTER(register_java_lang_reflect_Constructor);
REGISTER(register_java_lang_reflect_Field);
REGISTER(register_java_lang_reflect_Method);