diff options
author | Brian Carlstrom <bdc@google.com> | 2011-09-18 01:38:59 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2011-09-18 01:56:40 -0700 |
commit | 5b8e4c810a97c9dc417142b8c6e07871ae15c797 (patch) | |
tree | 1a28a30bfca5e29d2abb33ad8fa27e66ab9beae9 | |
parent | 3a7b4f26387b3529899f3cf16cdd6f1e200ded80 (diff) | |
download | art-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.mk | 1 | ||||
-rw-r--r-- | src/class_linker.cc | 79 | ||||
-rw-r--r-- | src/class_linker.h | 8 | ||||
-rw-r--r-- | src/class_linker_test.cc | 235 | ||||
-rw-r--r-- | src/dex_file.cc | 2 | ||||
-rw-r--r-- | src/dex_verifier.cc | 259 | ||||
-rw-r--r-- | src/java_lang_Class.cc | 19 | ||||
-rw-r--r-- | src/java_lang_System.cc | 6 | ||||
-rw-r--r-- | src/java_lang_reflect_Array.cc | 160 | ||||
-rw-r--r-- | src/jni_internal_test.cc | 2 | ||||
-rw-r--r-- | src/object.cc | 41 | ||||
-rw-r--r-- | src/object.h | 45 | ||||
-rw-r--r-- | src/object_test.cc | 5 | ||||
-rw-r--r-- | src/runtime.cc | 2 |
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); |