diff options
| author | 2011-10-23 14:59:04 -0700 | |
|---|---|---|
| committer | 2011-10-25 00:03:03 -0700 | |
| commit | 6b4ef025af12b158d117fc80fc79acf620f411a0 (patch) | |
| tree | 223c580477cbb7bde240b599da4bbee793b8dcaf /src | |
| parent | 21b9f1355f0311b5c67bfdfa9dd63cacb1fba502 (diff) | |
Make ResolveField not rely on Field::GetType resolution
Change-Id: I10f4a874809ac9db2cd54e200cf10eb7c8979fce
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_jni.cc | 8 | ||||
| -rw-r--r-- | src/class_linker.cc | 104 | ||||
| -rw-r--r-- | src/class_linker.h | 5 | ||||
| -rw-r--r-- | src/class_linker_test.cc | 39 | ||||
| -rw-r--r-- | src/common_test.h | 2 | ||||
| -rw-r--r-- | src/compiler_test.cc | 6 | ||||
| -rw-r--r-- | src/dex_file.h | 14 | ||||
| -rw-r--r-- | src/dex_verifier.cc | 32 | ||||
| -rw-r--r-- | src/dex_verifier.h | 2 | ||||
| -rw-r--r-- | src/heap.cc | 52 | ||||
| -rw-r--r-- | src/heap.h | 15 | ||||
| -rw-r--r-- | src/java_lang_reflect_Field.cc | 52 | ||||
| -rw-r--r-- | src/jni_internal.cc | 5 | ||||
| -rw-r--r-- | src/mark_sweep.cc | 4 | ||||
| -rw-r--r-- | src/oatdump.cc | 3 | ||||
| -rw-r--r-- | src/object.cc | 187 | ||||
| -rw-r--r-- | src/object.h | 84 | ||||
| -rw-r--r-- | src/object_test.cc | 28 | ||||
| -rw-r--r-- | src/primitive.h | 120 | ||||
| -rw-r--r-- | src/reflection.cc | 92 | ||||
| -rw-r--r-- | src/reflection.h | 5 | ||||
| -rw-r--r-- | src/runtime.cc | 6 | ||||
| -rw-r--r-- | src/runtime_support.cc | 44 | ||||
| -rw-r--r-- | src/signal_catcher.cc | 8 | ||||
| -rw-r--r-- | src/thread.cc | 40 | ||||
| -rw-r--r-- | src/utils.cc | 8 | ||||
| -rw-r--r-- | src/utils.h | 2 | ||||
| -rw-r--r-- | src/utils_test.cc | 6 |
28 files changed, 583 insertions, 390 deletions
diff --git a/src/check_jni.cc b/src/check_jni.cc index c740291844..15cc16170f 100644 --- a/src/check_jni.cc +++ b/src/check_jni.cc @@ -237,12 +237,12 @@ public: if (f == NULL) { return; } - Class* f_type = f->GetType(); // check invariant that all jfieldIDs have resolved types - DCHECK(f_type != NULL); + DCHECK(f->GetType() != NULL); Class* c = o->GetClass(); - if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f_type) == NULL) { - LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f) << " not valid for an object of class " << PrettyTypeOf(o); + if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f->GetTypeDescriptor()) == NULL) { + LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f) + << " not valid for an object of class " << PrettyTypeOf(o); JniAbort(); } } diff --git a/src/class_linker.cc b/src/class_linker.cc index de35d3312c..afb6721d10 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -284,14 +284,14 @@ void ClassLinker::Init(const std::string& boot_class_path) { SetClassRoot(kJavaLangString, java_lang_String.get()); // Setup the primitive type classes. - SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z", Class::kPrimBoolean)); - SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B", Class::kPrimByte)); - SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S", Class::kPrimShort)); - SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I", Class::kPrimInt)); - SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J", Class::kPrimLong)); - SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F", Class::kPrimFloat)); - SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D", Class::kPrimDouble)); - SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Class::kPrimVoid)); + SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z", Primitive::kPrimBoolean)); + SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B", Primitive::kPrimByte)); + SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S", Primitive::kPrimShort)); + SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I", Primitive::kPrimInt)); + SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J", Primitive::kPrimLong)); + SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F", Primitive::kPrimFloat)); + SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D", Primitive::kPrimDouble)); + SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Primitive::kPrimVoid)); // Create array interface entries to populate once we can load system classes array_interfaces_ = AllocClassArray(2); @@ -343,7 +343,7 @@ void ClassLinker::Init(const std::string& boot_class_path) { // now we can use FindSystemClass // run char class through InitializePrimitiveClass to finish init - InitializePrimitiveClass(char_class.get(), "C", Class::kPrimChar); + InitializePrimitiveClass(char_class.get(), "C", Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor // Object and String need to be rerun through FindSystemClass to finish init @@ -875,7 +875,7 @@ InterfaceEntry* ClassLinker::AllocInterfaceEntry(Class* interface) { Class* ClassLinker::AllocClass(Class* java_lang_Class, size_t class_size) { DCHECK_GE(class_size, sizeof(Class)); SirtRef<Class> klass(Heap::AllocObject(java_lang_Class, class_size)->AsClass()); - klass->SetPrimitiveType(Class::kPrimNot); // default to not being primitive + klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive klass->SetClassSize(class_size); return klass.get(); } @@ -1062,7 +1062,7 @@ size_t ClassLinker::SizeOfClass(const DexFile& dex_file, DexFile::Field dex_field; dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); const DexFile::FieldId& field_id = dex_file.GetFieldId(dex_field.field_idx_); - const char* descriptor = dex_file.dexStringByTypeIdx(field_id.type_idx_); + const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); char c = descriptor[0]; if (c == 'L' || c == '[') { num_ref++; @@ -1138,7 +1138,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U); klass->SetAccessFlags(access_flags); klass->SetClassLoader(class_loader); - DCHECK(klass->GetPrimitiveType() == Class::kPrimNot); + DCHECK(klass->GetPrimitiveType() == Primitive::kPrimNot); klass->SetStatus(Class::kStatusIdx); klass->SetSuperClassTypeIdx(dex_class_def.superclass_idx_); @@ -1264,7 +1264,7 @@ void ClassLinker::LoadField(const DexFile& dex_file, // In order to access primitive types using GetTypeDuringLinking we need to // ensure they are resolved into the dex cache - const char* descriptor = dex_file.dexStringByTypeIdx(field_id.type_idx_); + const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); if (descriptor[1] == '\0') { // only the descriptors of primitive types should be 1 character long Class* resolved = ResolveType(dex_file, field_id.type_idx_, klass.get()); @@ -1430,7 +1430,7 @@ DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const { Class* ClassLinker::InitializePrimitiveClass(Class* primitive_class, const char* descriptor, - Class::PrimitiveType type) { + Primitive::Type type) { // TODO: deduce one argument from the other CHECK(primitive_class != NULL); primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); @@ -1532,7 +1532,7 @@ Class* ClassLinker::CreateArrayClass(const std::string& descriptor, Class* java_lang_Object = GetClassRoot(kJavaLangObject); new_class->SetSuperClass(java_lang_Object); new_class->SetVTable(java_lang_Object->GetVTable()); - new_class->SetPrimitiveType(Class::kPrimNot); + new_class->SetPrimitiveType(Primitive::kPrimNot); new_class->SetClassLoader(component_type->GetClassLoader()); new_class->SetStatus(Class::kStatusInitialized); // don't need to set new_class->SetObjectSize(..) @@ -1582,25 +1582,27 @@ Class* ClassLinker::CreateArrayClass(const std::string& descriptor, } Class* ClassLinker::FindPrimitiveClass(char type) { - switch (type) { - case 'B': + switch (Primitive::GetType(type)) { + case Primitive::kPrimByte: return GetClassRoot(kPrimitiveByte); - case 'C': + case Primitive::kPrimChar: return GetClassRoot(kPrimitiveChar); - case 'D': + case Primitive::kPrimDouble: return GetClassRoot(kPrimitiveDouble); - case 'F': + case Primitive::kPrimFloat: return GetClassRoot(kPrimitiveFloat); - case 'I': + case Primitive::kPrimInt: return GetClassRoot(kPrimitiveInt); - case 'J': + case Primitive::kPrimLong: return GetClassRoot(kPrimitiveLong); - case 'S': + case Primitive::kPrimShort: return GetClassRoot(kPrimitiveShort); - case 'Z': + case Primitive::kPrimBoolean: return GetClassRoot(kPrimitiveBoolean); - case 'V': + case Primitive::kPrimVoid: return GetClassRoot(kPrimitiveVoid); + case Primitive::kPrimNot: + break; } std::string printable_type(PrintableChar(type)); ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str()); @@ -2419,12 +2421,12 @@ bool ClassLinker::LinkStaticFields(SirtRef<Class>& klass) { struct LinkFieldsComparator { bool operator()(const Field* field1, const Field* field2) { // First come reference fields, then 64-bit, and finally 32-bit - const Class* type1 = field1->GetTypeDuringLinking(); - const Class* type2 = field2->GetTypeDuringLinking(); - bool isPrimitive1 = type1 != NULL && type1->IsPrimitive(); - bool isPrimitive2 = type2 != NULL && type2->IsPrimitive(); - bool is64bit1 = isPrimitive1 && (type1->IsPrimitiveLong() || type1->IsPrimitiveDouble()); - bool is64bit2 = isPrimitive2 && (type2->IsPrimitiveLong() || type2->IsPrimitiveDouble()); + Primitive::Type type1 = field1->GetPrimitiveType(); + Primitive::Type type2 = field2->GetPrimitiveType(); + bool isPrimitive1 = type1 != Primitive::kPrimNot; + bool isPrimitive2 = type2 != Primitive::kPrimNot; + bool is64bit1 = isPrimitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble); + bool is64bit2 = isPrimitive2 && (type2 == Primitive::kPrimLong || type2 == Primitive::kPrimDouble); int order1 = (!isPrimitive1 ? 0 : (is64bit1 ? 1 : 2)); int order2 = (!isPrimitive2 ? 0 : (is64bit2 ? 1 : 2)); if (order1 != order2) { @@ -2477,9 +2479,8 @@ bool ClassLinker::LinkFields(SirtRef<Class>& klass, bool is_static) { size_t num_reference_fields = 0; for (; current_field < num_fields; current_field++) { Field* field = grouped_and_sorted_fields.front(); - const Class* type = field->GetTypeDuringLinking(); - // if a field's type at this point is NULL it isn't primitive - bool isPrimitive = type != NULL && type->IsPrimitive(); + Primitive::Type type = field->GetPrimitiveType(); + bool isPrimitive = type != Primitive::kPrimNot; if (isPrimitive) { break; // past last reference, move on to the next phase } @@ -2496,10 +2497,9 @@ bool ClassLinker::LinkFields(SirtRef<Class>& klass, bool is_static) { if (current_field != num_fields && !IsAligned<8>(field_offset.Uint32Value())) { for (size_t i = 0; i < grouped_and_sorted_fields.size(); i++) { Field* field = grouped_and_sorted_fields[i]; - const Class* type = field->GetTypeDuringLinking(); - CHECK(type != NULL); // should only be working on primitive types - DCHECK(type->IsPrimitive()); - if (type->IsPrimitiveLong() || type->IsPrimitiveDouble()) { + Primitive::Type type = field->GetPrimitiveType(); + CHECK(type != Primitive::kPrimNot); // should only be working on primitive types + if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) { continue; } fields->Set(current_field++, field); @@ -2518,13 +2518,12 @@ bool ClassLinker::LinkFields(SirtRef<Class>& klass, bool is_static) { while (!grouped_and_sorted_fields.empty()) { Field* field = grouped_and_sorted_fields.front(); grouped_and_sorted_fields.pop_front(); - const Class* type = field->GetTypeDuringLinking(); - CHECK(type != NULL); // should only be working on primitive types - DCHECK(type->IsPrimitive()); + Primitive::Type type = field->GetPrimitiveType(); + CHECK(type != Primitive::kPrimNot); // should only be working on primitive types fields->Set(current_field, field); field->SetOffset(field_offset); field_offset = MemberOffset(field_offset.Uint32Value() + - ((type->IsPrimitiveLong() || type->IsPrimitiveDouble()) + ((type == Primitive::kPrimLong || type == Primitive::kPrimDouble) ? sizeof(uint64_t) : sizeof(uint32_t))); current_field++; @@ -2551,8 +2550,8 @@ bool ClassLinker::LinkFields(SirtRef<Class>& klass, bool is_static) { << " field=" << PrettyField(field) << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false); } - const Class* type = field->GetTypeDuringLinking(); - bool is_primitive = (type != NULL && type->IsPrimitive()); + Primitive::Type type = field->GetPrimitiveType(); + bool is_primitive = type != Primitive::kPrimNot; if (klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;") && field->GetName()->Equals("referent")) { is_primitive = true; // We lied above, so we have to expect a lie here. } @@ -2727,23 +2726,18 @@ Field* ClassLinker::ResolveField(const DexFile& dex_file, return NULL; } - const char* name = dex_file.dexStringById(field_id.name_idx_); - Class* field_type = ResolveType(dex_file, field_id.type_idx_, dex_cache, class_loader); - if (field_type == NULL) { - // TODO: LinkageError? - UNIMPLEMENTED(WARNING) << "Failed to resolve type of field " << name - << " in " << PrettyClass(klass); - return NULL; -} + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); if (is_static) { - resolved = klass->FindStaticField(name, field_type); + resolved = klass->FindStaticField(name, type); } else { - resolved = klass->FindInstanceField(name, field_type); + resolved = klass->FindInstanceField(name, type); } if (resolved != NULL) { dex_cache->SetResolvedField(field_idx, resolved); } else { - DCHECK(Thread::Current()->IsExceptionPending()); + DCHECK(Thread::Current()->IsExceptionPending()) + << PrettyClass(klass) << " " << name << " " << type << " " << is_static; } return resolved; } diff --git a/src/class_linker.h b/src/class_linker.h index dd781746df..e2c5921d23 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -265,13 +265,12 @@ class ClassLinker { CodeAndDirectMethods* AllocCodeAndDirectMethods(size_t length); InterfaceEntry* AllocInterfaceEntry(Class* interface); - Class* CreatePrimitiveClass(const char* descriptor, - Class::PrimitiveType type) { + Class* CreatePrimitiveClass(const char* descriptor, Primitive::Type type) { return InitializePrimitiveClass(AllocClass(sizeof(Class)), descriptor, type); } Class* InitializePrimitiveClass(Class* primitive_class, const char* descriptor, - Class::PrimitiveType type); + Primitive::Type type); Class* CreateArrayClass(const std::string& descriptor, diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index 1b43825edd..54da19fb57 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -235,6 +235,7 @@ class ClassLinkerTest : public CommonTest { EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields()); for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) { Field* field = klass->GetInstanceField(i); + ASSERT_TRUE(!field->IsPrimitiveType()); Class* field_type = field->GetType(); ASSERT_TRUE(field_type != NULL); ASSERT_TRUE(!field_type->IsPrimitive()); @@ -243,7 +244,7 @@ class ClassLinkerTest : public CommonTest { Field* field = klass->GetInstanceField(i); Class* field_type = field->GetType(); ASSERT_TRUE(field_type != NULL); - if (!field_type->IsPrimitive()) { + if (!field->IsPrimitiveType() || !field_type->IsPrimitive()) { // While Reference.referent is not primitive, the ClassLinker // treats it as such so that the garbage collector won't scan it. EXPECT_EQ(PrettyField(field), "java.lang.Object java.lang.ref.Reference.referent"); @@ -830,49 +831,49 @@ TEST_F(ClassLinkerTest, StaticFields) { EXPECT_EQ(9U, statics->NumStaticFields()); - Field* s0 = statics->FindStaticField("s0", class_linker_->FindClass("Z", class_loader.get())); + Field* s0 = statics->FindStaticField("s0", "Z"); EXPECT_TRUE(s0->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Field;")); - EXPECT_TRUE(s0->GetType()->IsPrimitiveBoolean()); + EXPECT_TRUE(s0->GetPrimitiveType() == Primitive::kPrimBoolean); EXPECT_EQ(true, s0->GetBoolean(NULL)); s0->SetBoolean(NULL, false); - Field* s1 = statics->FindStaticField("s1", class_linker_->FindClass("B", class_loader.get())); - EXPECT_TRUE(s1->GetType()->IsPrimitiveByte()); + Field* s1 = statics->FindStaticField("s1", "B"); + EXPECT_TRUE(s1->GetPrimitiveType() == Primitive::kPrimByte); EXPECT_EQ(5, s1->GetByte(NULL)); s1->SetByte(NULL, 6); - Field* s2 = statics->FindStaticField("s2", class_linker_->FindClass("C", class_loader.get())); - EXPECT_TRUE(s2->GetType()->IsPrimitiveChar()); + Field* s2 = statics->FindStaticField("s2", "C"); + EXPECT_TRUE(s2->GetPrimitiveType() == Primitive::kPrimChar); EXPECT_EQ('a', s2->GetChar(NULL)); s2->SetChar(NULL, 'b'); - Field* s3 = statics->FindStaticField("s3", class_linker_->FindClass("S", class_loader.get())); - EXPECT_TRUE(s3->GetType()->IsPrimitiveShort()); + Field* s3 = statics->FindStaticField("s3", "S"); + EXPECT_TRUE(s3->GetPrimitiveType() == Primitive::kPrimShort); EXPECT_EQ(-536, s3->GetShort(NULL)); s3->SetShort(NULL, -535); - Field* s4 = statics->FindStaticField("s4", class_linker_->FindClass("I", class_loader.get())); - EXPECT_TRUE(s4->GetType()->IsPrimitiveInt()); + Field* s4 = statics->FindStaticField("s4", "I"); + EXPECT_TRUE(s4->GetPrimitiveType() == Primitive::kPrimInt); EXPECT_EQ(2000000000, s4->GetInt(NULL)); s4->SetInt(NULL, 2000000001); - Field* s5 = statics->FindStaticField("s5", class_linker_->FindClass("J", class_loader.get())); - EXPECT_TRUE(s5->GetType()->IsPrimitiveLong()); + Field* s5 = statics->FindStaticField("s5", "J"); + EXPECT_TRUE(s5->GetPrimitiveType() == Primitive::kPrimLong); EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(NULL)); s5->SetLong(NULL, 0x34567890abcdef12LL); - Field* s6 = statics->FindStaticField("s6", class_linker_->FindClass("F", class_loader.get())); - EXPECT_TRUE(s6->GetType()->IsPrimitiveFloat()); + Field* s6 = statics->FindStaticField("s6", "F"); + EXPECT_TRUE(s6->GetPrimitiveType() == Primitive::kPrimFloat); EXPECT_EQ(0.5, s6->GetFloat(NULL)); s6->SetFloat(NULL, 0.75); - Field* s7 = statics->FindStaticField("s7", class_linker_->FindClass("D", class_loader.get())); - EXPECT_TRUE(s7->GetType()->IsPrimitiveDouble()); + Field* s7 = statics->FindStaticField("s7", "D"); + EXPECT_TRUE(s7->GetPrimitiveType() == Primitive::kPrimDouble); EXPECT_EQ(16777217, s7->GetDouble(NULL)); s7->SetDouble(NULL, 16777219); - Field* s8 = statics->FindStaticField("s8", class_linker_->FindClass("Ljava/lang/String;", class_loader.get())); - EXPECT_FALSE(s8->GetType()->IsPrimitive()); + Field* s8 = statics->FindStaticField("s8", "Ljava/lang/String;"); + EXPECT_TRUE(s8->GetPrimitiveType() == Primitive::kPrimNot); EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("android")); s8->SetObject(NULL, String::AllocFromModifiedUtf8("robot")); diff --git a/src/common_test.h b/src/common_test.h index 3f56aab0d5..928cb5137e 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -288,7 +288,7 @@ class CommonTest : public testing::Test { const StringPiece& field_name) { for (size_t i = 0; i < dex_file.NumFieldIds(); i++) { const DexFile::FieldId& field_id = dex_file.GetFieldId(i); - if (class_descriptor == dex_file.GetFieldClassDescriptor(field_id) + if (class_descriptor == dex_file.GetFieldDeclaringClassDescriptor(field_id) && field_name == dex_file.GetFieldName(field_id)) { return i; } diff --git a/src/compiler_test.cc b/src/compiler_test.cc index 35da6f2ded..d1b377a49a 100644 --- a/src/compiler_test.cc +++ b/src/compiler_test.cc @@ -91,18 +91,18 @@ TEST_F(CompilerTest, DISABLED_LARGE_CompileDexLibCore) { for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { Method* method = dex_cache->GetResolvedMethod(i); EXPECT_TRUE(method != NULL) << "method_idx=" << i - << " " << dex->GetMethodClassDescriptor(dex->GetMethodId(i)) + << " " << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) << " " << dex->GetMethodName(dex->GetMethodId(i)); EXPECT_TRUE(method->GetCode() != NULL) << "method_idx=" << i << " " - << dex->GetMethodClassDescriptor(dex->GetMethodId(i)) + << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) << " " << dex->GetMethodName(dex->GetMethodId(i)); } EXPECT_EQ(dex->NumFieldIds(), dex_cache->NumResolvedFields()); for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { Field* field = dex_cache->GetResolvedField(i); EXPECT_TRUE(field != NULL) << "field_idx=" << i - << " " << dex->GetFieldClassDescriptor(dex->GetFieldId(i)) + << " " << dex->GetFieldDeclaringClassDescriptor(dex->GetFieldId(i)) << " " << dex->GetFieldName(dex->GetFieldId(i)); } diff --git a/src/dex_file.h b/src/dex_file.h index c30c5cab6b..3acd79f916 100644 --- a/src/dex_file.h +++ b/src/dex_file.h @@ -425,19 +425,25 @@ class DexFile { return dexStringById(type_id.descriptor_idx_); } - // Returns the class descriptor string of a field id. - const char* GetFieldClassDescriptor(const FieldId& field_id) const { + // Returns the declaring class descriptor string of a field id. + const char* GetFieldDeclaringClassDescriptor(const FieldId& field_id) const { const DexFile::TypeId& type_id = GetTypeId(field_id.class_idx_); return GetTypeDescriptor(type_id); } + // Returns the class descriptor string of a field id. + const char* GetFieldTypeDescriptor(const FieldId& field_id) const { + const DexFile::TypeId& type_id = GetTypeId(field_id.type_idx_); + return GetTypeDescriptor(type_id); + } + // Returns the name of a field id. const char* GetFieldName(const FieldId& field_id) const { return dexStringById(field_id.name_idx_); } - // Returns the class descriptor string of a method id. - const char* GetMethodClassDescriptor(const MethodId& method_id) const { + // Returns the declaring class descriptor string of a method id. + const char* GetMethodDeclaringClassDescriptor(const MethodId& method_id) const { const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_); return GetTypeDescriptor(type_id); } diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc index da7f63fdb9..e4d9f84268 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc @@ -289,18 +289,18 @@ const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_ty } } -static RegType::Type RegTypeFromPrimitiveType(Class::PrimitiveType prim_type) { +static RegType::Type RegTypeFromPrimitiveType(Primitive::Type prim_type) { switch (prim_type) { - case Class::kPrimBoolean: return RegType::kRegTypeBoolean; - case Class::kPrimByte: return RegType::kRegTypeByte; - case Class::kPrimShort: return RegType::kRegTypeShort; - case Class::kPrimChar: return RegType::kRegTypeChar; - case Class::kPrimInt: return RegType::kRegTypeInteger; - case Class::kPrimLong: return RegType::kRegTypeLongLo; - case Class::kPrimFloat: return RegType::kRegTypeFloat; - case Class::kPrimDouble: return RegType::kRegTypeDoubleLo; - case Class::kPrimVoid: - default: return RegType::kRegTypeUnknown; + case Primitive::kPrimBoolean: return RegType::kRegTypeBoolean; + case Primitive::kPrimByte: return RegType::kRegTypeByte; + case Primitive::kPrimShort: return RegType::kRegTypeShort; + case Primitive::kPrimChar: return RegType::kRegTypeChar; + case Primitive::kPrimInt: return RegType::kRegTypeInteger; + case Primitive::kPrimLong: return RegType::kRegTypeLongLo; + case Primitive::kPrimFloat: return RegType::kRegTypeFloat; + case Primitive::kPrimDouble: return RegType::kRegTypeDoubleLo; + case Primitive::kPrimVoid: + default: return RegType::kRegTypeUnknown; } } @@ -2134,7 +2134,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { if (array_data[0] != Instruction::kArrayDataSignature) { Fail(VERIFY_ERROR_GENERIC) << "invalid magic for array-data"; } else { - size_t elem_width = component_type->PrimitiveSize(); + size_t elem_width = Primitive::ComponentSize(component_type->GetPrimitiveType()); // Since we don't compress the data in Dex, expect to see equal width of data stored // in the table and expected from the array class. if (array_data[1] != elem_width) { @@ -2952,7 +2952,7 @@ Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_di DCHECK(failure_ != VERIFY_ERROR_NONE); return NULL; } - const char* name = dex_file_->dexStringById(method_id.name_idx_); + const char* name = dex_file_->GetMethodName(method_id); std::string signature(dex_file_->CreateMethodDescriptor(method_id.proto_idx_, NULL)); if (is_direct) { res_method = klass->FindDirectMethod(name, signature); @@ -2989,7 +2989,7 @@ Method* DexVerifier::VerifyInvocationArgs(const Instruction::DecodedInstruction& const DexFile::MethodId& method_id = dex_file_->GetMethodId(dec_insn.vB_); const char* method_name = dex_file_->GetMethodName(method_id); std::string method_signature = dex_file_->GetMethodSignature(method_id); - const char* class_descriptor = dex_file_->GetMethodClassDescriptor(method_id); + const char* class_descriptor = dex_file_->GetMethodDeclaringClassDescriptor(method_id); Fail(VERIFY_ERROR_GENERIC) << "unable to resolve method " << dec_insn.vB_ << ": " << class_descriptor << "." << method_name << " " << method_signature; return NULL; @@ -3236,7 +3236,7 @@ Field* DexVerifier::GetStaticField(int field_idx) { const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx); Fail(VERIFY_ERROR_NO_FIELD) << "unable to resolve static field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " - << dex_file_->GetFieldClassDescriptor(field_id); + << dex_file_->GetFieldDeclaringClassDescriptor(field_id); DCHECK(Thread::Current()->IsExceptionPending()); Thread::Current()->ClearException(); return NULL; @@ -3357,7 +3357,7 @@ Field* DexVerifier::GetInstanceField(const RegType& obj_type, int field_idx) { const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx); Fail(VERIFY_ERROR_NO_FIELD) << "unable to resolve instance field " << field_idx << " (" << dex_file_->GetFieldName(field_id) << ") in " - << dex_file_->GetFieldClassDescriptor(field_id); + << dex_file_->GetFieldDeclaringClassDescriptor(field_id); DCHECK(Thread::Current()->IsExceptionPending()); Thread::Current()->ClearException(); return NULL; diff --git a/src/dex_verifier.h b/src/dex_verifier.h index 3a614d5ea5..0d86eb5dfc 100644 --- a/src/dex_verifier.h +++ b/src/dex_verifier.h @@ -35,7 +35,7 @@ class RegTypeCache; /* * RegType holds information about the type of data held in a register. For most types it's a simple - * enum. For reference types it holds a pointer to the ClassObject, and for uninitialized references + * enum. For reference types it holds a pointer to the Class*, and for uninitialized references * it holds an index into the UninitInstanceMap. */ class RegType { diff --git a/src/heap.cc b/src/heap.cc index 01ba840198..bd6d009b08 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -16,6 +16,10 @@ namespace art { +bool Heap::is_verbose_heap_ = false; + +bool Heap::is_verbose_gc_ = false; + std::vector<Space*> Heap::spaces_; Space* Heap::alloc_space_ = NULL; @@ -58,10 +62,14 @@ class ScopedHeapLock { } }; -void Heap::Init(size_t initial_size, size_t maximum_size, +void Heap::Init(bool is_verbose_heap, bool is_verbose_gc, + size_t initial_size, size_t maximum_size, const std::vector<std::string>& image_file_names) { + is_verbose_heap_ = is_verbose_heap; + is_verbose_gc_ = is_verbose_gc; + const Runtime* runtime = Runtime::Current(); - if (runtime->IsVerboseStartup()) { + if (is_verbose_heap_ || runtime->IsVerboseStartup()) { LOG(INFO) << "Heap::Init entering"; } @@ -132,7 +140,7 @@ void Heap::Init(size_t initial_size, size_t maximum_size, // make it clear that you can't use locks during heap initialization. lock_ = new Mutex("Heap lock"); - if (runtime->IsVerboseStartup()) { + if (is_verbose_heap_ || runtime->IsVerboseStartup()) { LOG(INFO) << "Heap::Init exiting"; } } @@ -283,7 +291,7 @@ void Heap::RecordFreeLocked(size_t freed_objects, size_t freed_bytes) { void Heap::RecordImageAllocations(Space* space) { const Runtime* runtime = Runtime::Current(); - if (runtime->IsVerboseStartup()) { + if (is_verbose_heap_ || runtime->IsVerboseStartup()) { LOG(INFO) << "Heap::RecordImageAllocations entering"; } DCHECK(!Runtime::Current()->IsStarted()); @@ -296,7 +304,7 @@ void Heap::RecordImageAllocations(Space* space) { live_bitmap_->Set(obj); current += RoundUp(obj->SizeOf(), kObjectAlignment); } - if (runtime->IsVerboseStartup()) { + if (is_verbose_heap_ || runtime->IsVerboseStartup()) { LOG(INFO) << "Heap::RecordImageAllocations exiting"; } } @@ -344,14 +352,12 @@ Object* Heap::AllocateLocked(Space* space, size_t size) { ++Runtime::Current()->GetStats()->gc_for_alloc_count; ++Thread::Current()->GetStats()->gc_for_alloc_count; } - LOG(INFO) << "GC_FOR_ALLOC: AllocWithoutGrowth: TODO: test"; CollectGarbageInternal(); ptr = space->AllocWithoutGrowth(size); if (ptr != NULL) { return ptr; } - LOG(INFO) << "GC_FOR_ALLOC: AllocWithGrowth: TODO: test"; // Even that didn't work; this is an exceptional state. // Try harder, growing the heap if necessary. ptr = space->AllocWithGrowth(size); @@ -361,8 +367,10 @@ Object* Heap::AllocateLocked(Space* space, size_t size) { // OLD-TODO: may want to grow a little bit more so that the amount of // free space is equal to the old free space + the // utilization slop for the new allocation. - LOG(INFO) << "Grow heap (frag case) to " << new_footprint / MB - << "for " << size << "-byte allocation"; + if (is_verbose_gc_) { + LOG(INFO) << "Grow heap (frag case) to " << new_footprint / MB + << "for " << size << "-byte allocation"; + } return ptr; } @@ -373,8 +381,10 @@ Object* Heap::AllocateLocked(Space* space, size_t size) { // cleared before throwing an OOME. // OLD-TODO: wait for the finalizers from the previous GC to finish - LOG(INFO) << "Forcing collection of SoftReferences for " - << size << "-byte allocation"; + if (is_verbose_gc_) { + LOG(INFO) << "Forcing collection of SoftReferences for " + << size << "-byte allocation"; + } CollectGarbageInternal(); ptr = space->AllocWithGrowth(size); if (ptr != NULL) { @@ -512,11 +522,15 @@ void Heap::CollectGarbageInternal() { size_t percentFree = 100 - static_cast<size_t>(100.0f * float(num_bytes_allocated_) / footprint); uint32_t duration = (t1 - t0)/1000/1000; - LOG(INFO) << "GC freed " << (is_small ? "<" : "") << kib_freed << "KiB, " - << percentFree << "% free " - << (num_bytes_allocated_/1024) << "KiB/" << (footprint/1024) << "KiB, " - << "paused " << duration << "ms"; - timings.Dump(); + if (is_verbose_gc_) { + LOG(INFO) << "GC freed " << (is_small ? "<" : "") << kib_freed << "KiB, " + << percentFree << "% free " + << (num_bytes_allocated_/1024) << "KiB/" << (footprint/1024) << "KiB, " + << "paused " << duration << "ms"; + } + if (is_verbose_heap_) { + timings.Dump(); + } } void Heap::WaitForConcurrentGcToComplete() { @@ -547,8 +561,10 @@ void Heap::WaitForConcurrentGcToComplete() { void Heap::SetIdealFootprint(size_t max_allowed_footprint) { if (max_allowed_footprint > Heap::maximum_size_) { - LOG(INFO) << "Clamp target GC heap from " << max_allowed_footprint - << " to " << Heap::maximum_size_; + if (is_verbose_gc_) { + LOG(INFO) << "Clamp target GC heap from " << max_allowed_footprint + << " to " << Heap::maximum_size_; + } max_allowed_footprint = Heap::maximum_size_; } diff --git a/src/heap.h b/src/heap.h index 433bf6ac6c..9e21272576 100644 --- a/src/heap.h +++ b/src/heap.h @@ -45,11 +45,20 @@ class Heap { // Create a heap with the requested sizes. The possible empty // image_file_names names specify Spaces to load based on // ImageWriter output. - static void Init(size_t starting_size, size_t maximum_size, + static void Init(bool is_verbose_heap, bool is_verbose_gc, + size_t starting_size, size_t maximum_size, const std::vector<std::string>& image_file_names); static void Destroy(); + static bool IsVerboseHeap() { + return is_verbose_heap_; + } + + static bool IsVerboseGc() { + return is_verbose_gc_; + } + // Allocates and initializes storage for an object instance. static Object* AllocObject(Class* klass, size_t num_bytes); @@ -187,6 +196,10 @@ class Heap { static Mutex* lock_; + static bool is_verbose_heap_; + + static bool is_verbose_gc_; + static std::vector<Space*> spaces_; // default Space for allocations diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc index 7d43b2ea94..a2f09e7b6c 100644 --- a/src/java_lang_reflect_Field.cc +++ b/src/java_lang_reflect_Field.cc @@ -30,39 +30,39 @@ jint Field_getFieldModifiers(JNIEnv* env, jobject jfield, jclass javaDeclaringCl } bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) { - switch (f->GetType()->GetPrimitiveType()) { - case Class::kPrimBoolean: + switch (f->GetPrimitiveType()) { + case Primitive::kPrimBoolean: value.z = f->GetBoolean(o); return true; - case Class::kPrimByte: + case Primitive::kPrimByte: value.b = f->GetByte(o); return true; - case Class::kPrimChar: + case Primitive::kPrimChar: value.c = f->GetChar(o); return true; - case Class::kPrimDouble: + case Primitive::kPrimDouble: value.d = f->GetDouble(o); return true; - case Class::kPrimFloat: + case Primitive::kPrimFloat: value.f = f->GetFloat(o); return true; - case Class::kPrimInt: + case Primitive::kPrimInt: value.i = f->GetInt(o); return true; - case Class::kPrimLong: + case Primitive::kPrimLong: value.j = f->GetLong(o); return true; - case Class::kPrimShort: + case Primitive::kPrimShort: value.s = f->GetShort(o); return true; - case Class::kPrimNot: + case Primitive::kPrimNot: if (allow_references) { value.l = f->GetObject(o); return true; } // Else break to report an error. break; - case Class::kPrimVoid: + case Primitive::kPrimVoid: // Never okay. break; } @@ -101,7 +101,8 @@ JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass // Widen it if necessary (and possible). JValue wide_value; Class* dst_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(dst_descriptor); - if (!ConvertPrimitiveValue(f->GetType(), dst_type, field_value, wide_value)) { + if (!ConvertPrimitiveValue(f->GetPrimitiveType(), dst_type->GetPrimitiveType(), + field_value, wide_value)) { return JValue(); } return wide_value; @@ -140,38 +141,38 @@ jboolean Field_getZField(JNIEnv* env, jobject javaField, jobject javaObj, jclass } void SetFieldValue(Object* o, Field* f, const JValue& new_value, bool allow_references) { - switch (f->GetType()->GetPrimitiveType()) { - case Class::kPrimBoolean: + switch (f->GetPrimitiveType()) { + case Primitive::kPrimBoolean: f->SetBoolean(o, new_value.z); break; - case Class::kPrimByte: + case Primitive::kPrimByte: f->SetByte(o, new_value.b); break; - case Class::kPrimChar: + case Primitive::kPrimChar: f->SetChar(o, new_value.c); break; - case Class::kPrimDouble: + case Primitive::kPrimDouble: f->SetDouble(o, new_value.d); break; - case Class::kPrimFloat: + case Primitive::kPrimFloat: f->SetFloat(o, new_value.f); break; - case Class::kPrimInt: + case Primitive::kPrimInt: f->SetInt(o, new_value.i); break; - case Class::kPrimLong: + case Primitive::kPrimLong: f->SetLong(o, new_value.j); break; - case Class::kPrimShort: + case Primitive::kPrimShort: f->SetShort(o, new_value.s); break; - case Class::kPrimNot: + case Primitive::kPrimNot: if (allow_references) { f->SetObject(o, new_value.l); break; } // Else fall through to report an error. - case Class::kPrimVoid: + case Primitive::kPrimVoid: // Never okay. Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;", "Not a primitive field: %s", PrettyField(f).c_str()); @@ -195,7 +196,8 @@ void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass j // Widen the value if necessary (and possible). JValue wide_value; Class* src_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(src_descriptor); - if (!ConvertPrimitiveValue(src_type, f->GetType(), new_value, wide_value)) { + if (!ConvertPrimitiveValue(src_type->GetPrimitiveType(), f->GetPrimitiveType(), + new_value, wide_value)) { return; } @@ -282,7 +284,7 @@ jobject Field_getField(JNIEnv* env, jobject javaField, jobject javaObj, jclass j if (!GetFieldValue(o, f, value, true)) { return NULL; } - BoxPrimitive(env, f->GetType(), value); + BoxPrimitive(env, f->GetPrimitiveType(), value); return AddLocalReference<jobject>(env, value.l); } diff --git a/src/jni_internal.cc b/src/jni_internal.cc index 0ece455a7a..0982f83850 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -336,10 +336,11 @@ jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* nam "\"%s\" or its superclasses", sig, name, class_descriptor.c_str()); return NULL; } + std::string field_type_descriptor = field_type->GetDescriptor()->ToModifiedUtf8(); if (is_static) { - field = c->FindStaticField(name, field_type); + field = c->FindStaticField(name, field_type_descriptor); } else { - field = c->FindInstanceField(name, field_type); + field = c->FindInstanceField(name, field_type_descriptor); } if (field == NULL) { std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8()); diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc index d70d10d665..4cc6b22339 100644 --- a/src/mark_sweep.cc +++ b/src/mark_sweep.cc @@ -110,7 +110,9 @@ void MarkSweep::RecursiveMark() { finger_ = reinterpret_cast<Object*>(~0); ProcessMarkStack(); timings.AddSplit("ProcessMarkStack"); - timings.Dump(); + if (Heap::IsVerboseHeap()) { + timings.Dump(); + } } void MarkSweep::ReMarkRoots() { diff --git a/src/oatdump.cc b/src/oatdump.cc index 73b92a0103..02aecfca07 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -328,9 +328,6 @@ class ImageDump { StringAppendF(&summary, "METHOD %s", PrettyMethod(method).c_str()); } else if (obj->IsField()) { Field* field = obj->AsField(); - Class* type = field->GetType(); - std::string type_string; - type_string += (type == NULL) ? "<UNKNOWN>" : type->GetDescriptor()->ToModifiedUtf8(); StringAppendF(&summary, "FIELD %s", PrettyField(field).c_str()); } else if (obj->IsArrayInstance()) { StringAppendF(&summary, "ARRAY %d", obj->AsArray()->GetLength()); diff --git a/src/object.cc b/src/object.cc index ab95885e2f..91328aaccb 100644 --- a/src/object.cc +++ b/src/object.cc @@ -102,6 +102,31 @@ Class* Field::GetTypeDuringLinking() const { return GetDeclaringClass()->GetDexCache()->GetResolvedType(GetTypeIdx()); } +bool Field::IsPrimitiveType() const { + Class* type = GetTypeDuringLinking(); + return (type == NULL || type->IsPrimitive()); +} + +Primitive::Type Field::GetPrimitiveType() const { + Class* type = GetTypeDuringLinking(); + if (type == NULL) { + return Primitive::kPrimNot; + } + return type->GetPrimitiveType(); +} + +size_t Field::PrimitiveSize() const { + return Primitive::FieldSize(GetPrimitiveType()); +} + +const char* Field::GetTypeDescriptor() const { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + const DexFile& dex_file = class_linker->FindDexFile(GetDeclaringClass()->GetDexCache()); + const char* descriptor = dex_file.dexStringByTypeIdx(GetTypeIdx()); + DCHECK(descriptor != NULL); + return descriptor; +} + Class* Field::GetType() const { if (type_ == NULL) { type_ = Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this); @@ -120,11 +145,11 @@ void Field::InitJavaFields() { } void Field::InitJavaFieldsLocked() { - GetType(); // Sets type_ as a side-effect. May throw. + GetType(); // Resolves type as a side-effect. May throw. } uint32_t Field::Get32(const Object* object) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -132,7 +157,7 @@ uint32_t Field::Get32(const Object* object) const { } void Field::Set32(Object* object, uint32_t new_value) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -140,7 +165,7 @@ void Field::Set32(Object* object, uint32_t new_value) const { } uint64_t Field::Get64(const Object* object) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -148,7 +173,7 @@ uint64_t Field::Get64(const Object* object) const { } void Field::Set64(Object* object, uint64_t new_value) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -156,7 +181,7 @@ void Field::Set64(Object* object, uint64_t new_value) const { } Object* Field::GetObj(const Object* object) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -164,7 +189,7 @@ Object* Field::GetObj(const Object* object) const { } void Field::SetObj(Object* object, const Object* new_value) const { - CHECK((object == NULL) == IsStatic()); + CHECK((object == NULL) == IsStatic()) << PrettyField(this); if (IsStatic()) { object = declaring_class_; } @@ -172,100 +197,100 @@ void Field::SetObj(Object* object, const Object* new_value) const { } bool Field::GetBoolean(const Object* object) const { - DCHECK(GetType()->IsPrimitiveBoolean()); + DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this); return Get32(object); } void Field::SetBoolean(Object* object, bool z) const { - DCHECK(GetType()->IsPrimitiveBoolean()); + DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this); Set32(object, z); } int8_t Field::GetByte(const Object* object) const { - DCHECK(GetType()->IsPrimitiveByte()); + DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this); return Get32(object); } void Field::SetByte(Object* object, int8_t b) const { - DCHECK(GetType()->IsPrimitiveByte()); + DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this); Set32(object, b); } uint16_t Field::GetChar(const Object* object) const { - DCHECK(GetType()->IsPrimitiveChar()); + DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this); return Get32(object); } void Field::SetChar(Object* object, uint16_t c) const { - DCHECK(GetType()->IsPrimitiveChar()); + DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this); Set32(object, c); } int16_t Field::GetShort(const Object* object) const { - DCHECK(GetType()->IsPrimitiveShort()); + DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this); return Get32(object); } void Field::SetShort(Object* object, int16_t s) const { - DCHECK(GetType()->IsPrimitiveShort()); + DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this); Set32(object, s); } int32_t Field::GetInt(const Object* object) const { - DCHECK(GetType()->IsPrimitiveInt()); + DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this); return Get32(object); } void Field::SetInt(Object* object, int32_t i) const { - DCHECK(GetType()->IsPrimitiveInt()) << PrettyField(this); + DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this); Set32(object, i); } int64_t Field::GetLong(const Object* object) const { - DCHECK(GetType()->IsPrimitiveLong()); + DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this); return Get64(object); } void Field::SetLong(Object* object, int64_t j) const { - DCHECK(GetType()->IsPrimitiveLong()); + DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this); Set64(object, j); } float Field::GetFloat(const Object* object) const { - DCHECK(GetType()->IsPrimitiveFloat()); + DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this); JValue float_bits; float_bits.i = Get32(object); return float_bits.f; } void Field::SetFloat(Object* object, float f) const { - DCHECK(GetType()->IsPrimitiveFloat()); + DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this); JValue float_bits; float_bits.f = f; Set32(object, float_bits.i); } double Field::GetDouble(const Object* object) const { - DCHECK(GetType()->IsPrimitiveDouble()); + DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this); JValue double_bits; double_bits.j = Get64(object); return double_bits.d; } void Field::SetDouble(Object* object, double d) const { - DCHECK(GetType()->IsPrimitiveDouble()); + DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this); JValue double_bits; double_bits.d = d; Set64(object, double_bits.j); } Object* Field::GetObject(const Object* object) const { - CHECK(!GetType()->IsPrimitive()); + CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this); return GetObj(object); } void Field::SetObject(Object* object, const Object* l) const { - CHECK(!GetType()->IsPrimitive()); + CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this); SetObj(object, l); } @@ -828,44 +853,6 @@ void Class::SetReferenceStaticOffsets(uint32_t new_reference_offsets) { new_reference_offsets, false); } -size_t Class::PrimitiveSize() const { - switch (GetPrimitiveType()) { - case kPrimBoolean: - case kPrimByte: return 1; - case kPrimChar: - case kPrimShort: return 2; - case kPrimInt: - case kPrimFloat: return 4; - case kPrimLong: - case kPrimDouble: return 8; - default: - LOG(FATAL) << "Primitive type size calculation on invalid type " << this; - return 0; - } -} - -size_t Class::PrimitiveFieldSize() const { - return PrimitiveSize() <= 4 ? 4 : 8; -} - -size_t Class::GetTypeSize(const String* descriptor) { - switch (descriptor->CharAt(0)) { - case 'B': return 1; // byte - case 'C': return 2; // char - case 'D': return 8; // double - case 'F': return 4; // float - case 'I': return 4; // int - case 'J': return 8; // long - case 'S': return 2; // short - case 'Z': return 1; // boolean - case 'L': return sizeof(Object*); - case '[': return sizeof(Array*); - default: - LOG(ERROR) << "Unknown type " << descriptor; - return 0; - } -} - bool Class::Implements(const Class* klass) const { DCHECK(klass != NULL); DCHECK(klass->IsInterface()) << PrettyClass(this); @@ -1089,9 +1076,6 @@ Method* Class::FindDeclaredVirtualMethod(String* name, String* signature) const Method* method = GetVirtualMethod(i); if (method->GetName() == name && method->GetSignature() == signature) { return method; - } else { - LOG(INFO) << "Find (" << name->ToModifiedUtf8() << ", " << signature->ToModifiedUtf8() - << ") != " << PrettyMethod(method); } } return NULL; @@ -1117,19 +1101,32 @@ Method* Class::FindVirtualMethod(String* name, String* signature) const { return NULL; } -Field* Class::FindDeclaredInstanceField(const StringPiece& name, Class* type) { +Field* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) { + // Is the field in this class? + // Interfaces are not relevant because they can't contain instance fields. + for (size_t i = 0; i < NumInstanceFields(); ++i) { + Field* f = GetInstanceField(i); + if (f->GetName()->Equals(name) && + StringPiece(f->GetTypeDescriptor()) == type) { + return f; + } + } + return NULL; +} + +Field* Class::FindDeclaredInstanceField(String* name, String* type) { // Is the field in this class? // Interfaces are not relevant because they can't contain instance fields. for (size_t i = 0; i < NumInstanceFields(); ++i) { Field* f = GetInstanceField(i); - if (f->GetName()->Equals(name) && type == f->GetType()) { + if (f->GetName() == name && type->Equals(f->GetTypeDescriptor())) { return f; } } return NULL; } -Field* Class::FindInstanceField(const StringPiece& name, Class* type) { +Field* Class::FindInstanceField(const StringPiece& name, const StringPiece& type) { // Is the field in this class, or any of its superclasses? // Interfaces are not relevant because they can't contain instance fields. for (Class* c = this; c != NULL; c = c->GetSuperClass()) { @@ -1141,18 +1138,64 @@ Field* Class::FindInstanceField(const StringPiece& name, Class* type) { return NULL; } -Field* Class::FindDeclaredStaticField(const StringPiece& name, Class* type) { +Field* Class::FindInstanceField(String* name, String* type) { + // Is the field in this class, or any of its superclasses? + // Interfaces are not relevant because they can't contain instance fields. + for (Class* c = this; c != NULL; c = c->GetSuperClass()) { + Field* f = c->FindDeclaredInstanceField(name, type); + if (f != NULL) { + return f; + } + } + return NULL; +} + +Field* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& type) { DCHECK(type != NULL); for (size_t i = 0; i < NumStaticFields(); ++i) { Field* f = GetStaticField(i); - if (f->GetName()->Equals(name) && f->GetType() == type) { + if (f->GetName()->Equals(name) && StringPiece(f->GetTypeDescriptor()) == type) { return f; } } return NULL; } -Field* Class::FindStaticField(const StringPiece& name, Class* type) { +Field* Class::FindDeclaredStaticField(String* name, String* type) { + DCHECK(type != NULL); + for (size_t i = 0; i < NumStaticFields(); ++i) { + Field* f = GetStaticField(i); + if (f->GetName() == name && type->Equals(f->GetTypeDescriptor())) { + return f; + } + } + return NULL; +} + +Field* Class::FindStaticField(const StringPiece& name, const StringPiece& type) { + // Is the field in this class (or its interfaces), or any of its + // superclasses (or their interfaces)? + for (Class* c = this; c != NULL; c = c->GetSuperClass()) { + // Is the field in this class? + Field* f = c->FindDeclaredStaticField(name, type); + if (f != NULL) { + return f; + } + + // Is this field in any of this class' interfaces? + for (int32_t i = 0; i < c->GetIfTableCount(); ++i) { + InterfaceEntry* interface_entry = c->GetIfTable()->Get(i); + Class* interface = interface_entry->GetInterface(); + f = interface->FindDeclaredStaticField(name, type); + if (f != NULL) { + return f; + } + } + } + return NULL; +} + +Field* Class::FindStaticField(String* name, String* type) { // Is the field in this class (or its interfaces), or any of its // superclasses (or their interfaces)? for (Class* c = this; c != NULL; c = c->GetSuperClass()) { diff --git a/src/object.h b/src/object.h index 752d405a06..cabaac2b0d 100644 --- a/src/object.h +++ b/src/object.h @@ -29,6 +29,7 @@ #include "logging.h" #include "macros.h" #include "offsets.h" +#include "primitive.h" #include "runtime.h" #include "stringpiece.h" #include "thread.h" @@ -425,6 +426,14 @@ class MANAGED Field : public AccessibleObject { // if type isn't yet resolved Class* GetTypeDuringLinking() const; + bool IsPrimitiveType() const; + + Primitive::Type GetPrimitiveType() const; + + size_t PrimitiveSize() const; + + const char* GetTypeDescriptor() const; + // Performs full resolution, may return null and set exceptions if type cannot // be resolved Class* GetType() const; @@ -492,9 +501,9 @@ class MANAGED Field : public AccessibleObject { Object* generic_type_; - const String* name_; + String* name_; - // Type of the field + // The possibly null type of the field mutable Class* type_; uint32_t generic_types_are_initialized_; @@ -1263,19 +1272,6 @@ class MANAGED Class : public StaticStorageBase { kStatusInitialized = 7, // ready to go }; - enum PrimitiveType { - kPrimNot = 0, - kPrimBoolean, - kPrimByte, - kPrimChar, - kPrimShort, - kPrimInt, - kPrimLong, - kPrimFloat, - kPrimDouble, - kPrimVoid, - }; - Status GetStatus() const { DCHECK_EQ(sizeof(Status), sizeof(uint32_t)); return static_cast<Status>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false)); @@ -1383,62 +1379,58 @@ class MANAGED Class : public StaticStorageBase { return (GetAccessFlags() & kAccClassIsPhantomReference) != 0; } - PrimitiveType GetPrimitiveType() const { - DCHECK_EQ(sizeof(PrimitiveType), sizeof(int32_t)); - return static_cast<PrimitiveType>( + Primitive::Type GetPrimitiveType() const { + DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t)); + return static_cast<Primitive::Type>( GetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), false)); } - void SetPrimitiveType(PrimitiveType new_type) { - DCHECK_EQ(sizeof(PrimitiveType), sizeof(int32_t)); + void SetPrimitiveType(Primitive::Type new_type) { + DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t)); SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false); } // Returns true if the class is a primitive type. bool IsPrimitive() const { - return GetPrimitiveType() != kPrimNot; + return GetPrimitiveType() != Primitive::kPrimNot; } bool IsPrimitiveBoolean() const { - return GetPrimitiveType() == kPrimBoolean; + return GetPrimitiveType() == Primitive::kPrimBoolean; } bool IsPrimitiveByte() const { - return GetPrimitiveType() == kPrimByte; + return GetPrimitiveType() == Primitive::kPrimByte; } bool IsPrimitiveChar() const { - return GetPrimitiveType() == kPrimChar; + return GetPrimitiveType() == Primitive::kPrimChar; } bool IsPrimitiveShort() const { - return GetPrimitiveType() == kPrimShort; + return GetPrimitiveType() == Primitive::kPrimShort; } bool IsPrimitiveInt() const { - return GetPrimitiveType() == kPrimInt; + return GetPrimitiveType() == Primitive::kPrimInt; } bool IsPrimitiveLong() const { - return GetPrimitiveType() == kPrimLong; + return GetPrimitiveType() == Primitive::kPrimLong; } bool IsPrimitiveFloat() const { - return GetPrimitiveType() == kPrimFloat; + return GetPrimitiveType() == Primitive::kPrimFloat; } bool IsPrimitiveDouble() const { - return GetPrimitiveType() == kPrimDouble; + return GetPrimitiveType() == Primitive::kPrimDouble; } bool IsPrimitiveVoid() const { - return GetPrimitiveType() == kPrimVoid; + return GetPrimitiveType() == Primitive::kPrimVoid; } - size_t PrimitiveFieldSize() const; - - size_t PrimitiveSize() const; - // Depth of class from java.lang.Object size_t Depth() { size_t depth = 0; @@ -1463,7 +1455,7 @@ class MANAGED Class : public StaticStorageBase { } size_t GetComponentSize() const { - return GetTypeSize(GetComponentType()->GetDescriptor()); + return Primitive::ComponentSize(GetComponentType()->GetPrimitiveType()); } bool IsObjectClass() const { @@ -1473,8 +1465,6 @@ class MANAGED Class : public StaticStorageBase { // Creates a raw object instance but does not invoke the default constructor. Object* AllocObject(); - static size_t GetTypeSize(const String* descriptor); - const String* GetDescriptor() const { const String* result = GetFieldObject<const String*>( OFFSET_OF_OBJECT_MEMBER(Class, descriptor_), false); @@ -1923,14 +1913,18 @@ class MANAGED Class : public StaticStorageBase { void SetReferenceStaticOffsets(uint32_t new_reference_offsets); // Finds the given instance field in this class or a superclass. - Field* FindInstanceField(const StringPiece& name, Class* type); + Field* FindInstanceField(const StringPiece& name, const StringPiece& type); + Field* FindInstanceField(String* name, String* type); - Field* FindDeclaredInstanceField(const StringPiece& name, Class* type); + Field* FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type); + Field* FindDeclaredInstanceField(String* name, String* type); // Finds the given static field in this class or a superclass. - Field* FindStaticField(const StringPiece& name, Class* type); + Field* FindStaticField(const StringPiece& name, const StringPiece& type); + Field* FindStaticField(String* name, String* type); - Field* FindDeclaredStaticField(const StringPiece& name, Class* type); + Field* FindDeclaredStaticField(const StringPiece& name, const StringPiece& type); + Field* FindDeclaredStaticField(String* name, String* type); pid_t GetClinitThreadId() const { DCHECK(IsIdxLoaded() || IsErroneous()); @@ -2058,8 +2052,8 @@ class MANAGED Class : public StaticStorageBase { // See also class_size_. size_t object_size_; - // primitive type index, or kPrimNot (0); set for generated prim classes - PrimitiveType primitive_type_; + // primitive type index, or Primitive::kPrimNot (0); set for generated prim classes + Primitive::Type primitive_type_; // Bitmap of offsets of ifields. uint32_t reference_instance_offsets_; @@ -2178,8 +2172,8 @@ inline size_t Object::SizeOf() const { inline void Field::SetOffset(MemberOffset num_bytes) { DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); - Class* type = GetTypeDuringLinking(); - if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) { + Primitive::Type type = GetPrimitiveType(); + if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) { DCHECK_ALIGNED(num_bytes.Uint32Value(), 8); } SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), num_bytes.Uint32Value(), false); diff --git a/src/object_test.cc b/src/object_test.cc index db1d331c3c..b09cff1f9e 100644 --- a/src/object_test.cc +++ b/src/object_test.cc @@ -434,16 +434,16 @@ TEST_F(ObjectTest, FindInstanceField) { ASSERT_TRUE(c != NULL); // Wrong type. - EXPECT_TRUE(c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("J")) == NULL); - EXPECT_TRUE(c->FindInstanceField("count", class_linker_->FindSystemClass("J")) == NULL); + EXPECT_TRUE(c->FindDeclaredInstanceField("count", "J") == NULL); + EXPECT_TRUE(c->FindInstanceField("count", "J") == NULL); // Wrong name. - EXPECT_TRUE(c->FindDeclaredInstanceField("Count", class_linker_->FindSystemClass("I")) == NULL); - EXPECT_TRUE(c->FindInstanceField("Count", class_linker_->FindSystemClass("I")) == NULL); + EXPECT_TRUE(c->FindDeclaredInstanceField("Count", "I") == NULL); + EXPECT_TRUE(c->FindInstanceField("Count", "I") == NULL); // Right name and type. - Field* f1 = c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("I")); - Field* f2 = c->FindInstanceField("count", class_linker_->FindSystemClass("I")); + Field* f1 = c->FindDeclaredInstanceField("count", "I"); + Field* f2 = c->FindInstanceField("count", "I"); EXPECT_TRUE(f1 != NULL); EXPECT_TRUE(f2 != NULL); EXPECT_EQ(f1, f2); @@ -454,9 +454,9 @@ TEST_F(ObjectTest, FindInstanceField) { c = class_linker_->FindSystemClass("Ljava/lang/StringBuilder;"); ASSERT_TRUE(c != NULL); // No StringBuilder.count... - EXPECT_TRUE(c->FindDeclaredInstanceField("count", class_linker_->FindSystemClass("I")) == NULL); + EXPECT_TRUE(c->FindDeclaredInstanceField("count", "I") == NULL); // ...but there is an AbstractStringBuilder.count. - EXPECT_TRUE(c->FindInstanceField("count", class_linker_->FindSystemClass("I")) != NULL); + EXPECT_TRUE(c->FindInstanceField("count", "I") != NULL); } TEST_F(ObjectTest, FindStaticField) { @@ -466,16 +466,16 @@ TEST_F(ObjectTest, FindStaticField) { ASSERT_TRUE(c != NULL); // Wrong type. - EXPECT_TRUE(c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("I")) == NULL); - EXPECT_TRUE(c->FindStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("I")) == NULL); + EXPECT_TRUE(c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL); + EXPECT_TRUE(c->FindStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL); // Wrong name. - EXPECT_TRUE(c->FindDeclaredStaticField("cASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")) == NULL); - EXPECT_TRUE(c->FindStaticField("cASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")) == NULL); + EXPECT_TRUE(c->FindDeclaredStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL); + EXPECT_TRUE(c->FindStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL); // Right name and type. - Field* f1 = c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")); - Field* f2 = c->FindStaticField("CASE_INSENSITIVE_ORDER", class_linker_->FindSystemClass("Ljava/util/Comparator;")); + Field* f1 = c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;"); + Field* f2 = c->FindStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;"); EXPECT_TRUE(f1 != NULL); EXPECT_TRUE(f2 != NULL); EXPECT_EQ(f1, f2); diff --git a/src/primitive.h b/src/primitive.h new file mode 100644 index 0000000000..259378df95 --- /dev/null +++ b/src/primitive.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ART_SRC_PRIMITIVE_H_ +#define ART_SRC_PRIMITIVE_H_ + +#include <sys/types.h> + +#include "logging.h" +#include "macros.h" + +namespace art { + +class Object; + +class Primitive { + public: + enum Type { + kPrimNot = 0, + kPrimBoolean, + kPrimByte, + kPrimChar, + kPrimShort, + kPrimInt, + kPrimLong, + kPrimFloat, + kPrimDouble, + kPrimVoid, + }; + + static Type GetType(char type) { + switch (type) { + case 'B': + return kPrimByte; + case 'C': + return kPrimChar; + case 'D': + return kPrimDouble; + case 'F': + return kPrimFloat; + case 'I': + return kPrimInt; + case 'J': + return kPrimLong; + case 'S': + return kPrimShort; + case 'Z': + return kPrimBoolean; + case 'V': + return kPrimVoid; + default: + return kPrimNot; + } + } + + static size_t ComponentSize(Type type) { + switch (type) { + case kPrimBoolean: + case kPrimByte: return 1; + case kPrimChar: + case kPrimShort: return 2; + case kPrimInt: + case kPrimFloat: return 4; + case kPrimLong: + case kPrimDouble: return 8; + case kPrimNot: return sizeof(Object*); + default: + LOG(FATAL) << "Invalid type " << static_cast<int>(type); + return 0; + } + } + + static size_t FieldSize(Type type) { + return ComponentSize(type) <= 4 ? 4 : 8; + } + + static char DescriptorChar(Type type) { + switch (type) { + case kPrimBoolean: + return 'Z'; + case kPrimByte: + return 'B'; + case kPrimChar: + return 'C'; + case kPrimShort: + return 'S'; + case kPrimInt: + return 'I'; + case kPrimFloat: + return 'J'; + case kPrimLong: + return 'J'; + case kPrimDouble: + return 'D'; + default: + LOG(FATAL) << "Primitive char conversion on invalid type " << static_cast<int>(type); + return 0; + } + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive); +}; + +} // namespace art + +#endif // ART_SRC_PRIMITIVE_H_ diff --git a/src/reflection.cc b/src/reflection.cc index 86b4b095f8..b367ad3049 100644 --- a/src/reflection.cc +++ b/src/reflection.cc @@ -114,7 +114,7 @@ jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobj } // Box if necessary and return. - BoxPrimitive(env, m->GetReturnType(), value); + BoxPrimitive(env, m->GetReturnType()->GetPrimitiveType(), value); return AddLocalReference<jobject>(env, value.l); } @@ -153,66 +153,65 @@ bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) { * Returns the width in 32-bit words of the destination primitive, or * -1 if the conversion is not allowed. */ -bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst) { - Class::PrimitiveType srcType = src_class->GetPrimitiveType(); - Class::PrimitiveType dstType = dst_class->GetPrimitiveType(); +bool ConvertPrimitiveValue(Primitive::Type srcType, Primitive::Type dstType, + const JValue& src, JValue& dst) { switch (dstType) { - case Class::kPrimBoolean: - case Class::kPrimChar: - case Class::kPrimByte: + case Primitive::kPrimBoolean: + case Primitive::kPrimChar: + case Primitive::kPrimByte: if (srcType == dstType) { dst.i = src.i; return true; } break; - case Class::kPrimShort: - if (srcType == Class::kPrimByte || srcType == Class::kPrimShort) { + case Primitive::kPrimShort: + if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimShort) { dst.i = src.i; return true; } break; - case Class::kPrimInt: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + case Primitive::kPrimInt: + if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar || + srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) { dst.i = src.i; return true; } break; - case Class::kPrimLong: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + case Primitive::kPrimLong: + if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar || + srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) { dst.j = src.i; return true; - } else if (srcType == Class::kPrimLong) { + } else if (srcType == Primitive::kPrimLong) { dst.j = src.j; return true; } break; - case Class::kPrimFloat: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + case Primitive::kPrimFloat: + if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar || + srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) { dst.f = src.i; return true; - } else if (srcType == Class::kPrimLong) { + } else if (srcType == Primitive::kPrimLong) { dst.f = src.j; return true; - } else if (srcType == Class::kPrimFloat) { + } else if (srcType == Primitive::kPrimFloat) { dst.i = src.i; return true; } break; - case Class::kPrimDouble: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + case Primitive::kPrimDouble: + if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar || + srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) { dst.d = src.i; return true; - } else if (srcType == Class::kPrimLong) { + } else if (srcType == Primitive::kPrimLong) { dst.d = src.j; return true; - } else if (srcType == Class::kPrimFloat) { + } else if (srcType == Primitive::kPrimFloat) { dst.d = src.f; return true; - } else if (srcType == Class::kPrimDouble) { + } else if (srcType == Primitive::kPrimDouble) { dst.j = src.j; return true; } @@ -221,59 +220,59 @@ bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src break; } Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;", - "invalid primitive conversion from %s to %s", - PrettyDescriptor(src_class->GetDescriptor()).c_str(), - PrettyDescriptor(dst_class->GetDescriptor()).c_str()); + "invalid primitive conversion from %s to %s", + PrettyDescriptor(srcType).c_str(), + PrettyDescriptor(dstType).c_str()); return false; } -void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value) { - if (!src_class->IsPrimitive()) { +void BoxPrimitive(JNIEnv* env, Primitive::Type src_class, JValue& value) { + if (src_class == Primitive::kPrimNot) { return; } Method* m = NULL; UniquePtr<byte[]> args(new byte[8]); memset(&args[0], 0, 8); - switch (src_class->GetPrimitiveType()) { - case Class::kPrimBoolean: + switch (src_class) { + case Primitive::kPrimBoolean: m = gBoolean_valueOf; *reinterpret_cast<uint32_t*>(&args[0]) = value.z; break; - case Class::kPrimByte: + case Primitive::kPrimByte: m = gByte_valueOf; *reinterpret_cast<uint32_t*>(&args[0]) = value.b; break; - case Class::kPrimChar: + case Primitive::kPrimChar: m = gCharacter_valueOf; *reinterpret_cast<uint32_t*>(&args[0]) = value.c; break; - case Class::kPrimDouble: + case Primitive::kPrimDouble: m = gDouble_valueOf; *reinterpret_cast<double*>(&args[0]) = value.d; break; - case Class::kPrimFloat: + case Primitive::kPrimFloat: m = gFloat_valueOf; *reinterpret_cast<float*>(&args[0]) = value.f; break; - case Class::kPrimInt: + case Primitive::kPrimInt: m = gInteger_valueOf; *reinterpret_cast<uint32_t*>(&args[0]) = value.i; break; - case Class::kPrimLong: + case Primitive::kPrimLong: m = gLong_valueOf; *reinterpret_cast<uint64_t*>(&args[0]) = value.j; break; - case Class::kPrimShort: + case Primitive::kPrimShort: m = gShort_valueOf; *reinterpret_cast<uint32_t*>(&args[0]) = value.s; break; - case Class::kPrimVoid: + case Primitive::kPrimVoid: // There's no such thing as a void field, and void methods invoked via reflection return null. value.l = NULL; return; default: - LOG(FATAL) << PrettyClass(src_class); + LOG(FATAL) << static_cast<int>(src_class); } Thread* self = Thread::Current(); @@ -282,7 +281,7 @@ void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value) { } bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value) { - if (dst_class->GetPrimitiveType() == Class::kPrimNot) { + if (!dst_class->IsPrimitive()) { if (o != NULL && !o->InstanceOf(dst_class)) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "expected object of type %s, but got %s", @@ -292,7 +291,7 @@ bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_va } unboxed_value.l = o; return true; - } else if (dst_class->GetPrimitiveType() == Class::kPrimVoid) { + } else if (dst_class->GetPrimitiveType() == Primitive::kPrimVoid) { Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", "can't unbox to void"); return false; @@ -339,7 +338,8 @@ bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_va return false; } - return ConvertPrimitiveValue(src_class, dst_class, boxed_value, unboxed_value); + return ConvertPrimitiveValue(src_class->GetPrimitiveType(), dst_class->GetPrimitiveType(), + boxed_value, unboxed_value); } } // namespace art diff --git a/src/reflection.h b/src/reflection.h index 2d18331d99..e0263bdb8f 100644 --- a/src/reflection.h +++ b/src/reflection.h @@ -18,6 +18,7 @@ #define ART_SRC_REFLECTION_H_ #include "jni.h" +#include "primitive.h" namespace art { @@ -26,10 +27,10 @@ union JValue; class Object; void InitBoxingMethods(JNIEnv* env); -void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value); +void BoxPrimitive(JNIEnv* env, Primitive::Type src_class, JValue& value); bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value); -bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst); +bool ConvertPrimitiveValue(Primitive::Type src_class, Primitive::Type dst_class, const JValue& src, JValue& dst); jobject InvokeMethod(JNIEnv* env, jobject method, jobject receiver, jobject args, jobject params); diff --git a/src/runtime.cc b/src/runtime.cc index 5f2eddd4d1..c777fa1836 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -495,7 +495,11 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { thread_list_ = new ThreadList(options->IsVerbose("thread")); intern_table_ = new InternTable; - Heap::Init(options->heap_initial_size_, options->heap_maximum_size_, options->images_); + Heap::Init(options->IsVerbose("heap"), + options->IsVerbose("gc"), + options->heap_initial_size_, + options->heap_maximum_size_, + options->images_); BlockSignals(); diff --git a/src/runtime_support.cc b/src/runtime_support.cc index c7140f1593..35d1103b55 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -184,7 +184,7 @@ static std::string FieldNameFromIndex(const Method* method, uint32_t ref, const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache()); const DexFile::FieldId& id = dex_file.GetFieldId(ref); - std::string class_name(PrettyDescriptor(dex_file.GetFieldClassDescriptor(id))); + std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id))); const char* field_name = dex_file.dexStringById(id.name_idx_); if (!access) { return class_name + "." + field_name; @@ -206,7 +206,7 @@ static std::string MethodNameFromIndex(const Method* method, uint32_t ref, const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache()); const DexFile::MethodId& id = dex_file.GetMethodId(ref); - std::string class_name(PrettyDescriptor(dex_file.GetMethodClassDescriptor(id))); + std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id))); const char* method_name = dex_file.dexStringById(id.name_idx_); if (!access) { return class_name + "." + method_name; @@ -496,16 +496,14 @@ extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* ref Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int32_t))) { + if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int32_t))) { return field->Get32(NULL); } } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (field != NULL) { - Class* type = field->GetType(); - if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int32_t)) { + if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int32_t)) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted read of 32-bit primitive on field '%s'", PrettyField(field, true).c_str()); @@ -520,16 +518,14 @@ extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* ref Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int64_t))) { + if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int64_t))) { return field->Get64(NULL); } } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (field != NULL) { - Class* type = field->GetType(); - if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) { + if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int64_t)) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted read of 64-bit primitive on field '%s'", PrettyField(field, true).c_str()); @@ -544,16 +540,14 @@ extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* ref Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(!type->IsPrimitive())) { + if (LIKELY(!field->IsPrimitiveType())) { return field->GetObj(NULL); } } FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (field != NULL) { - Class* type = field->GetType(); - if (type->IsPrimitive()) { + if (field->IsPrimitiveType()) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted read of reference on primitive field '%s'", PrettyField(field, true).c_str()); @@ -568,8 +562,7 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, const Method* referrer uint32_t new_value, Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int32_t))) { + if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int32_t))) { field->Set32(NULL, new_value); return 0; // success } @@ -577,8 +570,7 @@ extern "C" int artSet32StaticFromCode(uint32_t field_idx, const Method* referrer FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (field != NULL) { - Class* type = field->GetType(); - if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int32_t)) { + if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int32_t)) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted write of 32-bit primitive to field '%s'", PrettyField(field, true).c_str()); @@ -594,8 +586,7 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer uint64_t new_value, Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int64_t))) { + if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int64_t))) { field->Set64(NULL, new_value); return 0; // success } @@ -603,8 +594,7 @@ extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (UNLIKELY(!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t))) { + if (UNLIKELY(!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int64_t))) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted write of 64-bit primitive to field '%s'", PrettyField(field, true).c_str()); @@ -620,8 +610,7 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, const Method* referre Object* new_value, Thread* self, Method** sp) { Field* field = FindFieldFast(field_idx, referrer); if (LIKELY(field != NULL)) { - Class* type = field->GetType(); - if (LIKELY(!type->IsPrimitive())) { + if (LIKELY(!field->IsPrimitiveType())) { field->SetObj(NULL, new_value); return 0; // success } @@ -629,8 +618,7 @@ extern "C" int artSetObjStaticFromCode(uint32_t field_idx, const Method* referre FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); field = FindFieldFromCode(field_idx, referrer, true); if (field != NULL) { - Class* type = field->GetType(); - if (type->IsPrimitive()) { + if (field->IsPrimitiveType()) { self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", "Attempted write of reference to primitive field '%s'", PrettyField(field, true).c_str()); @@ -1021,7 +1009,7 @@ extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver, uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize)); val.j = (val.j & 0xffffffffULL) | (high_half << 32); } - BoxPrimitive(env, param_type, val); + BoxPrimitive(env, param_type->GetPrimitiveType(), val); if (self->IsExceptionPending()) { return; } @@ -1040,7 +1028,7 @@ extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver, obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize))); } else { JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize)); - BoxPrimitive(env, param_type, val); + BoxPrimitive(env, param_type->GetPrimitiveType(), val); if (self->IsExceptionPending()) { return; } diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc index 851aab75b9..41d0fe4085 100644 --- a/src/signal_catcher.cc +++ b/src/signal_catcher.cc @@ -116,9 +116,11 @@ void SignalCatcher::HandleSigQuit() { runtime->Dump(os); - std::string maps; - if (ReadFileToString("/proc/self/maps", &maps)) { - os << "/proc/self/maps:\n" << maps; + if (false) { + std::string maps; + if (ReadFileToString("/proc/self/maps", &maps)) { + os << "/proc/self/maps:\n" << maps; + } } os << "----- end " << getpid() << " -----\n"; diff --git a/src/thread.cc b/src/thread.cc index 27361409b1..f4ca2abb63 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -642,9 +642,9 @@ Class* FindClassOrDie(ClassLinker* class_linker, const char* descriptor) { } // TODO: make more accessible? -Field* FindFieldOrDie(Class* c, const char* name, Class* type) { - Field* f = c->FindDeclaredInstanceField(name, type); - CHECK(f != NULL) << PrettyClass(c) << " " << name << " " << PrettyClass(type); +Field* FindFieldOrDie(Class* c, const char* name, const char* descriptor) { + Field* f = c->FindDeclaredInstanceField(name, descriptor); + CHECK(f != NULL) << PrettyClass(c) << " " << name << " " << descriptor; return f; } @@ -659,25 +659,21 @@ void Thread::FinishStartup() { // Now the ClassLinker is ready, we can find the various Class*, Field*, and Method*s we need. ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Class* boolean_class = FindPrimitiveClassOrDie(class_linker, 'Z'); - Class* int_class = FindPrimitiveClassOrDie(class_linker, 'I'); - Class* ClassLoader_class = FindClassOrDie(class_linker, "Ljava/lang/ClassLoader;"); - Class* String_class = FindClassOrDie(class_linker, "Ljava/lang/String;"); Class* Thread_class = FindClassOrDie(class_linker, "Ljava/lang/Thread;"); Class* ThreadGroup_class = FindClassOrDie(class_linker, "Ljava/lang/ThreadGroup;"); Class* UncaughtExceptionHandler_class = FindClassOrDie(class_linker, "Ljava/lang/Thread$UncaughtExceptionHandler;"); gThreadLock = FindClassOrDie(class_linker, "Ljava/lang/ThreadLock;"); gThrowable = FindClassOrDie(class_linker, "Ljava/lang/Throwable;"); - gThread_daemon = FindFieldOrDie(Thread_class, "daemon", boolean_class); - gThread_group = FindFieldOrDie(Thread_class, "group", ThreadGroup_class); - gThread_lock = FindFieldOrDie(Thread_class, "lock", gThreadLock); - gThread_name = FindFieldOrDie(Thread_class, "name", String_class); - gThread_priority = FindFieldOrDie(Thread_class, "priority", int_class); - gThread_uncaughtHandler = FindFieldOrDie(Thread_class, "uncaughtHandler", UncaughtExceptionHandler_class); - gThread_vmData = FindFieldOrDie(Thread_class, "vmData", int_class); - gThreadGroup_name = FindFieldOrDie(ThreadGroup_class, "name", String_class); - gThreadLock_thread = FindFieldOrDie(gThreadLock, "thread", Thread_class); + gThread_daemon = FindFieldOrDie(Thread_class, "daemon", "Z"); + gThread_group = FindFieldOrDie(Thread_class, "group", "Ljava/lang/ThreadGroup;"); + gThread_lock = FindFieldOrDie(Thread_class, "lock", "Ljava/lang/ThreadLock;"); + gThread_name = FindFieldOrDie(Thread_class, "name", "Ljava/lang/String;"); + gThread_priority = FindFieldOrDie(Thread_class, "priority", "I"); + gThread_uncaughtHandler = FindFieldOrDie(Thread_class, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;"); + gThread_vmData = FindFieldOrDie(Thread_class, "vmData", "I"); + gThreadGroup_name = FindFieldOrDie(ThreadGroup_class, "name", "Ljava/lang/String;"); + gThreadLock_thread = FindFieldOrDie(gThreadLock, "thread", "Ljava/lang/Thread;"); gThread_run = FindMethodOrDie(Thread_class, "run", "()V"); gThreadGroup_removeThread = FindMethodOrDie(ThreadGroup_class, "removeThread", "(Ljava/lang/Thread;)V"); @@ -688,7 +684,7 @@ void Thread::FinishStartup() { Thread* self = Thread::Current(); self->CreatePeer("main", false); - const Field* Thread_contextClassLoader = FindFieldOrDie(Thread_class , "contextClassLoader", ClassLoader_class); + const Field* Thread_contextClassLoader = FindFieldOrDie(Thread_class , "contextClassLoader", "Ljava/lang/ClassLoader;"); Thread_contextClassLoader->SetObject(self->GetPeer(), self->GetClassLoaderOverride()); } @@ -1235,7 +1231,15 @@ Thread* Thread::CurrentFromGdb() { } void Thread::DumpFromGdb() const { - Dump(std::cerr); + std::ostringstream ss; + Dump(ss); + std::string str = ss.str(); + // log to stderr for debugging command line processes + std::cerr << str; +#ifdef HAVE_ANDROID_OS + // log to logcat for debugging frameworks processes + LOG(INFO) << str; +#endif } class CatchBlockStackVisitor : public Thread::StackVisitor { diff --git a/src/utils.cc b/src/utils.cc index 3922033dd7..a74e2310a7 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -110,13 +110,19 @@ std::string PrettyDescriptor(const std::string& descriptor) { return result; } +std::string PrettyDescriptor(Primitive::Type type) { + char descriptor_char = Primitive::DescriptorChar(type); + std::string descriptor_string(1, descriptor_char); + return PrettyDescriptor(descriptor_string); +} + std::string PrettyField(const Field* f, bool with_type) { if (f == NULL) { return "null"; } std::string result; if (with_type) { - result += PrettyDescriptor(f->GetType()->GetDescriptor()); + result += PrettyDescriptor(f->GetTypeDescriptor()); result += ' '; } result += PrettyDescriptor(f->GetDeclaringClass()->GetDescriptor()); diff --git a/src/utils.h b/src/utils.h index 53a0378da1..66cda54323 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,6 +5,7 @@ #include "globals.h" #include "logging.h" +#include "primitive.h" #include "stringpiece.h" #include "stringprintf.h" @@ -156,6 +157,7 @@ static inline std::string PrintableString(const StringT& s) { // "java.lang.String[]", and so forth. std::string PrettyDescriptor(const String* descriptor); std::string PrettyDescriptor(const std::string& descriptor); +std::string PrettyDescriptor(Primitive::Type type); // Returns a human-readable signature for 'f'. Something like "a.b.C.f" or // "int a.b.C.f" (depending on the value of 'with_type'). diff --git a/src/utils_test.cc b/src/utils_test.cc index f1944f0faa..df47d79aad 100644 --- a/src/utils_test.cc +++ b/src/utils_test.cc @@ -92,14 +92,12 @@ TEST_F(UtilsTest, PrettyField) { EXPECT_EQ("null", PrettyField(NULL)); Class* java_lang_String = class_linker_->FindSystemClass("Ljava/lang/String;"); - Class* int_class = class_linker_->FindPrimitiveClass('I'); - Class* char_array_class = class_linker_->FindSystemClass("[C"); Field* f; - f = java_lang_String->FindDeclaredInstanceField("count", int_class); + f = java_lang_String->FindDeclaredInstanceField("count", "I"); EXPECT_EQ("int java.lang.String.count", PrettyField(f)); EXPECT_EQ("java.lang.String.count", PrettyField(f, false)); - f = java_lang_String->FindDeclaredInstanceField("value", char_array_class); + f = java_lang_String->FindDeclaredInstanceField("value", "[C"); EXPECT_EQ("char[] java.lang.String.value", PrettyField(f)); EXPECT_EQ("java.lang.String.value", PrettyField(f, false)); } |