diff options
38 files changed, 543 insertions, 674 deletions
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index ae4cbd85ab..f2be4fb655 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -379,8 +379,11 @@ class ElfCompilationUnitWriter { } // Member variables. - for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) { - ArtField* field = type->GetInstanceField(i); + for (uint32_t i = 0, count = type->NumFields(); i < count; ++i) { + ArtField* field = type->GetField(i); + if (field->IsStatic()) { + continue; + } info_.StartTag(DW_TAG_member); WriteName(field->GetName()); WriteLazyType(field->GetTypeDescriptor()); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index ccebfa9c07..fc139aa000 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -67,9 +67,9 @@ bool DexCompilationUnit::RequiresConstructorBarrier() const { // Decoding class data can be slow, so iterate over fields of the compiling class if resolved. ScopedObjectAccess soa(Thread::Current()); ObjPtr<mirror::Class> compiling_class = GetCompilingClass().Get(); - for (size_t i = 0, size = compiling_class->NumInstanceFields(); i != size; ++i) { - ArtField* field = compiling_class->GetInstanceField(i); - if (field->IsFinal()) { + for (size_t i = 0, size = compiling_class->NumFields(); i != size; ++i) { + ArtField* field = compiling_class->GetField(i); + if (field->IsFinal() && !field->IsStatic()) { return true; } } diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 5281346644..201841a5b4 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -804,7 +804,7 @@ HInliner::InlineCacheType HInliner::GetInlineCacheAOT( HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker, HInstruction* receiver, uint32_t dex_pc) const { - ArtField* field = GetClassRoot<mirror::Object>(class_linker)->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>(class_linker)->GetField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); HInstanceFieldGet* result = new (graph_->GetAllocator()) HInstanceFieldGet( receiver, @@ -2452,8 +2452,7 @@ bool HInliner::ReturnTypeMoreSpecific(HInstruction* return_replacement, return true; } else if (return_replacement->IsInstanceFieldGet()) { HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet(); - if (field_get->GetFieldInfo().GetField() == - GetClassRoot<mirror::Object>()->GetInstanceField(0)) { + if (field_get->GetFieldInfo().GetField() == GetClassRoot<mirror::Object>()->GetField(0)) { return true; } } diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index ba426b5694..c8086cff99 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -1634,7 +1634,7 @@ static bool HasTrivialClinit(ObjPtr<mirror::Class> klass, PointerSize pointer_si REQUIRES_SHARED(Locks::mutator_lock_) { // Check if the class has encoded fields that trigger bytecode execution. // (Encoded fields are just a different representation of <clinit>.) - if (klass->NumStaticFields() != 0u) { + if (klass->HasStaticFields()) { DCHECK(klass->GetClassDef() != nullptr); EncodedStaticFieldValueIterator it(klass->GetDexFile(), *klass->GetClassDef()); for (; it.HasNext(); it.Next()) { diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 69a880c242..101808a193 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -1800,7 +1800,7 @@ static bool RecognizeAndSimplifyClassCheck(HCondition* condition) { { ScopedObjectAccess soa(Thread::Current()); - ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>()->GetField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); if (field_get->GetFieldInfo().GetField() != field) { return false; diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index b87f6f3975..6b91cf515e 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -173,16 +173,16 @@ IntrinsicVisitor::ValueOfInfo IntrinsicVisitor::ComputeValueOfInfo( MemberOffset IntrinsicVisitor::GetReferenceDisableIntrinsicOffset() { ScopedObjectAccess soa(Thread::Current()); - // The "disableIntrinsic" is the first static field. - ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(0); + // The "disableIntrinsic" is the first field. + ArtField* field = GetClassRoot<mirror::Reference>()->GetField(0); DCHECK_STREQ(field->GetName(), "disableIntrinsic"); return field->GetOffset(); } MemberOffset IntrinsicVisitor::GetReferenceSlowPathEnabledOffset() { ScopedObjectAccess soa(Thread::Current()); - // The "slowPathEnabled" is the second static field. - ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(1); + // The "slowPathEnabled" is the sixth field. + ArtField* field = GetClassRoot<mirror::Reference>()->GetField(5); DCHECK_STREQ(field->GetName(), "slowPathEnabled"); return field->GetOffset(); } diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 1eef0ce6d5..8ff1b89f9e 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -278,7 +278,7 @@ static void BoundTypeForClassCheck(HInstruction* check) { { ScopedObjectAccess soa(Thread::Current()); - ArtField* field = GetClassRoot<mirror::Object>()->GetInstanceField(0); + ArtField* field = GetClassRoot<mirror::Object>()->GetField(0); DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); if (field_get->GetFieldInfo().GetField() != field) { return; diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index bbb70e4ef1..fc2d94a342 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -1404,10 +1404,9 @@ class ClinitImageUpdate { } else if (can_include_in_image) { // Check whether the class is initialized and has a clinit or static fields. // Such classes must be kept too. - if (klass->IsInitialized()) { + if (klass->IsInitialized() && !klass->IsArrayClass()) { PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - if (klass->FindClassInitializer(pointer_size) != nullptr || - klass->NumStaticFields() != 0) { + if (klass->FindClassInitializer(pointer_size) != nullptr || klass->HasStaticFields()) { DCHECK(!Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass->GetDexCache())) << klass->PrettyDescriptor(); data_->image_classes_.push_back(data_->hs_.NewHandle(klass)); @@ -2275,8 +2274,9 @@ class InitializeClassVisitor : public CompilationVisitor { // cannot be initialized, no need to proceed. old_status = klass->GetStatus(); + ClassAccessor accessor(klass->GetDexFile(), klass->GetDexClassDefIndex()); bool too_many_encoded_fields = (!is_boot_image && !is_boot_image_extension) && - klass->NumStaticFields() > kMaxEncodedFields; + accessor.NumStaticFields() > kMaxEncodedFields; bool have_profile = (compiler_options.GetProfileCompilationInfo() != nullptr) && !compiler_options.GetProfileCompilationInfo()->IsEmpty(); diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 179a0bb4f7..04bf4833cd 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -761,23 +761,12 @@ ImageWriter::Bin ImageWriter::GetImageBin(mirror::Object* object) { // If the class's static fields are all final, put it into a separate bin // since it's very likely it will stay clean. - uint32_t num_static_fields = as_klass->NumStaticFields(); - if (num_static_fields == 0) { + auto fields = as_klass->GetFields(); + bool all_final = std::all_of(fields.begin(), + fields.end(), + [](ArtField& f) { return !f.IsStatic() || f.IsFinal(); }); + if (all_final) { bin = Bin::kClassInitializedFinalStatics; - } else { - // Maybe all the statics are final? - bool all_final = true; - for (uint32_t i = 0; i < num_static_fields; ++i) { - ArtField* field = as_klass->GetStaticField(i); - if (!field->IsFinal()) { - all_final = false; - break; - } - } - - if (all_final) { - bin = Bin::kClassInitializedFinalStatics; - } } } } else if (!klass->HasSuperClass()) { @@ -1415,28 +1404,24 @@ void ImageWriter::RecordNativeRelocations(ObjPtr<mirror::Class> klass, size_t oa // Extra consistency check: no boot loader classes should be left! CHECK(!klass->IsBootStrapClassLoaded()) << klass->PrettyClass(); } - LengthPrefixedArray<ArtField>* fields[] = { - klass->GetSFieldsPtr(), klass->GetIFieldsPtr(), - }; ImageInfo& image_info = GetImageInfo(oat_index); - for (LengthPrefixedArray<ArtField>* cur_fields : fields) { - // Total array length including header. - if (cur_fields != nullptr) { - // Forward the entire array at once. - size_t offset = image_info.GetBinSlotSize(Bin::kArtField); - DCHECK(!IsInBootImage(cur_fields)); - bool inserted = - native_object_relocations_.insert(std::make_pair( - cur_fields, - NativeObjectRelocation{ - oat_index, offset, NativeObjectRelocationType::kArtFieldArray - })).second; - CHECK(inserted) << "Field array " << cur_fields << " already forwarded"; - const size_t size = LengthPrefixedArray<ArtField>::ComputeSize(cur_fields->size()); - offset += size; - image_info.IncrementBinSlotSize(Bin::kArtField, size); - DCHECK_EQ(offset, image_info.GetBinSlotSize(Bin::kArtField)); - } + LengthPrefixedArray<ArtField>* fields = klass->GetFieldsPtr(); + // Total array length including header. + if (fields != nullptr) { + // Forward the entire array at once. + size_t offset = image_info.GetBinSlotSize(Bin::kArtField); + DCHECK(!IsInBootImage(fields)); + bool inserted = + native_object_relocations_.insert(std::make_pair( + fields, + NativeObjectRelocation{ + oat_index, offset, NativeObjectRelocationType::kArtFieldArray + })).second; + CHECK(inserted) << "Field array " << fields << " already forwarded"; + const size_t size = LengthPrefixedArray<ArtField>::ComputeSize(fields->size()); + offset += size; + image_info.IncrementBinSlotSize(Bin::kArtField, size); + DCHECK_EQ(offset, image_info.GetBinSlotSize(Bin::kArtField)); } // Visit and assign offsets for methods. size_t num_methods = klass->NumMethods(); @@ -3334,8 +3319,7 @@ T* ImageWriter::NativeLocationInImage(T* obj) { ArtField* ImageWriter::NativeLocationInImage(ArtField* src_field) { // Fields are not individually stored in the native relocation map. Use the field array. ObjPtr<mirror::Class> declaring_class = src_field->GetDeclaringClass<kWithoutReadBarrier>(); - LengthPrefixedArray<ArtField>* src_fields = - src_field->IsStatic() ? declaring_class->GetSFieldsPtr() : declaring_class->GetIFieldsPtr(); + LengthPrefixedArray<ArtField>* src_fields = declaring_class->GetFieldsPtr(); DCHECK(src_fields != nullptr); LengthPrefixedArray<ArtField>* dst_fields = NativeLocationInImage(src_fields); DCHECK(dst_fields != nullptr); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index feba70ff3a..1b0a3b552b 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -2075,8 +2075,10 @@ class ImageDumper { if (super != nullptr) { DumpFields(os, obj, super); } - for (ArtField& field : klass->GetIFields()) { - PrintField(os, &field, obj); + for (ArtField& field : klass->GetFields()) { + if (!field.IsStatic()) { + PrintField(os, &field, obj); + } } } @@ -2190,11 +2192,13 @@ class ImageDumper { } } - if (klass->NumStaticFields() != 0) { + if (klass->HasStaticFields()) { os << "STATICS:\n"; ScopedIndentation indent2(&vios_); - for (ArtField& field : klass->GetSFields()) { - PrintField(os, &field, field.GetDeclaringClass()); + for (ArtField& field : klass->GetFields()) { + if (field.IsStatic()) { + PrintField(os, &field, field.GetDeclaringClass()); + } } } } diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index 5581bc2f02..40dde5755b 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -564,9 +564,8 @@ jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env, return ERR(NULL_POINTER); } - art::IterationRange<art::StrideIterator<art::ArtField>> ifields = klass->GetIFields(); - art::IterationRange<art::StrideIterator<art::ArtField>> sfields = klass->GetSFields(); - size_t array_size = klass->NumInstanceFields() + klass->NumStaticFields(); + art::IterationRange<art::StrideIterator<art::ArtField>> fields = klass->GetFields(); + size_t array_size = klass->NumFields(); unsigned char* out_ptr; jvmtiError allocError = env->Allocate(array_size * sizeof(jfieldID), &out_ptr); @@ -576,11 +575,7 @@ jvmtiError ClassUtil::GetClassFields(jvmtiEnv* env, jfieldID* field_array = reinterpret_cast<jfieldID*>(out_ptr); size_t array_idx = 0; - for (art::ArtField& field : sfields) { - field_array[array_idx] = art::jni::EncodeArtField(&field); - ++array_idx; - } - for (art::ArtField& field : ifields) { + for (art::ArtField& field : fields) { field_array[array_idx] = art::jni::EncodeArtField(&field); ++array_idx; } diff --git a/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc index 80bfa0ff43..af74b67b17 100644 --- a/openjdkjvmti/ti_heap.cc +++ b/openjdkjvmti/ti_heap.cc @@ -352,43 +352,42 @@ class FieldVisitor { // Now visit fields for the current klass. - for (auto& static_field : klass->GetSFields()) { - if (static_field.IsPrimitiveType()) { - if (static_prim_visitor(obj, - klass, - static_field, - field_index, - user_data_)) { - return true; - } - } else { - if (static_ref_visitor(obj, - klass, - static_field, - field_index, - user_data_)) { - return true; - } - } - field_index++; - } - - for (auto& instance_field : klass->GetIFields()) { - if (instance_field.IsPrimitiveType()) { - if (instance_prim_visitor(obj, + for (auto& field : klass->GetFields()) { + if (field.IsStatic()) { + if (field.IsPrimitiveType()) { + if (static_prim_visitor(obj, klass, - instance_field, + field, field_index, user_data_)) { - return true; - } - } else { - if (instance_ref_visitor(obj, + return true; + } + } else { + if (static_ref_visitor(obj, klass, - instance_field, + field, field_index, user_data_)) { - return true; + return true; + } + } + } else { + if (field.IsPrimitiveType()) { + if (instance_prim_visitor(obj, + klass, + field, + field_index, + user_data_)) { + return true; + } + } else { + if (instance_ref_visitor(obj, + klass, + field, + field_index, + user_data_)) { + return true; + } } } field_index++; @@ -458,8 +457,7 @@ class FieldVisitor { auto visitor = [&count](art::ObjPtr<art::mirror::Class> inf_klass) REQUIRES_SHARED(art::Locks::mutator_lock_) { DCHECK(inf_klass->IsInterface()); - DCHECK_EQ(0u, inf_klass->NumInstanceFields()); - count += inf_klass->NumStaticFields(); + count += inf_klass->NumFields(); }; RecursiveInterfaceVisit<decltype(visitor)>::VisitStatic(art::Thread::Current(), klass, visitor); diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 8e11d592e5..d2e022fd14 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -2585,21 +2585,18 @@ void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> } void Redefiner::ClassRedefinition::UpdateFields(art::ObjPtr<art::mirror::Class> mclass) { - // TODO The IFields & SFields pointers should be combined like the methods_ arrays were. - for (auto fields_iter : {mclass->GetIFields(), mclass->GetSFields()}) { - for (art::ArtField& field : fields_iter) { - const art::dex::TypeId* new_declaring_id = - dex_file_->FindTypeId(field.GetDeclaringClassDescriptorView()); - const art::dex::StringId* new_name_id = dex_file_->FindStringId(field.GetName()); - const art::dex::TypeId* new_type_id = dex_file_->FindTypeId(field.GetTypeDescriptorView()); - CHECK(new_name_id != nullptr && new_type_id != nullptr && new_declaring_id != nullptr); - const art::dex::FieldId* new_field_id = - dex_file_->FindFieldId(*new_declaring_id, *new_name_id, *new_type_id); - CHECK(new_field_id != nullptr); - uint32_t new_field_index = dex_file_->GetIndexForFieldId(*new_field_id); - // We only need to update the index since the other data in the ArtField cannot be updated. - field.SetDexFieldIndex(new_field_index); - } + for (art::ArtField& field : mclass->GetFields()) { + const art::dex::TypeId* new_declaring_id = + dex_file_->FindTypeId(field.GetDeclaringClassDescriptorView()); + const art::dex::StringId* new_name_id = dex_file_->FindStringId(field.GetName()); + const art::dex::TypeId* new_type_id = dex_file_->FindTypeId(field.GetTypeDescriptorView()); + CHECK(new_name_id != nullptr && new_type_id != nullptr && new_declaring_id != nullptr); + const art::dex::FieldId* new_field_id = + dex_file_->FindFieldId(*new_declaring_id, *new_name_id, *new_type_id); + CHECK(new_field_id != nullptr); + uint32_t new_field_index = dex_file_->GetIndexForFieldId(*new_field_id); + // We only need to update the index since the other data in the ArtField cannot be updated. + field.SetDexFieldIndex(new_field_index); } } @@ -2609,11 +2606,10 @@ void Redefiner::ClassRedefinition::CollectNewFieldAndMethodMappings( std::map<art::ArtField*, art::ArtField*>* field_map) { for (auto [new_cls, old_cls] : art::ZipLeft(data.GetNewClasses()->Iterate(), data.GetOldClasses()->Iterate())) { - for (art::ArtField& f : old_cls->GetSFields()) { - (*field_map)[&f] = new_cls->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor()); - } - for (art::ArtField& f : old_cls->GetIFields()) { - (*field_map)[&f] = new_cls->FindDeclaredInstanceField(f.GetName(), f.GetTypeDescriptor()); + for (art::ArtField& f : old_cls->GetFields()) { + (*field_map)[&f] = f.IsStatic() + ? new_cls->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor()) + : new_cls->FindDeclaredInstanceField(f.GetName(), f.GetTypeDescriptor()); } auto new_methods = new_cls->GetMethods(art::kRuntimePointerSize); for (art::ArtMethod& m : old_cls->GetMethods(art::kRuntimePointerSize)) { @@ -2673,12 +2669,14 @@ static void CopyFields(bool is_static, DCHECK(!source_class->IsObjectClass() && !target_class->IsObjectClass()) << "Should not be overriding object class fields. Target: " << target_class->PrettyClass() << " Source: " << source_class->PrettyClass(); - for (art::ArtField& f : (is_static ? source_class->GetSFields() : source_class->GetIFields())) { - art::ArtField* new_field = - (is_static ? target_class->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor()) - : target_class->FindDeclaredInstanceField(f.GetName(), f.GetTypeDescriptor())); - CHECK(new_field != nullptr) << "could not find new version of " << f.PrettyField(); - CopyField(target, new_field, source, f); + for (art::ArtField& f : source_class->GetFields()) { + if (f.IsStatic() == is_static) { + art::ArtField* new_field = + (is_static ? target_class->FindDeclaredStaticField(f.GetName(), f.GetTypeDescriptor()) + : target_class->FindDeclaredInstanceField(f.GetName(), f.GetTypeDescriptor())); + CHECK(new_field != nullptr) << "could not find new version of " << f.PrettyField(); + CopyField(target, new_field, source, f); + } } if (!is_static && !target_class->GetSuperClass()->IsObjectClass()) { CopyFields( @@ -2719,8 +2717,10 @@ static void ClearFields(bool is_static, art::ObjPtr<art::mirror::Class> target_class) REQUIRES(art::Locks::mutator_lock_) { DCHECK(!target_class->IsObjectClass()); - for (art::ArtField& f : (is_static ? target_class->GetSFields() : target_class->GetIFields())) { - ClearField(target, f); + for (art::ArtField& f : target_class->GetFields()) { + if (f.IsStatic() == is_static) { + ClearField(target, f); + } } if (!is_static && !target_class->GetSuperClass()->IsObjectClass()) { ClearFields(is_static, target, target_class->GetSuperClass()); @@ -2860,27 +2860,16 @@ void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDat }); } else { auto pred = [&](art::ArtField& f) REQUIRES(art::Locks::mutator_lock_) { - return std::string_view(f.GetName()) == std::string_view(field_or_method->GetName()) && - std::string_view(f.GetTypeDescriptor()) == - std::string_view(field_or_method->GetTypeDescriptor()); + return f.GetNameView() == field_or_method->GetNameView() && + f.GetTypeDescriptorView() == field_or_method->GetTypeDescriptorView(); }; - if (field_or_method->IsStatic()) { - return std::any_of( - replacement_classes_iter.begin(), - replacement_classes_iter.end(), - [&](art::ObjPtr<art::mirror::Class> cand) REQUIRES(art::Locks::mutator_lock_) { - auto sfields = cand->GetSFields(); - return std::find_if(sfields.begin(), sfields.end(), pred) != sfields.end(); - }); - } else { - return std::any_of( + return std::any_of( replacement_classes_iter.begin(), replacement_classes_iter.end(), [&](art::ObjPtr<art::mirror::Class> cand) REQUIRES(art::Locks::mutator_lock_) { - auto ifields = cand->GetIFields(); - return std::find_if(ifields.begin(), ifields.end(), pred) != ifields.end(); + auto fields = cand->GetFields(); + return std::find_if(fields.begin(), fields.end(), pred) != fields.end(); }); - } } }; // TODO Performing 2 stack-walks back to back isn't the greatest. We might want to try to combine diff --git a/perfetto_hprof/perfetto_hprof.cc b/perfetto_hprof/perfetto_hprof.cc index 7379fd66c9..0602437383 100644 --- a/perfetto_hprof/perfetto_hprof.cc +++ b/perfetto_hprof/perfetto_hprof.cc @@ -568,8 +568,9 @@ uint64_t GetObjectId(const art::mirror::Object* obj) { template <typename F> void ForInstanceReferenceField(art::mirror::Class* klass, F fn) NO_THREAD_SAFETY_ANALYSIS { - for (art::ArtField& af : klass->GetIFields()) { - if (af.IsPrimitiveType() || + for (art::ArtField& af : klass->GetFields()) { + if (af.IsStatic() || + af.IsPrimitiveType() || af.GetOffset().Uint32Value() == art::mirror::Object::ClassOffset().Uint32Value()) { continue; } diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 95d21e0eb7..1dd8c83499 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -1565,7 +1565,10 @@ static void TestFields(Thread* self, StubTest* test, Primitive::Type test_type) // Play with it... // Static fields. - for (ArtField& f : c->GetSFields()) { + for (ArtField& f : c->GetFields()) { + if (!f.IsStatic()) { + continue; + } Primitive::Type type = f.GetTypeAsPrimitiveType(); if (test_type != type) { continue; @@ -1601,7 +1604,10 @@ static void TestFields(Thread* self, StubTest* test, Primitive::Type test_type) } // Instance fields. - for (ArtField& f : c->GetIFields()) { + for (ArtField& f : c->GetFields()) { + if (f.IsStatic()) { + continue; + } Primitive::Type type = f.GetTypeAsPrimitiveType(); if (test_type != type) { continue; diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index dd86e68164..8557b13ae6 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -425,19 +425,20 @@ inline ObjPtr<mirror::String> ArtField::ResolveNameString() { template <bool kExactOffset> static inline ArtField* FindFieldWithOffset( const IterationRange<StrideIterator<ArtField>>& fields, - uint32_t field_offset) REQUIRES_SHARED(Locks::mutator_lock_) { + uint32_t field_offset, + bool is_static) REQUIRES_SHARED(Locks::mutator_lock_) { for (ArtField& field : fields) { - if (kExactOffset) { - if (field.GetOffset().Uint32Value() == field_offset) { - return &field; - } - } else { - const uint32_t offset = field.GetOffset().Uint32Value(); - Primitive::Type type = field.GetTypeAsPrimitiveType(); - const size_t field_size = Primitive::ComponentSize(type); - DCHECK_GT(field_size, 0u); - if (offset <= field_offset && field_offset < offset + field_size) { + if (field.IsStatic() == is_static) { + if (kExactOffset && field.GetOffset().Uint32Value() == field_offset) { return &field; + } else { + const uint32_t offset = field.GetOffset().Uint32Value(); + Primitive::Type type = field.GetTypeAsPrimitiveType(); + const size_t field_size = Primitive::ComponentSize(type); + DCHECK_GT(field_size, 0u); + if (offset <= field_offset && field_offset < offset + field_size) { + return &field; + } } } } @@ -448,7 +449,8 @@ template <bool kExactOffset, VerifyObjectFlags kVerifyFlags, ReadBarrierOption k inline ArtField* ArtField::FindInstanceFieldWithOffset(ObjPtr<mirror::Class> klass, uint32_t field_offset) { DCHECK(klass != nullptr); - ArtField* field = FindFieldWithOffset<kExactOffset>(klass->GetIFields(), field_offset); + ArtField* field = FindFieldWithOffset<kExactOffset>( + klass->GetFields(), field_offset, /* is_static= */ false); if (field != nullptr) { return field; } @@ -464,7 +466,7 @@ template <bool kExactOffset> inline ArtField* ArtField::FindStaticFieldWithOffset(ObjPtr<mirror::Class> klass, uint32_t field_offset) { DCHECK(klass != nullptr); - return FindFieldWithOffset<kExactOffset>(klass->GetSFields(), field_offset); + return FindFieldWithOffset<kExactOffset>(klass->GetFields(), field_offset, /* is_static= */ true); } inline ObjPtr<mirror::ClassLoader> ArtField::GetClassLoader() { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 1488cc6450..31d3acbbcd 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1102,23 +1102,29 @@ void ClassLinker::FinishInit(Thread* self) { Handle<mirror::Class> java_lang_ref_FinalizerReference = hs.NewHandle(FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;")); - ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); + ArtField* pendingNext = java_lang_ref_Reference->GetField(1); + CHECK(!pendingNext->IsStatic()); CHECK_STREQ(pendingNext->GetName(), "pendingNext"); CHECK_STREQ(pendingNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); - ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); + ArtField* queue = java_lang_ref_Reference->GetField(2); + CHECK(!queue->IsStatic()); CHECK_STREQ(queue->GetName(), "queue"); CHECK_STREQ(queue->GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); - ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); + ArtField* queueNext = java_lang_ref_Reference->GetField(3); + CHECK(!queueNext->IsStatic()); CHECK_STREQ(queueNext->GetName(), "queueNext"); CHECK_STREQ(queueNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); - ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); + ArtField* referent = java_lang_ref_Reference->GetField(4); + CHECK(!referent->IsStatic()); CHECK_STREQ(referent->GetName(), "referent"); CHECK_STREQ(referent->GetTypeDescriptor(), "Ljava/lang/Object;"); - ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); + ArtField* zombie = java_lang_ref_FinalizerReference->GetField( + java_lang_ref_FinalizerReference->NumFields() - 1); + CHECK(!zombie->IsStatic()); CHECK_STREQ(zombie->GetName(), "zombie"); CHECK_STREQ(zombie->GetTypeDescriptor(), "Ljava/lang/Object;"); @@ -2003,10 +2009,7 @@ class ImageChecker final { CHECK(class_class != nullptr) << "Null class class " << obj; if (obj_klass == class_class) { auto klass = obj->AsClass(); - for (ArtField& field : klass->GetIFields()) { - CHECK_EQ(field.GetDeclaringClass<kWithoutReadBarrier>(), klass); - } - for (ArtField& field : klass->GetSFields()) { + for (ArtField& field : klass->GetFields()) { CHECK_EQ(field.GetDeclaringClass<kWithoutReadBarrier>(), klass); } for (ArtMethod& m : klass->GetMethods(kPointerSize)) { @@ -4019,12 +4022,11 @@ void ClassLinker::LoadClass(Thread* self, // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); - LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, - allocator, - accessor.NumStaticFields()); - LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self, - allocator, - accessor.NumInstanceFields()); + LengthPrefixedArray<ArtField>* fields = + AllocArtFieldArray(self, + allocator, + accessor.NumStaticFields() + accessor.NumInstanceFields()); + size_t num_fields = 0u; size_t num_sfields = 0u; size_t num_ifields = 0u; uint32_t last_static_field_idx = 0u; @@ -4056,7 +4058,8 @@ void ClassLinker::LoadClass(Thread* self, uint32_t field_idx = field.GetIndex(); DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier. if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) { - LoadField(field, klass, &sfields->At(num_sfields)); + LoadField(field, klass, &fields->At(num_fields)); + ++num_fields; ++num_sfields; last_static_field_idx = field_idx; } @@ -4064,7 +4067,8 @@ void ClassLinker::LoadClass(Thread* self, uint32_t field_idx = field.GetIndex(); DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier. if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) { - LoadField(field, klass, &ifields->At(num_ifields)); + LoadField(field, klass, &fields->At(num_fields)); + ++num_fields; ++num_ifields; last_instance_field_idx = field_idx; } @@ -4094,24 +4098,27 @@ void ClassLinker::LoadClass(Thread* self, ++class_def_method_index; }); - if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) { + if (UNLIKELY(num_fields != accessor.NumFields())) { LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor() << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields() << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields() << ")"; - // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size. - if (sfields != nullptr) { - sfields->SetSize(num_sfields); - } - if (ifields != nullptr) { - ifields->SetSize(num_ifields); + // NOTE: Not shrinking the over-allocated fields, just setting size. + if (fields != nullptr) { + fields->SetSize(num_fields); } } - // Set the field arrays. - klass->SetSFieldsPtr(sfields); - DCHECK_EQ(klass->NumStaticFields(), num_sfields); - klass->SetIFieldsPtr(ifields); - DCHECK_EQ(klass->NumInstanceFields(), num_ifields); + if (fields != nullptr) { + // Sort the fields by dex field index to facilitate fast lookups. + std::sort(fields->begin(), + fields->end(), + [](ArtField& lhs, ArtField& rhs) { + return lhs.GetDexFieldIndex() < rhs.GetDexFieldIndex(); + }); + } + + // Set the field array. + klass->SetFieldsPtr(fields); } // Ensure that the card is marked so that remembered sets pick up native roots. WriteBarrier::ForEveryFieldWrite(klass.Get()); @@ -5304,18 +5311,18 @@ ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRun // Instance fields are inherited, but we add a couple of static fields... const size_t num_fields = 2; - LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields); - temp_klass->SetSFieldsPtr(sfields); + LengthPrefixedArray<ArtField>* fields = AllocArtFieldArray(self, allocator, num_fields); + temp_klass->SetFieldsPtr(fields); // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by // our proxy, so Class.getInterfaces doesn't return the flattened set. - ArtField& interfaces_sfield = sfields->At(0); + ArtField& interfaces_sfield = fields->At(0); interfaces_sfield.SetDexFieldIndex(0); interfaces_sfield.SetDeclaringClass(temp_klass.Get()); interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // 2. Create a static field 'throws' that holds exceptions thrown by our methods. - ArtField& throws_sfield = sfields->At(1); + ArtField& throws_sfield = fields->At(1); throws_sfield.SetDexFieldIndex(1); throws_sfield.SetDeclaringClass(temp_klass.Get()); throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); @@ -5455,7 +5462,6 @@ ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRun // Consistency checks. if (kIsDebugBuild) { - CHECK(klass->GetIFieldsPtr() == nullptr); CheckProxyConstructor(klass->GetDirectMethod(0, image_pointer_size_)); for (size_t i = 0; i < num_virtual_methods; ++i) { @@ -5467,11 +5473,11 @@ ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRun Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name)); std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces", decoded_name->ToModifiedUtf8().c_str())); - CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(0)), interfaces_field_name); + CHECK_EQ(ArtField::PrettyField(klass->GetField(0)), interfaces_field_name); std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws", decoded_name->ToModifiedUtf8().c_str())); - CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(1)), throws_field_name); + CHECK_EQ(ArtField::PrettyField(klass->GetField(1)), throws_field_name); CHECK_EQ(klass.Get()->GetProxyInterfaces(), soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)); @@ -5576,7 +5582,7 @@ bool ClassLinker::CanWeInitializeClass(ObjPtr<mirror::Class> klass, return false; } // Check if there are encoded static values needing initialization. - if (klass->NumStaticFields() != 0) { + if (klass->HasStaticFields()) { const dex::ClassDef* dex_class_def = klass->GetClassDef(); DCHECK(dex_class_def != nullptr); if (dex_class_def->static_values_off_ != 0) { @@ -5804,8 +5810,7 @@ bool ClassLinker::InitializeClass(Thread* self, } } - const size_t num_static_fields = klass->NumStaticFields(); - if (num_static_fields > 0) { + if (klass->HasStaticFields()) { const dex::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); StackHandleScope<2> hs(self); @@ -5814,8 +5819,11 @@ bool ClassLinker::InitializeClass(Thread* self, // Eagerly fill in static fields so that the we don't have to do as many expensive // Class::FindStaticField in ResolveField. - for (size_t i = 0; i < num_static_fields; ++i) { - ArtField* field = klass->GetStaticField(i); + for (size_t i = 0; i < klass->NumFields(); ++i) { + ArtField* field = klass->GetField(i); + if (!field->IsStatic()) { + continue; + } const uint32_t field_idx = field->GetDexFieldIndex(); ArtField* resolved_field = dex_cache->GetResolvedField(field_idx); if (resolved_field == nullptr) { @@ -6258,15 +6266,8 @@ bool ClassLinker::EnsureInitialized(Thread* self, void ClassLinker::FixupTemporaryDeclaringClass(ObjPtr<mirror::Class> temp_class, ObjPtr<mirror::Class> new_class) { - DCHECK_EQ(temp_class->NumInstanceFields(), 0u); - for (ArtField& field : new_class->GetIFields()) { - if (field.GetDeclaringClass() == temp_class) { - field.SetDeclaringClass(new_class); - } - } - - DCHECK_EQ(temp_class->NumStaticFields(), 0u); - for (ArtField& field : new_class->GetSFields()) { + DCHECK_EQ(temp_class->NumFields(), 0u); + for (ArtField& field : new_class->GetFields()) { if (field.GetDeclaringClass() == temp_class) { field.SetDeclaringClass(new_class); } @@ -6413,8 +6414,7 @@ bool ClassLinker::LinkClass(Thread* self, // may not see any references to the target space and clean the card for a class if another // class had the same array pointer. klass->SetMethodsPtrUnchecked(nullptr, 0, 0); - klass->SetSFieldsPtrUnchecked(nullptr); - klass->SetIFieldsPtrUnchecked(nullptr); + klass->SetFieldsPtrUnchecked(nullptr); if (UNLIKELY(h_new_class == nullptr)) { self->AssertPendingOOMException(); mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); @@ -9283,9 +9283,7 @@ bool ClassLinker::LinkFieldsHelper::LinkFields(ClassLinker* class_linker, bool is_static, size_t* class_size) { self->AllowThreadSuspension(); - const size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); - LengthPrefixedArray<ArtField>* const fields = is_static ? klass->GetSFieldsPtr() : - klass->GetIFieldsPtr(); + LengthPrefixedArray<ArtField>* const fields = klass->GetFieldsPtr(); // Initialize field_offset MemberOffset field_offset(0); @@ -9301,7 +9299,8 @@ bool ClassLinker::LinkFieldsHelper::LinkFields(ClassLinker* class_linker, } } - CHECK_EQ(num_fields == 0, fields == nullptr) << klass->PrettyClass(); + size_t num_fields = + is_static ? klass->ComputeNumStaticFields() : klass->ComputeNumInstanceFields(); // we want a relatively stable order so that adding new fields // minimizes disruption of C++ version such as Class and Method. @@ -9341,8 +9340,11 @@ bool ClassLinker::LinkFieldsHelper::LinkFields(ClassLinker* class_linker, size_t num_reference_fields = 0; size_t primitive_fields_start = num_fields; DCHECK_LE(num_fields, 1u << 16); - for (size_t i = 0; i != num_fields; ++i) { + for (size_t i = 0; i != klass->NumFields(); ++i) { ArtField* field = &fields->At(i); + if (field->IsStatic() != is_static) { + continue; + } const char* descriptor = field->GetTypeDescriptor(); FieldTypeOrder field_type_order = FieldTypeOrderFromFirstDescriptorCharacter(descriptor[0]); uint16_t field_index = dchecked_integral_cast<uint16_t>(i); @@ -9491,8 +9493,8 @@ bool ClassLinker::LinkFieldsHelper::LinkFields(ClassLinker* class_linker, // We know there are no non-reference fields in the Reference classes, and we know // that 'referent' is alphabetically last, so this is easy... CHECK_EQ(num_reference_fields, num_fields) << klass->PrettyClass(); - CHECK_STREQ(fields->At(num_fields - 1).GetName(), "referent") - << klass->PrettyClass(); + CHECK_STREQ(fields->At(klass->NumFields() - 2).GetName(), "referent"); + CHECK_STREQ(fields->At(klass->NumFields() - 1).GetName(), "slowPathEnabled"); --num_reference_fields; } @@ -9550,8 +9552,11 @@ bool ClassLinker::LinkFieldsHelper::LinkFields(ClassLinker* class_linker, num_reference_fields * sizeof(mirror::HeapReference<mirror::Object>)); MemberOffset current_ref_offset = start_ref_offset; - for (size_t i = 0; i < num_fields; i++) { + for (size_t i = 0; i < klass->NumFields(); i++) { ArtField* field = &fields->At(i); + if (field->IsStatic() != is_static) { + continue; + } VLOG(class_linker) << "LinkFields: " << (is_static ? "static" : "instance") << " class=" << klass->PrettyClass() << " field=" << field->PrettyField() << " offset=" << field->GetOffsetDuringLinking(); @@ -10182,19 +10187,16 @@ ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass, uint32_t field_idx, bool is_static) { DCHECK(dex_cache->GetClassLoader() == class_loader); - ArtField* resolved = is_static ? klass->FindStaticField(dex_cache, field_idx) - : klass->FindInstanceField(dex_cache, field_idx); - if (resolved != nullptr && + ArtField* resolved = klass->FindField(dex_cache, field_idx); + if (resolved == nullptr || + is_static != resolved->IsStatic() || hiddenapi::ShouldDenyAccessToMember(resolved, hiddenapi::AccessContext(class_loader, dex_cache), hiddenapi::AccessMethod::kLinking)) { - resolved = nullptr; - } - - if (resolved != nullptr) { - dex_cache->SetResolvedField(field_idx, resolved); + return nullptr; } + dex_cache->SetResolvedField(field_idx, resolved); return resolved; } @@ -10348,7 +10350,7 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForField( ArtField* target_field = ResolveField(method_handle.field_or_method_idx_, referrer, is_static); if (LIKELY(target_field != nullptr)) { - DCHECK_EQ(is_static, target_field->IsStatic()); + DCHECK_EQ(is_static, target_field->IsStatic()) << target_field->PrettyField(); ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass(); ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); if (UNLIKELY(!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags()))) { diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 5d5d025050..1176bb133e 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -110,8 +110,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_FALSE(primitive->IsSynthetic()); EXPECT_EQ(0U, primitive->NumDirectMethods()); EXPECT_EQ(0U, primitive->NumVirtualMethods()); - EXPECT_EQ(0U, primitive->NumInstanceFields()); - EXPECT_EQ(0U, primitive->NumStaticFields()); + EXPECT_EQ(0U, primitive->NumFields()); EXPECT_EQ(0U, primitive->NumDirectInterfaces()); EXPECT_FALSE(primitive->HasVTable()); EXPECT_EQ(0, primitive->GetIfTableCount()); @@ -156,13 +155,12 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_FALSE(JavaLangObject->IsSynthetic()); EXPECT_EQ(4U, JavaLangObject->NumDirectMethods()); EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods()); - EXPECT_EQ(2U, JavaLangObject->NumInstanceFields()); - EXPECT_STREQ(JavaLangObject->GetInstanceField(0)->GetName(), - "shadow$_klass_"); - EXPECT_STREQ(JavaLangObject->GetInstanceField(1)->GetName(), - "shadow$_monitor_"); + EXPECT_EQ(2U, JavaLangObject->NumFields()); + EXPECT_STREQ(JavaLangObject->GetField(0)->GetName(), "shadow$_klass_"); + EXPECT_FALSE(JavaLangObject->GetField(0)->IsStatic()); + EXPECT_STREQ(JavaLangObject->GetField(1)->GetName(), "shadow$_monitor_"); + EXPECT_FALSE(JavaLangObject->GetField(1)->IsStatic()); - EXPECT_EQ(0U, JavaLangObject->NumStaticFields()); EXPECT_EQ(0U, JavaLangObject->NumDirectInterfaces()); PointerSize pointer_size = class_linker_->GetImagePointerSize(); @@ -220,8 +218,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_FALSE(array->IsSynthetic()); EXPECT_EQ(0U, array->NumDirectMethods()); EXPECT_EQ(0U, array->NumVirtualMethods()); - EXPECT_EQ(0U, array->NumInstanceFields()); - EXPECT_EQ(0U, array->NumStaticFields()); + EXPECT_EQ(0U, array->NumFields()); EXPECT_EQ(2U, array->NumDirectInterfaces()); EXPECT_TRUE(array->ShouldHaveImt()); EXPECT_TRUE(array->ShouldHaveEmbeddedVTable()); @@ -343,27 +340,23 @@ class ClassLinkerTest : public CommonRuntimeTest { << "declaring class: " << method.GetDeclaringClass()->PrettyClass(); } - for (size_t i = 0; i < klass->NumInstanceFields(); i++) { - ArtField* field = klass->GetInstanceField(i); + for (size_t i = 0; i < klass->NumFields(); i++) { + ArtField* field = klass->GetField(i); AssertField(klass.Get(), field); - EXPECT_FALSE(field->IsStatic()); - } - - for (size_t i = 0; i < klass->NumStaticFields(); i++) { - ArtField* field = klass->GetStaticField(i); - AssertField(klass.Get(), field); - EXPECT_TRUE(field->IsStatic()); } // Confirm that all instances field offsets are packed together at the start. - EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields()); + EXPECT_GE(klass->ComputeNumInstanceFields(), klass->NumReferenceInstanceFields()); MemberOffset start_ref_offset = klass->GetFirstReferenceInstanceFieldOffset(); MemberOffset end_ref_offset(start_ref_offset.Uint32Value() + klass->NumReferenceInstanceFields() * sizeof(mirror::HeapReference<mirror::Object>)); MemberOffset current_ref_offset = start_ref_offset; - for (size_t i = 0; i < klass->NumInstanceFields(); i++) { - ArtField* field = klass->GetInstanceField(i); + for (size_t i = 0; i < klass->NumFields(); i++) { + ArtField* field = klass->GetField(i); + if (field->IsStatic()) { + continue; + } ObjPtr<mirror::Class> field_type = field->ResolveType(); ASSERT_TRUE(field_type != nullptr); if (!field->IsPrimitiveType()) { @@ -499,7 +492,8 @@ struct CheckOffsets { } } - size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); + size_t num_fields = + is_static ? klass->ComputeNumStaticFields() : klass->ComputeNumInstanceFields(); if (offsets.size() != num_fields) { LOG(ERROR) << "Field count mismatch:" << " class=" << class_descriptor @@ -508,17 +502,25 @@ struct CheckOffsets { error = true; } + size_t j = 0; for (size_t i = 0; i < offsets.size(); i++) { - ArtField* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i); + ArtField* field = nullptr; + do { + field = klass->GetField(j++); + } while (field->IsStatic() != is_static); std::string_view field_name(field->GetName()); if (field_name != offsets[i].java_name) { error = true; } } + j = 0; if (error) { for (size_t i = 0; i < offsets.size(); i++) { CheckOffset& offset = offsets[i]; - ArtField* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i); + ArtField* field = nullptr; + do { + field = klass->GetField(j++); + } while (field->IsStatic() != is_static); std::string_view field_name(field->GetName()); if (field_name != offsets[i].java_name) { LOG(ERROR) << "JAVA FIELD ORDER MISMATCH NEXT LINE:"; @@ -530,17 +532,25 @@ struct CheckOffsets { } } + j = 0; for (size_t i = 0; i < offsets.size(); i++) { CheckOffset& offset = offsets[i]; - ArtField* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i); + ArtField* field = nullptr; + do { + field = klass->GetField(j++); + } while (field->IsStatic() != is_static); if (field->GetOffset().Uint32Value() != offset.cpp_offset) { error = true; } } + j = 0; if (error) { for (size_t i = 0; i < offsets.size(); i++) { CheckOffset& offset = offsets[i]; - ArtField* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i); + ArtField* field = nullptr; + do { + field = klass->GetField(j++); + } while (field->IsStatic() != is_static); if (field->GetOffset().Uint32Value() != offset.cpp_offset) { LOG(ERROR) << "OFFSET MISMATCH NEXT LINE:"; } @@ -583,7 +593,7 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex"); addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex"); addOffset(OFFSETOF_MEMBER(mirror::Class, ext_data_), "extData"); - addOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, fields_), "fields"); addOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable"); addOffset(OFFSETOF_MEMBER(mirror::Class, methods_), "methods"); addOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name"); @@ -597,7 +607,6 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { addOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType"); addOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_), "referenceInstanceOffsets"); - addOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields"); addOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status"); addOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass"); addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_offset_), "virtualMethodsOffset"); @@ -975,8 +984,7 @@ TEST_F(ClassLinkerTest, FindClass) { 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->NumFields()); EXPECT_EQ(0U, MyClass->NumDirectInterfaces()); EXPECT_OBJ_PTR_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass()); @@ -1137,30 +1145,6 @@ TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) { // Take it as given that bytes and booleans have byte alignment } -TEST_F(ClassLinkerTest, ValidateBoxedTypes) { - // Validate that the "value" field is always the 0th field in each of java.lang's box classes. - // This lets UnboxPrimitive avoid searching for the field by name at runtime. - ScopedObjectAccess soa(Thread::Current()); - ScopedNullHandle<mirror::ClassLoader> class_loader; - ObjPtr<mirror::Class> c; - c = FindClass("Ljava/lang/Boolean;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Byte;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Character;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Double;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Float;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Integer;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Long;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); - c = FindClass("Ljava/lang/Short;", class_loader); - EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); -} - TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) { ScopedObjectAccess soa(Thread::Current()); StackHandleScope<3> hs(soa.Self()); @@ -1189,7 +1173,7 @@ TEST_F(ClassLinkerTest, StaticFields) { ArtMethod* clinit = statics->FindClassMethod("<clinit>", "()V", kRuntimePointerSize); EXPECT_TRUE(clinit == nullptr); - EXPECT_EQ(9U, statics->NumStaticFields()); + EXPECT_EQ(9U, statics->NumFields()); ArtField* s0 = statics->FindStaticField("s0", "Z"); EXPECT_EQ(s0->GetTypeAsPrimitiveType(), Primitive::kPrimBoolean); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 7ea675d4cf..5ceeeb75af 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3375,8 +3375,9 @@ class VerifyReferenceCardVisitor { if (!obj->IsObjectArray()) { ObjPtr<mirror::Class> klass = is_static ? obj->AsClass() : obj->GetClass(); CHECK(klass != nullptr); - for (ArtField& field : (is_static ? klass->GetSFields() : klass->GetIFields())) { - if (field.GetOffset().Int32Value() == offset.Int32Value()) { + for (ArtField& field : klass->GetFields()) { + if (is_static == field.IsStatic() && + field.GetOffset().Int32Value() == offset.Int32Value()) { LOG(ERROR) << (is_static ? "Static " : "") << "field in the live stack is " << field.PrettyField(); break; diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index cb777c895c..c799f5443b 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -54,8 +54,8 @@ ReferenceProcessor::ReferenceProcessor() static inline MemberOffset GetSlowPathFlagOffset(ObjPtr<mirror::Class> reference_class) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(reference_class == GetClassRoot<mirror::Reference>()); - // Second static field - ArtField* field = reference_class->GetStaticField(1); + ArtField* field = reference_class->GetField(reference_class->NumFields() - 1); + DCHECK(field->IsStatic()); DCHECK_STREQ(field->GetName(), "slowPathEnabled"); return field->GetOffset(); } diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index b16c42f1a7..444ad0bd48 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -651,14 +651,15 @@ TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) { // Find the "interfaces" static field. This is generated for all proxies. ArtField* field = nullptr; - for (size_t i = 0; i < proxyClass->NumStaticFields(); ++i) { - ArtField* f = proxyClass->GetStaticField(i); + for (size_t i = 0; i < proxyClass->NumFields(); ++i) { + ArtField* f = proxyClass->GetField(i); if (strcmp("interfaces", f->GetName()) == 0) { field = f; break; } } ASSERT_TRUE(field != nullptr); + ASSERT_TRUE(field->IsStatic()); // Test the signature. We expect the signature from the interface class. std::ostringstream ss_method; diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index f77370d3d4..885112c342 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -1191,7 +1191,7 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { // For other overhead (currently only the embedded vtable), we will generate a synthetic // byte array (or field[s] in case the overhead size is of reference size or less). - const size_t num_static_fields = klass->NumStaticFields(); + const size_t num_static_fields = klass->ComputeNumStaticFields(); // Total class size: // * class instance fields (including Object instance fields) @@ -1212,10 +1212,12 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { // Tools (ahat/Studio) will count the static fields and account for them in the class size. We // must thus subtract them from base_overhead_size or they will be double-counted. size_t class_static_fields_size = 0; - for (ArtField& class_static_field : klass->GetSFields()) { - size_t size = 0; - SignatureToBasicTypeAndSize(class_static_field.GetTypeDescriptor(), &size); - class_static_fields_size += size; + for (ArtField& class_field : klass->GetFields()) { + if (class_field.IsStatic()) { + size_t size = 0; + SignatureToBasicTypeAndSize(class_field.GetTypeDescriptor(), &size); + class_static_fields_size += size; + } } CHECK_GE(base_overhead_size, class_static_fields_size); @@ -1284,8 +1286,8 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { mirror::Class* class_class = klass->GetClass(); DCHECK(class_class->GetSuperClass()->IsObjectClass()); - const size_t static_fields_reported = class_class->NumInstanceFields() - + class_class->GetSuperClass()->NumInstanceFields() + const size_t static_fields_reported = class_class->ComputeNumInstanceFields() + + class_class->GetSuperClass()->ComputeNumInstanceFields() + java_heap_overhead_field_count + num_static_fields; __ AddU2(dchecked_integral_cast<uint16_t>(static_fields_reported)); @@ -1373,11 +1375,15 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { auto class_instance_field_name_fn = [](ArtField& field) REQUIRES_SHARED(Locks::mutator_lock_) { return std::string("$class$") + field.GetName(); }; - for (ArtField& class_instance_field : class_class->GetIFields()) { - static_field_writer(class_instance_field, class_instance_field_name_fn); + for (ArtField& class_field : class_class->GetFields()) { + if (!class_field.IsStatic()) { + static_field_writer(class_field, class_instance_field_name_fn); + } } - for (ArtField& object_instance_field : class_class->GetSuperClass()->GetIFields()) { - static_field_writer(object_instance_field, class_instance_field_name_fn); + for (ArtField& object_field : class_class->GetSuperClass()->GetFields()) { + if (!object_field.IsStatic()) { + static_field_writer(object_field, class_instance_field_name_fn); + } } } @@ -1385,13 +1391,15 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { auto class_static_field_name_fn = [](ArtField& field) REQUIRES_SHARED(Locks::mutator_lock_) { return field.GetName(); }; - for (ArtField& class_static_field : klass->GetSFields()) { - static_field_writer(class_static_field, class_static_field_name_fn); + for (ArtField& class_field : klass->GetFields()) { + if (class_field.IsStatic()) { + static_field_writer(class_field, class_static_field_name_fn); + } } } // Instance fields for this class (no superclass fields) - int iFieldCount = klass->NumInstanceFields(); + int iFieldCount = klass->ComputeNumInstanceFields(); // add_internal_runtime_objects is only for classes that may retain objects live through means // other than fields. It is never the case for strings. const bool add_internal_runtime_objects = AddRuntimeInternalObjectsField(klass); @@ -1400,8 +1408,11 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { } else { __ AddU2((uint16_t)iFieldCount); } - for (int i = 0; i < iFieldCount; ++i) { - ArtField* f = klass->GetInstanceField(i); + for (uint32_t i = 0; i < klass->NumFields(); ++i) { + ArtField* f = klass->GetField(i); + if (f->IsStatic()) { + continue; + } __ AddStringId(LookupStringId(f->GetName())); HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), nullptr); __ AddU1(t); @@ -1487,9 +1498,11 @@ void Hprof::DumpHeapInstanceObject(mirror::Object* obj, // Write the instance data; fields for this class, followed by super class fields, and so on. do { - const size_t instance_fields = klass->NumInstanceFields(); - for (size_t i = 0; i < instance_fields; ++i) { - ArtField* f = klass->GetInstanceField(i); + for (size_t i = 0; i < klass->NumFields(); ++i) { + ArtField* f = klass->GetField(i); + if (f->IsStatic()) { + continue; + } size_t size; HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size); switch (t) { diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 9149f3a6c2..07ab73f38e 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -356,20 +356,12 @@ void UnstartedRuntime::UnstartedClassGetDeclaredField( ObjPtr<mirror::Class> klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); ObjPtr<mirror::String> name2 = shadow_frame->GetVRegReference(arg_offset + 1)->AsString(); ArtField* found = nullptr; - for (ArtField& field : klass->GetIFields()) { + for (ArtField& field : klass->GetFields()) { if (name2->Equals(field.GetName())) { found = &field; break; } } - if (found == nullptr) { - for (ArtField& field : klass->GetSFields()) { - if (name2->Equals(field.GetName())) { - found = &field; - break; - } - } - } if (found != nullptr && ShouldDenyAccessToMember(found, shadow_frame)) { found = nullptr; } diff --git a/runtime/jni/jni_id_manager.cc b/runtime/jni/jni_id_manager.cc index f295d29640..789265a3e5 100644 --- a/runtime/jni/jni_id_manager.cc +++ b/runtime/jni/jni_id_manager.cc @@ -460,19 +460,12 @@ void JniIdManager::VisitReflectiveTargets(ReflectiveValueVisitor* rvv) { !old_ext_data->HasStaticFieldPointerIdMarker()) << old_class->PrettyClass(); // Clear the old field mapping. - if (old_field->IsStatic()) { - size_t old_off = ArraySlice<ArtField>(old_class->GetSFieldsPtr()).OffsetOf(old_field); - ObjPtr<mirror::PointerArray> old_statics(old_ext_data->GetStaticJFieldIDsPointerArray()); - if (!old_statics.IsNull()) { - old_statics->SetElementPtrSize(old_off, 0, kRuntimePointerSize); - } - } else { - size_t old_off = ArraySlice<ArtField>(old_class->GetIFieldsPtr()).OffsetOf(old_field); - ObjPtr<mirror::PointerArray> old_instances( - old_ext_data->GetInstanceJFieldIDsPointerArray()); - if (!old_instances.IsNull()) { - old_instances->SetElementPtrSize(old_off, 0, kRuntimePointerSize); - } + size_t old_off = ArraySlice<ArtField>(old_class->GetFieldsPtr()).OffsetOf(old_field); + ObjPtr<mirror::PointerArray> array(old_field->IsStatic() + ? old_ext_data->GetStaticJFieldIDsPointerArray() + : old_ext_data->GetInstanceJFieldIDsPointerArray()); + if (!array.IsNull()) { + array->SetElementPtrSize(old_off, 0, kRuntimePointerSize); } } if (!new_ext_data.IsNull()) { @@ -480,19 +473,12 @@ void JniIdManager::VisitReflectiveTargets(ReflectiveValueVisitor* rvv) { !new_ext_data->HasStaticFieldPointerIdMarker()) << new_class->PrettyClass(); // Set the new field mapping. - if (new_field->IsStatic()) { - size_t new_off = ArraySlice<ArtField>(new_class->GetSFieldsPtr()).OffsetOf(new_field); - ObjPtr<mirror::PointerArray> new_statics(new_ext_data->GetStaticJFieldIDsPointerArray()); - if (!new_statics.IsNull()) { - new_statics->SetElementPtrSize(new_off, id, kRuntimePointerSize); - } - } else { - size_t new_off = ArraySlice<ArtField>(new_class->GetIFieldsPtr()).OffsetOf(new_field); - ObjPtr<mirror::PointerArray> new_instances( - new_ext_data->GetInstanceJFieldIDsPointerArray()); - if (!new_instances.IsNull()) { - new_instances->SetElementPtrSize(new_off, id, kRuntimePointerSize); - } + size_t new_off = ArraySlice<ArtField>(new_class->GetFieldsPtr()).OffsetOf(new_field); + ObjPtr<mirror::PointerArray> array(new_field->IsStatic() + ? new_ext_data->GetStaticJFieldIDsPointerArray() + : new_ext_data->GetInstanceJFieldIDsPointerArray()); + if (!array.IsNull()) { + array->SetElementPtrSize(new_off, id, kRuntimePointerSize); } } } diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 161fa2cd01..7e04d66252 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -100,12 +100,12 @@ bool GetUnboxedTypeAndValue(ObjPtr<mirror::Object> o, Primitive::Type* type, JVa REQUIRES_SHARED(Locks::mutator_lock_) { ScopedAssertNoThreadSuspension ants(__FUNCTION__); ObjPtr<mirror::Class> klass = o->GetClass(); - ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0); -#define CASE_PRIMITIVE(primitive, abbrev, _, shorthand) \ - if (klass == GetBoxedPrimitiveClass(primitive)) { \ - *type = primitive; \ - value->Set ## shorthand(primitive_field->Get ## abbrev(o)); \ - return true; \ +#define CASE_PRIMITIVE(primitive, abbrev, java_name, shorthand) \ + if (klass == GetBoxedPrimitiveClass(primitive)) { \ + *type = primitive; \ + value->Set ## shorthand( \ + WellKnownClasses::java_lang_ ## java_name ## _value->Get ## abbrev(o)); \ + return true; \ } PRIMITIVES_LIST(CASE_PRIMITIVE) #undef CASE_PRIMITIVE diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 3d3c71759b..82e1462add 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -29,6 +29,7 @@ #include "class_linker.h" #include "class_loader.h" #include "common_throws.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/invoke_type.h" #include "dex_cache.h" @@ -643,9 +644,9 @@ inline void Class::SetIfTable(ObjPtr<IfTable> new_iftable) { IfTableOffset(), new_iftable); } -inline LengthPrefixedArray<ArtField>* Class::GetIFieldsPtr() { +inline LengthPrefixedArray<ArtField>* Class::GetFieldsPtr() { DCHECK(IsLoaded() || IsErroneous()) << GetStatus(); - return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); + return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, fields_)); } template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> @@ -680,44 +681,21 @@ inline MemberOffset Class::GetFirstReferenceStaticFieldOffsetDuringLinking( return MemberOffset(base); } -inline void Class::SetIFieldsPtr(LengthPrefixedArray<ArtField>* new_ifields) { - DCHECK(GetIFieldsPtrUnchecked() == nullptr); - return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields); +inline void Class::SetFieldsPtr(LengthPrefixedArray<ArtField>* new_fields) { + DCHECK(GetFieldsPtrUnchecked() == nullptr); + return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(Class, fields_), new_fields); } -inline void Class::SetIFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_ifields) { - SetFieldPtr<false, true, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields); +inline void Class::SetFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_fields) { + SetFieldPtr<false, true, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Class, fields_), new_fields); } -inline LengthPrefixedArray<ArtField>* Class::GetSFieldsPtrUnchecked() { - return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)); +inline LengthPrefixedArray<ArtField>* Class::GetFieldsPtrUnchecked() { + return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, fields_)); } -inline LengthPrefixedArray<ArtField>* Class::GetIFieldsPtrUnchecked() { - return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); -} - -inline LengthPrefixedArray<ArtField>* Class::GetSFieldsPtr() { - DCHECK(IsLoaded() || IsErroneous()) << GetStatus(); - return GetSFieldsPtrUnchecked(); -} - -inline void Class::SetSFieldsPtr(LengthPrefixedArray<ArtField>* new_sfields) { - DCHECK((IsRetired() && new_sfields == nullptr) || - GetFieldPtr<ArtField*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)) == nullptr); - SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields); -} - -inline void Class::SetSFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_sfields) { - SetFieldPtr<false, true, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields); -} - -inline ArtField* Class::GetStaticField(uint32_t i) { - return &GetSFieldsPtr()->At(i); -} - -inline ArtField* Class::GetInstanceField(uint32_t i) { - return &GetIFieldsPtr()->At(i); +inline ArtField* Class::GetField(uint32_t i) { + return &GetFieldsPtr()->At(i); } template<VerifyObjectFlags kVerifyFlags> @@ -1020,8 +998,8 @@ inline void Class::AssertInitializedOrInitializingInThread(Thread* self) { inline ObjPtr<ObjectArray<Class>> Class::GetProxyInterfaces() { CHECK(IsProxyClass()); - // First static field. - ArtField* field = GetStaticField(0); + // First field. + ArtField* field = GetField(0); DCHECK_STREQ(field->GetName(), "interfaces"); MemberOffset field_offset = field->GetOffset(); return GetFieldObject<ObjectArray<Class>>(field_offset); @@ -1029,8 +1007,8 @@ inline ObjPtr<ObjectArray<Class>> Class::GetProxyInterfaces() { inline ObjPtr<ObjectArray<ObjectArray<Class>>> Class::GetProxyThrows() { CHECK(IsProxyClass()); - // Second static field. - ArtField* field = GetStaticField(1); + // Second field. + ArtField* field = GetField(1); DCHECK_STREQ(field->GetName(), "throws"); MemberOffset field_offset = field->GetOffset(); return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset); @@ -1124,20 +1102,12 @@ inline ArraySlice<ArtMethod> Class::GetMethods(PointerSize pointer_size) { return GetMethodsSliceRangeUnchecked(methods, pointer_size, 0u, NumMethods(methods)); } -inline IterationRange<StrideIterator<ArtField>> Class::GetIFields() { - return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtr()); +inline IterationRange<StrideIterator<ArtField>> Class::GetFields() { + return MakeIterationRangeFromLengthPrefixedArray(GetFieldsPtr()); } -inline IterationRange<StrideIterator<ArtField>> Class::GetSFields() { - return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtr()); -} - -inline IterationRange<StrideIterator<ArtField>> Class::GetIFieldsUnchecked() { - return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtrUnchecked()); -} - -inline IterationRange<StrideIterator<ArtField>> Class::GetSFieldsUnchecked() { - return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtrUnchecked()); +inline IterationRange<StrideIterator<ArtField>> Class::GetFieldsUnchecked() { + return MakeIterationRangeFromLengthPrefixedArray(GetFieldsPtrUnchecked()); } inline void Class::CheckPointerSize(PointerSize pointer_size) { @@ -1234,14 +1204,37 @@ inline uint32_t Class::NumVirtualMethods() { return NumMethods() - GetVirtualMethodsStartOffset(); } -inline uint32_t Class::NumInstanceFields() { - LengthPrefixedArray<ArtField>* arr = GetIFieldsPtrUnchecked(); +inline uint32_t Class::NumFields() { + LengthPrefixedArray<ArtField>* arr = GetFieldsPtrUnchecked(); return arr != nullptr ? arr->size() : 0u; } -inline uint32_t Class::NumStaticFields() { - LengthPrefixedArray<ArtField>* arr = GetSFieldsPtrUnchecked(); - return arr != nullptr ? arr->size() : 0u; +inline bool Class::HasStaticFields() { + if (IsArrayClass() || IsPrimitive()) { + return false; + } + ClassAccessor accessor(GetDexFile(), GetDexClassDefIndex()); + return accessor.NumStaticFields() != 0u; +} + +inline uint32_t Class::ComputeNumStaticFields() { + uint32_t num = 0; + for (ArtField& field : GetFields()) { + if (field.IsStatic()) { + ++num; + } + } + return num; +} + +inline uint32_t Class::ComputeNumInstanceFields() { + uint32_t num = 0; + for (ArtField& field : GetFields()) { + if (!field.IsStatic()) { + ++num; + } + } + return num; } template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor> @@ -1262,11 +1255,9 @@ template <VerifyObjectFlags kVerifyFlags, typename Visitor> inline void Class::FixupNativePointers(Class* dest, PointerSize pointer_size, const Visitor& visitor) { - // Update the field arrays. - FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>( - dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, sfields_)); + // Update the field array. FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>( - dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); + dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, fields_)); // Update method array. FixupNativePointer<LengthPrefixedArray<ArtMethod>*, kVerifyFlags>( dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, methods_)); diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h index 96c218b175..8de27de485 100644 --- a/runtime/mirror/class-refvisitor-inl.h +++ b/runtime/mirror/class-refvisitor-inl.h @@ -120,11 +120,8 @@ void Class::VisitMethods(Visitor visitor, PointerSize pointer_size) { template<ReadBarrierOption kReadBarrierOption, class Visitor> void Class::VisitFields(Visitor visitor) { - for (ArtField& sfield : GetSFieldsUnchecked()) { - visitor(&sfield); - } - for (ArtField& ifield : GetIFieldsUnchecked()) { - visitor(&ifield); + for (ArtField& field : GetFieldsUnchecked()) { + visitor(&field); } } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index a122393171..327d2b78f1 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -426,22 +426,15 @@ void Class::DumpClass(std::ostream& os, int flags) { os << StringPrintf(" %2zd: %s\n", i, ArtMethod::PrettyMethod( GetDirectMethod(i, image_pointer_size)).c_str()); } - if (NumStaticFields() > 0) { - os << " static fields (" << NumStaticFields() << " entries):\n"; + if (NumFields() > 0) { + os << " fields (" << NumFields() << " entries):\n"; if (IsResolved()) { - for (size_t i = 0; i < NumStaticFields(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, ArtField::PrettyField(GetStaticField(i)).c_str()); - } - } else { - os << " <not yet available>"; - } - } - if (NumInstanceFields() > 0) { - os << " instance fields (" << NumInstanceFields() << " entries):\n"; - if (IsResolved()) { - for (size_t i = 0; i < NumInstanceFields(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, - ArtField::PrettyField(GetInstanceField(i)).c_str()); + for (size_t i = 0; i < NumFields(); ++i) { + ArtField* field = GetField(i); + os << StringPrintf(" %2zd: %s %s\n", + i, + field->IsStatic() ? "static" : "instance", + ArtField::PrettyField(field).c_str()); } } else { os << " <not yet available>"; @@ -1107,25 +1100,30 @@ static std::tuple<bool, ArtField*> FindFieldByNameAndType(const DexFile& dex_fil return {false, nullptr}; } -ArtField* Class::FindDeclaredInstanceField(std::string_view name, std::string_view type) { +ArtField* Class::FindDeclaredField(std::string_view name, std::string_view type) { // Binary search by name. Interfaces are not relevant because they can't contain instance fields. - LengthPrefixedArray<ArtField>* ifields = GetIFieldsPtr(); - if (ifields == nullptr) { + LengthPrefixedArray<ArtField>* fields = GetFieldsPtr(); + if (fields == nullptr) { return nullptr; } DCHECK(!IsProxyClass()); - auto [success, field] = FindFieldByNameAndType(GetDexFile(), ifields, name, type); + auto [success, field] = FindFieldByNameAndType(GetDexFile(), fields, name, type); DCHECK_EQ(success, field != nullptr); return field; } +ArtField* Class::FindDeclaredInstanceField(std::string_view name, std::string_view type) { + ArtField* f = FindDeclaredField(name, type); + if (f != nullptr && !f->IsStatic()) { + return f; + } + return nullptr; +} + ArtField* Class::FindDeclaredInstanceField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) { - if (GetDexCache() == dex_cache) { - for (ArtField& field : GetIFields()) { - if (field.GetDexFieldIndex() == dex_field_idx) { - return &field; - } - } + ArtField* f = FindDeclaredField(dex_cache, dex_field_idx); + if (f != nullptr && !f->IsStatic()) { + return f; } return nullptr; } @@ -1144,35 +1142,39 @@ ArtField* Class::FindInstanceField(std::string_view name, std::string_view type) ArtField* Class::FindDeclaredStaticField(std::string_view name, std::string_view type) { DCHECK(!type.empty()); - LengthPrefixedArray<ArtField>* sfields = GetSFieldsPtr(); - if (sfields == nullptr) { + LengthPrefixedArray<ArtField>* fields = GetFieldsPtr(); + if (fields == nullptr) { return nullptr; } if (UNLIKELY(IsProxyClass())) { // Proxy fields do not have appropriate dex field indexes required by // `FindFieldByNameAndType()`. However, each proxy class has exactly // the same artificial fields created by the `ClassLinker`. - DCHECK_EQ(sfields->size(), 2u); - DCHECK_EQ(strcmp(sfields->At(0).GetName(), "interfaces"), 0); - DCHECK_EQ(strcmp(sfields->At(0).GetTypeDescriptor(), "[Ljava/lang/Class;"), 0); - DCHECK_EQ(strcmp(sfields->At(1).GetName(), "throws"), 0); - DCHECK_EQ(strcmp(sfields->At(1).GetTypeDescriptor(), "[[Ljava/lang/Class;"), 0); + DCHECK_EQ(fields->size(), 2u); + DCHECK_EQ(strcmp(fields->At(0).GetName(), "interfaces"), 0); + DCHECK_EQ(strcmp(fields->At(0).GetTypeDescriptor(), "[Ljava/lang/Class;"), 0); + DCHECK(fields->At(0).IsStatic()); + DCHECK_EQ(strcmp(fields->At(1).GetName(), "throws"), 0); + DCHECK_EQ(strcmp(fields->At(1).GetTypeDescriptor(), "[[Ljava/lang/Class;"), 0); + DCHECK(fields->At(1).IsStatic()); if (name == "interfaces") { - return (type == "[Ljava/lang/Class;") ? &sfields->At(0) : nullptr; + return (type == "[Ljava/lang/Class;") ? &fields->At(0) : nullptr; } else if (name == "throws") { - return (type == "[[Ljava/lang/Class;") ? &sfields->At(1) : nullptr; + return (type == "[[Ljava/lang/Class;") ? &fields->At(1) : nullptr; } else { return nullptr; } } - auto [success, field] = FindFieldByNameAndType(GetDexFile(), sfields, name, type); - DCHECK_EQ(success, field != nullptr); - return field; + ArtField* f = FindDeclaredField(name, type); + if (f != nullptr && f->IsStatic()) { + return f; + } + return nullptr; } -ArtField* Class::FindDeclaredStaticField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) { +ArtField* Class::FindDeclaredField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) { if (dex_cache == GetDexCache()) { - for (ArtField& field : GetSFields()) { + for (ArtField& field : GetFields()) { if (field.GetDexFieldIndex() == dex_field_idx) { return &field; } @@ -1181,6 +1183,14 @@ ArtField* Class::FindDeclaredStaticField(ObjPtr<DexCache> dex_cache, uint32_t de return nullptr; } +ArtField* Class::FindDeclaredStaticField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) { + ArtField* f = FindDeclaredField(dex_cache, dex_field_idx); + if (f != nullptr && f->IsStatic()) { + return f; + } + return nullptr; +} + ObjPtr<mirror::ObjectArray<mirror::Field>> Class::GetDeclaredFields( Thread* self, bool public_only, @@ -1190,17 +1200,11 @@ ObjPtr<mirror::ObjectArray<mirror::Field>> Class::GetDeclaredFields( return nullptr; } StackHandleScope<1> hs(self); - IterationRange<StrideIterator<ArtField>> ifields = GetIFields(); - IterationRange<StrideIterator<ArtField>> sfields = GetSFields(); - size_t array_size = NumInstanceFields() + NumStaticFields(); + IterationRange<StrideIterator<ArtField>> fields = GetFields(); + size_t array_size = NumFields(); auto hiddenapi_context = hiddenapi::GetReflectionCallerAccessContext(self); // Lets go subtract all the non discoverable fields. - for (ArtField& field : ifields) { - if (!IsDiscoverable(public_only, hiddenapi_context, &field)) { - --array_size; - } - } - for (ArtField& field : sfields) { + for (ArtField& field : fields) { if (!IsDiscoverable(public_only, hiddenapi_context, &field)) { --array_size; } @@ -1211,7 +1215,7 @@ ObjPtr<mirror::ObjectArray<mirror::Field>> Class::GetDeclaredFields( if (object_array == nullptr) { return nullptr; } - for (ArtField& field : ifields) { + for (ArtField& field : fields) { if (IsDiscoverable(public_only, hiddenapi_context, &field)) { ObjPtr<mirror::Field> reflect_field = mirror::Field::CreateFromArtField(self, &field, force_resolve); @@ -1229,23 +1233,6 @@ ObjPtr<mirror::ObjectArray<mirror::Field>> Class::GetDeclaredFields( array_idx++, reflect_field); } } - for (ArtField& field : sfields) { - if (IsDiscoverable(public_only, hiddenapi_context, &field)) { - ObjPtr<mirror::Field> reflect_field = - mirror::Field::CreateFromArtField(self, &field, force_resolve); - if (reflect_field == nullptr) { - if (kIsDebugBuild) { - self->AssertPendingException(); - } - return nullptr; - } - // We're initializing a newly allocated object, so we do not need to record that under - // a transaction. If the transaction is aborted, the whole object shall be unreachable. - object_array->SetWithoutChecks</*kTransactionActive=*/ false, - /*kCheckTransaction=*/ false>( - array_idx++, reflect_field); - } - } DCHECK_EQ(array_idx, array_size); return object_array.Get(); } @@ -1274,17 +1261,15 @@ ArtField* Class::FindStaticField(std::string_view name, std::string_view type) { } // Find a field using the JLS field resolution order. -// Template arguments can be used to limit the search to either static or instance fields. +// Template arguments can be used to extend the search to static fields of interfaces. // The search should be limited only if we know that a full search would yield a field of // the right type or no field at all. This can be known for field references in a method // if we have previously verified that method and did not find a field type mismatch. -template <bool kSearchInstanceFields, bool kSearchStaticFields> +template <bool kSearchStaticFieldsInInterfaces> ALWAYS_INLINE ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, ObjPtr<mirror::DexCache> dex_cache, uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_) { - static_assert(kSearchInstanceFields || kSearchStaticFields); - // FIXME: Hijacking a proxy class by a custom class loader can break this assumption. DCHECK(!klass->IsProxyClass()); @@ -1296,12 +1281,7 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, // Lookup is always performed in the class referenced by the FieldId. DCHECK_EQ(klass->GetDexTypeIndex(), klass_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_); - ArtField* f = kSearchInstanceFields - ? klass->FindDeclaredInstanceField(klass_dex_cache, field_idx) - : nullptr; - if (kSearchStaticFields && f == nullptr) { - f = klass->FindDeclaredStaticField(klass_dex_cache, field_idx); - } + ArtField* f = klass->FindDeclaredField(klass_dex_cache, field_idx); if (f != nullptr) { return f; } @@ -1346,27 +1326,14 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, auto find_field_by_name_and_type = [&](ObjPtr<mirror::Class> k, ObjPtr<DexCache> k_dex_cache) REQUIRES_SHARED(Locks::mutator_lock_) -> std::tuple<bool, ArtField*> { - if ((!kSearchInstanceFields || k->GetIFieldsPtr() == nullptr) && - (!kSearchStaticFields || k->GetSFieldsPtr() == nullptr)) { + if (k->GetFieldsPtr() == nullptr) { return {false, nullptr}; } ensure_name_and_type_initialized(); const DexFile& k_dex_file = *k_dex_cache->GetDexFile(); - if (kSearchInstanceFields && k->GetIFieldsPtr() != nullptr) { - auto [success, field] = FindFieldByNameAndType(k_dex_file, k->GetIFieldsPtr(), name, type); - DCHECK_EQ(success, field != nullptr); - if (success) { - return {true, field}; - } - } - if (kSearchStaticFields && k->GetSFieldsPtr() != nullptr) { - auto [success, field] = FindFieldByNameAndType(k_dex_file, k->GetSFieldsPtr(), name, type); - DCHECK_EQ(success, field != nullptr); - if (success) { - return {true, field}; - } - } - return {false, nullptr}; + auto [success, field] = FindFieldByNameAndType(k_dex_file, k->GetFieldsPtr(), name, type); + DCHECK_EQ(success, field != nullptr); + return {success, field}; }; // If we had a dex cache mismatch, search declared fields by name and type. @@ -1379,7 +1346,7 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, } // Search direct interfaces for static fields. - if (kSearchStaticFields) { + if (kSearchStaticFieldsInInterfaces) { ArtField* f = search_direct_interfaces(klass); if (f != nullptr) { return f; @@ -1393,22 +1360,11 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, if (k_dex_cache == dex_cache) { // Matching dex_cache. We cannot compare the `field_idx` anymore because // the type index differs, so compare the name index and type index. - if (kSearchInstanceFields) { - for (ArtField& field : k->GetIFields()) { - const dex::FieldId& other_field_id = dex_file.GetFieldId(field.GetDexFieldIndex()); - if (other_field_id.name_idx_ == field_id.name_idx_ && - other_field_id.type_idx_ == field_id.type_idx_) { - return &field; - } - } - } - if (kSearchStaticFields) { - for (ArtField& field : k->GetSFields()) { - const dex::FieldId& other_field_id = dex_file.GetFieldId(field.GetDexFieldIndex()); - if (other_field_id.name_idx_ == field_id.name_idx_ && - other_field_id.type_idx_ == field_id.type_idx_) { - return &field; - } + for (ArtField& field : k->GetFields()) { + const dex::FieldId& other_field_id = dex_file.GetFieldId(field.GetDexFieldIndex()); + if (other_field_id.name_idx_ == field_id.name_idx_ && + other_field_id.type_idx_ == field_id.type_idx_) { + return &field; } } } else { @@ -1418,7 +1374,7 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, return field; } } - if (kSearchStaticFields) { + if (kSearchStaticFieldsInInterfaces) { // Is this field in any of this class' interfaces? ArtField* f = search_direct_interfaces(k); if (f != nullptr) { @@ -1431,20 +1387,17 @@ ArtField* FindFieldImpl(ObjPtr<mirror::Class> klass, FLATTEN ArtField* Class::FindField(ObjPtr<mirror::DexCache> dex_cache, uint32_t field_idx) { - return FindFieldImpl</*kSearchInstanceFields=*/ true, - /*kSearchStaticFields*/ true>(this, dex_cache, field_idx); + return FindFieldImpl</*kSearchStaticFieldsInInterfaces*/ true>(this, dex_cache, field_idx); } FLATTEN ArtField* Class::FindInstanceField(ObjPtr<mirror::DexCache> dex_cache, uint32_t field_idx) { - return FindFieldImpl</*kSearchInstanceFields=*/ true, - /*kSearchStaticFields*/ false>(this, dex_cache, field_idx); + return FindFieldImpl</*kSearchStaticFieldsInInterfaces*/ false>(this, dex_cache, field_idx); } FLATTEN ArtField* Class::FindStaticField(ObjPtr<mirror::DexCache> dex_cache, uint32_t field_idx) { - return FindFieldImpl</*kSearchInstanceFields=*/ false, - /*kSearchStaticFields*/ true>(this, dex_cache, field_idx); + return FindFieldImpl</*kSearchStaticFieldsInInterfaces*/ true>(this, dex_cache, field_idx); } void Class::ClearSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) { @@ -2247,7 +2200,7 @@ bool Class::EnsureStaticFieldIds(Handle<Class> h_this) { self->AssertPendingOOMException(); return false; } - return ext->EnsureStaticJFieldIDsArrayPresent(h_this->NumStaticFields()); + return ext->EnsureStaticJFieldIDsArrayPresent(h_this->NumFields()); } ObjPtr<Object> Class::GetInstanceFieldIds() { ObjPtr<ClassExt> ext(GetExtData()); @@ -2265,42 +2218,42 @@ bool Class::EnsureInstanceFieldIds(Handle<Class> h_this) { self->AssertPendingOOMException(); return false; } - return ext->EnsureInstanceJFieldIDsArrayPresent(h_this->NumInstanceFields()); + return ext->EnsureInstanceJFieldIDsArrayPresent(h_this->NumFields()); } size_t Class::GetStaticFieldIdOffset(ArtField* field) { DCHECK_LT(reinterpret_cast<uintptr_t>(field), - reinterpret_cast<uintptr_t>(&*GetSFieldsPtr()->end())) + reinterpret_cast<uintptr_t>(&*GetFieldsPtr()->end())) << "field not part of the current class. " << field->PrettyField() << " class is " << PrettyClass(); DCHECK_GE(reinterpret_cast<uintptr_t>(field), - reinterpret_cast<uintptr_t>(&*GetSFieldsPtr()->begin())) + reinterpret_cast<uintptr_t>(&*GetFieldsPtr()->begin())) << "field not part of the current class. " << field->PrettyField() << " class is " << PrettyClass(); - uintptr_t start = reinterpret_cast<uintptr_t>(&GetSFieldsPtr()->At(0)); + uintptr_t start = reinterpret_cast<uintptr_t>(&GetFieldsPtr()->At(0)); uintptr_t fld = reinterpret_cast<uintptr_t>(field); size_t res = (fld - start) / sizeof(ArtField); - DCHECK_EQ(&GetSFieldsPtr()->At(res), field) + DCHECK_EQ(&GetFieldsPtr()->At(res), field) << "Incorrect field computation expected: " << field->PrettyField() - << " got: " << GetSFieldsPtr()->At(res).PrettyField(); + << " got: " << GetFieldsPtr()->At(res).PrettyField(); return res; } size_t Class::GetInstanceFieldIdOffset(ArtField* field) { DCHECK_LT(reinterpret_cast<uintptr_t>(field), - reinterpret_cast<uintptr_t>(&*GetIFieldsPtr()->end())) + reinterpret_cast<uintptr_t>(&*GetFieldsPtr()->end())) << "field not part of the current class. " << field->PrettyField() << " class is " << PrettyClass(); DCHECK_GE(reinterpret_cast<uintptr_t>(field), - reinterpret_cast<uintptr_t>(&*GetIFieldsPtr()->begin())) + reinterpret_cast<uintptr_t>(&*GetFieldsPtr()->begin())) << "field not part of the current class. " << field->PrettyField() << " class is " << PrettyClass(); - uintptr_t start = reinterpret_cast<uintptr_t>(&GetIFieldsPtr()->At(0)); + uintptr_t start = reinterpret_cast<uintptr_t>(&GetFieldsPtr()->At(0)); uintptr_t fld = reinterpret_cast<uintptr_t>(field); size_t res = (fld - start) / sizeof(ArtField); - DCHECK_EQ(&GetIFieldsPtr()->At(res), field) + DCHECK_EQ(&GetFieldsPtr()->At(res), field) << "Incorrect field computation expected: " << field->PrettyField() - << " got: " << GetIFieldsPtr()->At(res).PrettyField(); + << " got: " << GetFieldsPtr()->At(res).PrettyField(); return res; } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 9560f985ac..9a45a73e72 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1032,21 +1032,24 @@ class EXPORT MANAGED Class final : public Object { ALWAYS_INLINE void SetIfTable(ObjPtr<IfTable> new_iftable) REQUIRES_SHARED(Locks::mutator_lock_); - // Get instance fields of the class (See also GetSFields). - LengthPrefixedArray<ArtField>* GetIFieldsPtr() REQUIRES_SHARED(Locks::mutator_lock_); + // Get fields of the class. + LengthPrefixedArray<ArtField>* GetFieldsPtr() REQUIRES_SHARED(Locks::mutator_lock_); - ALWAYS_INLINE IterationRange<StrideIterator<ArtField>> GetIFields() + ALWAYS_INLINE IterationRange<StrideIterator<ArtField>> GetFields() REQUIRES_SHARED(Locks::mutator_lock_); - void SetIFieldsPtr(LengthPrefixedArray<ArtField>* new_ifields) + void SetFieldsPtr(LengthPrefixedArray<ArtField>* new_fields) REQUIRES_SHARED(Locks::mutator_lock_); // Unchecked edition has no verification flags. - void SetIFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_sfields) + void SetFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_fields) REQUIRES_SHARED(Locks::mutator_lock_); - uint32_t NumInstanceFields() REQUIRES_SHARED(Locks::mutator_lock_); - ArtField* GetInstanceField(uint32_t i) REQUIRES_SHARED(Locks::mutator_lock_); + ArtField* GetField(uint32_t i) REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t NumFields() REQUIRES_SHARED(Locks::mutator_lock_); + bool HasStaticFields() REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t ComputeNumStaticFields() REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t ComputeNumInstanceFields() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the number of instance fields containing reference types. Does not count fields in any // super classes. @@ -1104,23 +1107,6 @@ class EXPORT MANAGED Class final : public Object { MemberOffset GetFirstReferenceStaticFieldOffsetDuringLinking(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); - // Gets the static fields of the class. - LengthPrefixedArray<ArtField>* GetSFieldsPtr() REQUIRES_SHARED(Locks::mutator_lock_); - ALWAYS_INLINE IterationRange<StrideIterator<ArtField>> GetSFields() - REQUIRES_SHARED(Locks::mutator_lock_); - - void SetSFieldsPtr(LengthPrefixedArray<ArtField>* new_sfields) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Unchecked edition has no verification flags. - void SetSFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_sfields) - REQUIRES_SHARED(Locks::mutator_lock_); - - uint32_t NumStaticFields() REQUIRES_SHARED(Locks::mutator_lock_); - - // TODO: uint16_t - ArtField* GetStaticField(uint32_t i) REQUIRES_SHARED(Locks::mutator_lock_); - // Find a static or instance field using the JLS resolution order ArtField* FindField(ObjPtr<mirror::DexCache> dex_cache, uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1134,6 +1120,12 @@ class EXPORT MANAGED Class final : public Object { ArtField* FindInstanceField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) REQUIRES_SHARED(Locks::mutator_lock_); + ArtField* FindDeclaredField(ObjPtr<DexCache> dex_cache, uint32_t dex_field_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + + ArtField* FindDeclaredField(std::string_view name, std::string_view type) + REQUIRES_SHARED(Locks::mutator_lock_); + ArtField* FindDeclaredInstanceField(std::string_view name, std::string_view type) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1384,7 +1376,7 @@ class EXPORT MANAGED Class final : public Object { REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<Object> GetInstanceFieldIds() REQUIRES_SHARED(Locks::mutator_lock_); - // Calculate the index in the ifields_, methods_ or sfields_ arrays a method is located at. This + // Calculate the index in the fields_ or methods_ arrays a method is located at. This // is to be used with the above Get{,OrCreate}...Ids functions. size_t GetStaticFieldIdOffset(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1426,11 +1418,8 @@ class EXPORT MANAGED Class final : public Object { void CheckObjectAlloc() REQUIRES_SHARED(Locks::mutator_lock_); // Unchecked editions is for root visiting. - LengthPrefixedArray<ArtField>* GetSFieldsPtrUnchecked() REQUIRES_SHARED(Locks::mutator_lock_); - IterationRange<StrideIterator<ArtField>> GetSFieldsUnchecked() - REQUIRES_SHARED(Locks::mutator_lock_); - LengthPrefixedArray<ArtField>* GetIFieldsPtrUnchecked() REQUIRES_SHARED(Locks::mutator_lock_); - IterationRange<StrideIterator<ArtField>> GetIFieldsUnchecked() + LengthPrefixedArray<ArtField>* GetFieldsPtrUnchecked() REQUIRES_SHARED(Locks::mutator_lock_); + IterationRange<StrideIterator<ArtField>> GetFieldsUnchecked() REQUIRES_SHARED(Locks::mutator_lock_); // The index in the methods_ array where the first declared virtual method is. @@ -1514,16 +1503,16 @@ class EXPORT MANAGED Class final : public Object { // virtual_ methods_ for miranda methods. HeapReference<PointerArray> vtable_; - // instance fields + // instance and static fields // // These describe the layout of the contents of an Object. // Note that only the fields directly declared by this class are - // listed in ifields; fields declared by a superclass are listed in - // the superclass's Class.ifields. + // listed in `fields_`; fields declared by a superclass are listed in + // the superclass's `Class.fields_`. // // ArtFields are allocated as a length prefixed ArtField array, and not an array of pointers to // ArtFields. - uint64_t ifields_; + uint64_t fields_; // Pointer to an ArtMethod length-prefixed array. All the methods where this class is the place // where they are logically defined. This includes all private, static, final and virtual methods @@ -1542,9 +1531,6 @@ class EXPORT MANAGED Class final : public Object { // Note that this field is used by the native debugger as the unique identifier for the type. uint64_t methods_; - // Static fields length-prefixed array. - uint64_t sfields_; - // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; @@ -1587,7 +1573,7 @@ class EXPORT MANAGED Class final : public Object { // bits contains the size shift of the primitive type. uint32_t primitive_type_; - // Bitmap of offsets of ifields. + // Bitmap of offsets of instance fields. uint32_t reference_instance_offsets_; // See the real definition in subtype_check_bits_and_status.h @@ -1611,7 +1597,7 @@ class EXPORT MANAGED Class final : public Object { // VTableEntry embedded_vtable_[0]; // Static fields, variable size. // uint32_t fields_[0]; - // Embedded bitmap of offsets of ifields, for classes that need more than 31 + // Embedded bitmap of offsets of instance fields, for classes that need more than 31 // reference-offset bits. 'reference_instance_offsets_' stores the number of // 32-bit entries that hold the entire bitmap. We compute the offset of first // entry by subtracting this number from class_size_. diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index b981f08d97..7dc407c737 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -245,10 +245,7 @@ void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) } auto* resolved_fields = GetResolvedFieldsArray(); if (resolved_fields != nullptr) { - for (ArtField& current_field : resolved->GetSFields()) { - resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field); - } - for (ArtField& current_field : resolved->GetIFields()) { + for (ArtField& current_field : resolved->GetFields()) { resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field); } } diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 1429bb3e04..f2cfcbf050 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -85,14 +85,16 @@ TEST_F(DexCacheTest, TestResolvedFieldAccess) { ASSERT_TRUE(klass2 != nullptr); EXPECT_OBJ_PTR_EQ(klass1->GetDexCache(), klass2->GetDexCache()); - EXPECT_NE(klass1->NumStaticFields(), 0u); - for (ArtField& field : klass2->GetSFields()) { - EXPECT_FALSE( - klass1->ResolvedFieldAccessTest</*throw_on_failure=*/ false>( - klass2.Get(), - &field, - klass1->GetDexCache(), - field.GetDexFieldIndex())); + EXPECT_NE(klass1->ComputeNumStaticFields(), 0u); + for (ArtField& field : klass2->GetFields()) { + if (field.IsStatic()) { + EXPECT_FALSE( + klass1->ResolvedFieldAccessTest</*throw_on_failure=*/ false>( + klass2.Get(), + &field, + klass1->GetDexCache(), + field.GetDexFieldIndex())); + } } } diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc index 5ad59fadf4..40af891f01 100644 --- a/runtime/mirror/field.cc +++ b/runtime/mirror/field.cc @@ -32,8 +32,7 @@ void Field::VisitTarget(ReflectiveValueVisitor* v) { if (orig != new_value) { SetOffset<false>(new_value->GetOffset().Int32Value()); SetDeclaringClass<false>(new_value->GetDeclaringClass()); - auto new_range = - IsStatic() ? GetDeclaringClass()->GetSFields() : GetDeclaringClass()->GetIFields(); + auto new_range = GetDeclaringClass()->GetFields(); auto position = std::find_if( new_range.begin(), new_range.end(), [&](const auto& f) { return &f == new_value; }); DCHECK(position != new_range.end()); @@ -45,13 +44,7 @@ void Field::VisitTarget(ReflectiveValueVisitor* v) { ArtField* Field::GetArtField() { ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); - if (IsStatic()) { - DCHECK_LT(GetArtFieldIndex(), declaring_class->NumStaticFields()); - return declaring_class->GetStaticField(GetArtFieldIndex()); - } else { - DCHECK_LT(GetArtFieldIndex(), declaring_class->NumInstanceFields()); - return declaring_class->GetInstanceField(GetArtFieldIndex()); - } + return declaring_class->GetField(GetArtFieldIndex()); } ObjPtr<mirror::Field> Field::CreateFromArtField(Thread* self, @@ -86,8 +79,7 @@ ObjPtr<mirror::Field> Field::CreateFromArtField(Thread* self, field->GetDeclaringClass()); ret->SetAccessFlags</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( field->GetAccessFlags()); - auto iter_range = field->IsStatic() ? field->GetDeclaringClass()->GetSFields() - : field->GetDeclaringClass()->GetIFields(); + auto iter_range = field->GetDeclaringClass()->GetFields(); auto position = std::find_if( iter_range.begin(), iter_range.end(), [&](const auto& f) { return &f == field; }); DCHECK(position != iter_range.end()); diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index b28978603c..3fa71c66d1 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -248,8 +248,8 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> return; } for (ObjPtr<Class> cur = c; cur != nullptr; cur = cur->GetSuperClass()) { - for (ArtField& field : cur->GetIFields()) { - if (field.GetOffset().Int32Value() == field_offset.Int32Value()) { + for (ArtField& field : cur->GetFields()) { + if (!field.IsStatic() && field.GetOffset().Int32Value() == field_offset.Int32Value()) { CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC. ObjPtr<mirror::Class> field_type = @@ -266,8 +266,8 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> return; } if (IsClass()) { - for (ArtField& field : AsClass()->GetSFields()) { - if (field.GetOffset().Int32Value() == field_offset.Int32Value()) { + for (ArtField& field : AsClass()->GetFields()) { + if (field.IsStatic() && field.GetOffset().Int32Value() == field_offset.Int32Value()) { CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC. ObjPtr<mirror::Class> field_type = diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index c31c9790bd..09bd9abec7 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -290,11 +290,7 @@ ALWAYS_INLINE static inline ObjPtr<mirror::Field> GetDeclaredField(Thread* self, ThrowRuntimeException("Obsolete Object!"); return nullptr; } - ArtField* art_field = FindFieldByName(name, c->GetIFieldsPtr()); - if (art_field != nullptr) { - return mirror::Field::CreateFromArtField(self, art_field, true); - } - art_field = FindFieldByName(name, c->GetSFieldsPtr()); + ArtField* art_field = FindFieldByName(name, c->GetFieldsPtr()); if (art_field != nullptr) { return mirror::Field::CreateFromArtField(self, art_field, true); } diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index f9bf31bedd..d0e40d86bb 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -93,11 +93,10 @@ TEST_F(ProxyTest, ProxyFieldHelper) { ASSERT_TRUE(proxyClass->IsProxyClass()); ASSERT_TRUE(proxyClass->IsInitialized()); - EXPECT_TRUE(proxyClass->GetIFieldsPtr() == nullptr); - - LengthPrefixedArray<ArtField>* static_fields = proxyClass->GetSFieldsPtr(); - ASSERT_TRUE(static_fields != nullptr); - ASSERT_EQ(2u, proxyClass->NumStaticFields()); + LengthPrefixedArray<ArtField>* fields = proxyClass->GetFieldsPtr(); + ASSERT_TRUE(fields != nullptr); + ASSERT_EQ(2u, proxyClass->NumFields()); + ASSERT_EQ(0u, proxyClass->ComputeNumInstanceFields()); Handle<mirror::Class> interfacesFieldClass( hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Class;"))); @@ -107,7 +106,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { ASSERT_TRUE(throwsFieldClass != nullptr); // Test "Class[] interfaces" field. - ArtField* field = &static_fields->At(0); + ArtField* field = &fields->At(0); EXPECT_STREQ("interfaces", field->GetName()); EXPECT_STREQ("[Ljava/lang/Class;", field->GetTypeDescriptor()); EXPECT_EQ("[Ljava/lang/Class;", field->GetTypeDescriptorView()); @@ -117,7 +116,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { EXPECT_FALSE(field->IsPrimitiveType()); // Test "Class[][] throws" field. - field = &static_fields->At(1); + field = &fields->At(1); EXPECT_STREQ("throws", field->GetName()); EXPECT_STREQ("[[Ljava/lang/Class;", field->GetTypeDescriptor()); EXPECT_EQ("[[Ljava/lang/Class;", field->GetTypeDescriptorView()); @@ -149,10 +148,10 @@ TEST_F(ProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) { ASSERT_TRUE(proxyClass1->IsProxyClass()); ASSERT_TRUE(proxyClass1->IsInitialized()); - LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetSFieldsPtr(); + LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetFieldsPtr(); ASSERT_TRUE(static_fields0 != nullptr); ASSERT_EQ(2u, static_fields0->size()); - LengthPrefixedArray<ArtField>* static_fields1 = proxyClass1->GetSFieldsPtr(); + LengthPrefixedArray<ArtField>* static_fields1 = proxyClass1->GetFieldsPtr(); ASSERT_TRUE(static_fields1 != nullptr); ASSERT_EQ(2u, static_fields1->size()); diff --git a/runtime/runtime_image.cc b/runtime/runtime_image.cc index c73810de59..7bfefe5278 100644 --- a/runtime/runtime_image.cc +++ b/runtime/runtime_image.cc @@ -860,27 +860,23 @@ class RuntimeImageHelper { void CopyFieldArrays(ObjPtr<mirror::Class> cls, uint32_t class_image_address) REQUIRES_SHARED(Locks::mutator_lock_) { - LengthPrefixedArray<ArtField>* fields[] = { - cls->GetSFieldsPtr(), cls->GetIFieldsPtr(), - }; - for (LengthPrefixedArray<ArtField>* cur_fields : fields) { - if (cur_fields != nullptr) { - // Copy the array. - size_t number_of_fields = cur_fields->size(); - size_t size = LengthPrefixedArray<ArtField>::ComputeSize(number_of_fields); - size_t offset = art_fields_.size(); - art_fields_.resize(offset + size); - auto* dest_array = - reinterpret_cast<LengthPrefixedArray<ArtField>*>(art_fields_.data() + offset); - memcpy(dest_array, cur_fields, size); - native_relocations_.Put(cur_fields, - std::make_pair(NativeRelocationKind::kArtFieldArray, offset)); - - // Update the class pointer of individual fields. - for (size_t i = 0; i != number_of_fields; ++i) { - dest_array->At(i).GetDeclaringClassAddressWithoutBarrier()->Assign( - reinterpret_cast<mirror::Class*>(class_image_address)); - } + LengthPrefixedArray<ArtField>* cur_fields = cls->GetFieldsPtr(); + if (cur_fields != nullptr) { + // Copy the array. + size_t number_of_fields = cur_fields->size(); + size_t size = LengthPrefixedArray<ArtField>::ComputeSize(number_of_fields); + size_t offset = art_fields_.size(); + art_fields_.resize(offset + size); + auto* dest_array = + reinterpret_cast<LengthPrefixedArray<ArtField>*>(art_fields_.data() + offset); + memcpy(dest_array, cur_fields, size); + native_relocations_.Put(cur_fields, + std::make_pair(NativeRelocationKind::kArtFieldArray, offset)); + + // Update the class pointer of individual fields. + for (size_t i = 0; i != number_of_fields; ++i) { + dest_array->At(i).GetDeclaringClassAddressWithoutBarrier()->Assign( + reinterpret_cast<mirror::Class*>(class_image_address)); } } } @@ -1429,7 +1425,7 @@ class RuntimeImageHelper { } // Trivial case: no static fields. - if (cls->NumStaticFields() == 0u) { + if (!cls->HasStaticFields()) { return true; } diff --git a/test/906-iterate-heap/expected-stdout.txt b/test/906-iterate-heap/expected-stdout.txt index 73b7129bba..125e65132e 100644 --- a/test/906-iterate-heap/expected-stdout.txt +++ b/test/906-iterate-heap/expected-stdout.txt @@ -19,27 +19,27 @@ 1@0 (32, 2xD '0000000000000000000000000000f03f') 2 doTestPrimitiveFieldsClasses -10000@0 (static, int, index=3) 0000000000000000 +10000@0 (static, int, index=9) 0000000000000000 10001 -10000@0 (static, int, index=11) 0000000000000000 +10000@0 (static, int, index=14) 0000000000000000 10001 10001 10001 doTestPrimitiveFieldsIntegral 10000@0 (instance, int, index=2) 0000000000000000 +10001@0 (instance, byte, index=3) 0000000000000001 +10002@0 (instance, char, index=4) 0000000000000061 +10003@0 (instance, int, index=5) 0000000000000003 +10004@0 (instance, long, index=6) 0000000000000004 +10005@0 (instance, short, index=8) 0000000000000002 +10006 +doTestPrimitiveFieldsFloat +10000@0 (instance, int, index=3) 0000000000000000 10001@0 (instance, byte, index=4) 0000000000000001 10002@0 (instance, char, index=5) 0000000000000061 10003@0 (instance, int, index=6) 0000000000000003 10004@0 (instance, long, index=7) 0000000000000004 10005@0 (instance, short, index=9) 0000000000000002 -10006 -doTestPrimitiveFieldsFloat -10000@0 (instance, int, index=3) 0000000000000000 -10001@0 (instance, byte, index=5) 0000000000000001 -10002@0 (instance, char, index=6) 0000000000000061 -10003@0 (instance, int, index=7) 0000000000000003 -10004@0 (instance, long, index=8) 0000000000000004 -10005@0 (instance, short, index=10) 0000000000000002 -10006@0 (instance, double, index=12) 3ff3ae147ae147ae -10007@0 (instance, float, index=13) 000000003f9d70a4 +10006@0 (instance, double, index=11) 3ff3ae147ae147ae +10007@0 (instance, float, index=12) 000000003f9d70a4 10008 diff --git a/test/913-heaps/expected-stdout.txt b/test/913-heaps/expected-stdout.txt index 7d3622305a..87ad2d669d 100644 --- a/test/913-heaps/expected-stdout.txt +++ b/test/913-heaps/expected-stdout.txt @@ -128,27 +128,27 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] 4@0 (18, 3xS '010002000300') 1@0 (14, 2xZ '0001') 23456789 -10000@0 (static, int, index=3) 0000000000000000 +10000@0 (static, int, index=9) 0000000000000000 10001 -10000@0 (static, int, index=11) 0000000000000000 +10000@0 (static, int, index=14) 0000000000000000 10001 10001 10001 10000@0 (instance, int, index=2) 0000000000000000 +10001@0 (instance, byte, index=3) 0000000000000001 +10002@0 (instance, char, index=4) 0000000000000061 +10003@0 (instance, int, index=5) 0000000000000003 +10004@0 (instance, long, index=6) 0000000000000004 +10005@0 (instance, short, index=8) 0000000000000002 +10006 +10000@0 (instance, int, index=3) 0000000000000000 10001@0 (instance, byte, index=4) 0000000000000001 10002@0 (instance, char, index=5) 0000000000000061 10003@0 (instance, int, index=6) 0000000000000003 10004@0 (instance, long, index=7) 0000000000000004 10005@0 (instance, short, index=9) 0000000000000002 -10006 -10000@0 (instance, int, index=3) 0000000000000000 -10001@0 (instance, byte, index=5) 0000000000000001 -10002@0 (instance, char, index=6) 0000000000000061 -10003@0 (instance, int, index=7) 0000000000000003 -10004@0 (instance, long, index=8) 0000000000000004 -10005@0 (instance, short, index=10) 0000000000000002 -10006@0 (instance, double, index=12) 3ff3ae147ae147ae -10007@0 (instance, float, index=13) 000000003f9d70a4 +10006@0 (instance, double, index=11) 3ff3ae147ae147ae +10007@0 (instance, float, index=12) 000000003f9d70a4 10008 --- klass --- root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=0,location= 31])--> 1@1000 [size=16, length=-1] |