diff options
author | Vladimir Marko <vmarko@google.com> | 2022-04-14 10:59:53 +0100 |
---|---|---|
committer | Treehugger Robot <treehugger-gerrit@google.com> | 2022-04-21 11:01:45 +0000 |
commit | 10137abcd09d51f263f56d64bb0b41fb4f8e5070 (patch) | |
tree | 5ed1f202dcaae81e60e24f32a3579731ba4a86f3 | |
parent | 86f1b3f30fa72c3f3e712c930c4444c51054b615 (diff) | |
download | art-10137abcd09d51f263f56d64bb0b41fb4f8e5070.tar.gz |
Move descriptor hashing to `mirror::Class`.
We may want to reuse the hashing for image classes which are
not closely related with the `ClassTable` where the hashing
was previously.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: Icf1b51085829509f58e7685dc1e9cf2b0583d107
-rw-r--r-- | dex2oat/linker/image_writer.cc | 6 | ||||
-rw-r--r-- | runtime/class_table-inl.h | 39 | ||||
-rw-r--r-- | runtime/class_table.cc | 30 | ||||
-rw-r--r-- | runtime/class_table.h | 6 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 28 | ||||
-rw-r--r-- | runtime/mirror/class.cc | 27 | ||||
-rw-r--r-- | runtime/mirror/class.h | 5 |
7 files changed, 69 insertions, 72 deletions
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index d4cd867266..56fbe9013b 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -1115,7 +1115,7 @@ class ImageWriter::PruneClassesVisitor : public ClassVisitor { DCHECK(!class_table->classes_.empty()); ClassTable::ClassSet& last_class_set = class_table->classes_.back(); for (mirror::Class* klass : classes_to_prune_) { - uint32_t hash = ClassTable::TableSlot::HashDescriptor(klass); + uint32_t hash = klass->DescriptorHash(); auto it = last_class_set.FindWithHash(ClassTable::TableSlot(klass, hash), hash); DCHECK(it != last_class_set.end()); last_class_set.erase(it); @@ -1687,7 +1687,7 @@ class ImageWriter::LayoutHelper::CollectClassesVisitor { size_t oat_index = pair.second; DCHECK(image_writer->image_infos_[oat_index].class_table_.has_value()); ClassTable::ClassSet& class_table = *image_writer->image_infos_[oat_index].class_table_; - uint32_t hash = ClassTable::TableSlot::HashDescriptor(klass); + uint32_t hash = klass->DescriptorHash(); bool inserted = class_table.InsertWithHash(ClassTable::TableSlot(klass, hash), hash).second; DCHECK(inserted) << "Class " << klass->PrettyDescriptor() << " (" << klass.Ptr() << ") already inserted"; @@ -1703,7 +1703,7 @@ class ImageWriter::LayoutHelper::CollectClassesVisitor { DCHECK(image_info.class_table_.has_value()); ClassTable::ClassSet& table = *image_info.class_table_; for (mirror::Class* klass : boot_image_classes) { - uint32_t hash = ClassTable::TableSlot::HashDescriptor(klass); + uint32_t hash = klass->DescriptorHash(); bool inserted = table.InsertWithHash(ClassTable::TableSlot(klass, hash), hash).second; DCHECK(inserted) << "Boot image class " << klass->PrettyDescriptor() << " (" << klass << ") already inserted"; diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index ff775d774f..071376cd77 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -29,41 +29,12 @@ namespace art { inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass) - : TableSlot(klass, HashDescriptor(klass)) {} - -inline uint32_t ClassTable::TableSlot::HashDescriptor(ObjPtr<mirror::Class> klass) { - // No read barriers needed, we're reading a chain of constant references for comparison with null - // and retrieval of constant primitive data. See `ReadBarrierOption` and `Class::GetDescriptor()`. - DCHECK(klass != nullptr); - ObjPtr<mirror::Class> orig_klass = klass; // For debug check. - uint32_t hash = StartModifiedUtf8Hash(); - while (klass->IsArrayClass()) { - klass = klass->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>(); - hash = UpdateModifiedUtf8Hash(hash, '['); - } - if (UNLIKELY(klass->IsProxyClass())) { - hash = UpdateHashForProxyClass(hash, klass); - } else if (klass->IsPrimitive()) { - hash = UpdateModifiedUtf8Hash(hash, Primitive::Descriptor(klass->GetPrimitiveType())[0]); - } else { - const DexFile& dex_file = klass->GetDexFile(); - const dex::TypeId& type_id = dex_file.GetTypeId(klass->GetDexTypeIndex()); - std::string_view descriptor = dex_file.GetTypeDescriptorView(type_id); - hash = UpdateModifiedUtf8Hash(hash, descriptor); - } - - if (kIsDebugBuild) { - std::string temp; - CHECK_EQ(hash, ComputeModifiedUtf8Hash(orig_klass->GetDescriptor(&temp))); - } - - return hash; -} + : TableSlot(klass, klass->DescriptorHash()) {} inline uint32_t ClassTable::ClassDescriptorHash::operator()(const TableSlot& slot) const { // No read barriers needed, we're reading a chain of constant references for comparison with null - // and retrieval of constant primitive data. See `ReadBarrierOption` and `Class::GetDescriptor()`. - return TableSlot::HashDescriptor(slot.Read<kWithoutReadBarrier>()); + // and retrieval of constant primitive data. See `ReadBarrierOption` and `Class::DescriptorHash()`. + return slot.Read<kWithoutReadBarrier>()->DescriptorHash(); } inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const { @@ -202,7 +173,7 @@ inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint3 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash) : data_(Encode(klass, MaskHash(descriptor_hash))) { - DCHECK_EQ(descriptor_hash, HashDescriptor(klass)); + DCHECK_EQ(descriptor_hash, klass->DescriptorHash()); } template <typename Filter> @@ -213,9 +184,9 @@ inline void ClassTable::RemoveStrongRoots(const Filter& filter) { } inline ObjPtr<mirror::Class> ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) { + uint32_t hash = klass->DescriptorHash(); std::string temp; const char* descriptor = klass->GetDescriptor(&temp); - uint32_t hash = TableSlot::HashDescriptor(klass); return Lookup(descriptor, hash); } diff --git a/runtime/class_table.cc b/runtime/class_table.cc index 10f60ab508..429f9268ec 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -23,34 +23,6 @@ namespace art { -uint32_t ClassTable::TableSlot::UpdateHashForProxyClass( - uint32_t hash, ObjPtr<mirror::Class> proxy_class) { - // No read barrier needed, the `name` field is constant for proxy classes and - // the contents of the String are also constant. See ReadBarrierOption. - // Note: The `proxy_class` can be a from-space reference. - DCHECK(proxy_class->IsProxyClass()); - ObjPtr<mirror::String> name = proxy_class->GetName<kVerifyNone, kWithoutReadBarrier>(); - DCHECK(name != nullptr); - // Update hash for characters we would get from `DotToDescriptor(name->ToModifiedUtf8())`. - DCHECK_NE(name->GetLength(), 0); - DCHECK_NE(name->CharAt(0), '['); - hash = UpdateModifiedUtf8Hash(hash, 'L'); - if (name->IsCompressed()) { - std::string_view dot_name(reinterpret_cast<const char*>(name->GetValueCompressed()), - name->GetLength()); - for (char c : dot_name) { - hash = UpdateModifiedUtf8Hash(hash, (c != '.') ? c : '/'); - } - } else { - std::string dot_name = name->ToModifiedUtf8(); - for (char c : dot_name) { - hash = UpdateModifiedUtf8Hash(hash, (c != '.') ? c : '/'); - } - } - hash = UpdateModifiedUtf8Hash(hash, ';'); - return hash; -} - ClassTable::ClassTable() : lock_("Class loader classes", kClassLoaderClassesLock) { Runtime* const runtime = Runtime::Current(); classes_.push_back(ClassSet(runtime->GetHashTableMinLoadFactor(), @@ -150,7 +122,7 @@ ObjPtr<mirror::Class> ClassTable::Lookup(const char* descriptor, size_t hash) { } void ClassTable::Insert(ObjPtr<mirror::Class> klass) { - InsertWithHash(klass, TableSlot::HashDescriptor(klass)); + InsertWithHash(klass, klass->DescriptorHash()); } void ClassTable::InsertWithHash(ObjPtr<mirror::Class> klass, size_t hash) { diff --git a/runtime/class_table.h b/runtime/class_table.h index 3377f14b4a..212a7d6631 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -78,9 +78,6 @@ class ClassTable { return MaskHash(other) == Hash(); } - static uint32_t HashDescriptor(ObjPtr<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); - template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ObjPtr<mirror::Class> Read() const REQUIRES_SHARED(Locks::mutator_lock_); @@ -96,9 +93,6 @@ class ClassTable { static uint32_t Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) REQUIRES_SHARED(Locks::mutator_lock_); - static uint32_t UpdateHashForProxyClass(uint32_t hash, ObjPtr<mirror::Class> proxy_class) - REQUIRES_SHARED(Locks::mutator_lock_); - // Data contains the class pointer GcRoot as well as the low bits of the descriptor hash. mutable Atomic<uint32_t> data_; static constexpr uint32_t kHashMask = kObjectAlignment - 1; diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 84f117fdbe..b6bd22eb76 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -898,6 +898,34 @@ inline bool Class::DescriptorEquals(const char* match) { } } +inline uint32_t Class::DescriptorHash() { + // No read barriers needed, we're reading a chain of constant references for comparison with null + // and retrieval of constant primitive data. See `ReadBarrierOption` and `Class::GetDescriptor()`. + ObjPtr<mirror::Class> klass = this; + uint32_t hash = StartModifiedUtf8Hash(); + while (klass->IsArrayClass()) { + klass = klass->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>(); + hash = UpdateModifiedUtf8Hash(hash, '['); + } + if (UNLIKELY(klass->IsProxyClass())) { + hash = UpdateHashForProxyClass(hash, klass); + } else if (klass->IsPrimitive()) { + hash = UpdateModifiedUtf8Hash(hash, Primitive::Descriptor(klass->GetPrimitiveType())[0]); + } else { + const DexFile& dex_file = klass->GetDexFile(); + const dex::TypeId& type_id = dex_file.GetTypeId(klass->GetDexTypeIndex()); + std::string_view descriptor = dex_file.GetTypeDescriptorView(type_id); + hash = UpdateModifiedUtf8Hash(hash, descriptor); + } + + if (kIsDebugBuild) { + std::string temp; + CHECK_EQ(hash, ComputeModifiedUtf8Hash(GetDescriptor(&temp))); + } + + return hash; +} + inline void Class::AssertInitializedOrInitializingInThread(Thread* self) { if (kIsDebugBuild && !IsInitialized()) { CHECK(IsInitializing()) << PrettyClass() << " is not initializing: " << GetStatus(); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index a07a15b01d..37a4197d71 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -1702,6 +1702,33 @@ bool Class::ProxyDescriptorEquals(const char* match) { return storage == match; } +uint32_t Class::UpdateHashForProxyClass(uint32_t hash, ObjPtr<mirror::Class> proxy_class) { + // No read barrier needed, the `name` field is constant for proxy classes and + // the contents of the String are also constant. See ReadBarrierOption. + // Note: The `proxy_class` can be a from-space reference. + DCHECK(proxy_class->IsProxyClass()); + ObjPtr<mirror::String> name = proxy_class->GetName<kVerifyNone, kWithoutReadBarrier>(); + DCHECK(name != nullptr); + // Update hash for characters we would get from `DotToDescriptor(name->ToModifiedUtf8())`. + DCHECK_NE(name->GetLength(), 0); + DCHECK_NE(name->CharAt(0), '['); + hash = UpdateModifiedUtf8Hash(hash, 'L'); + if (name->IsCompressed()) { + std::string_view dot_name(reinterpret_cast<const char*>(name->GetValueCompressed()), + name->GetLength()); + for (char c : dot_name) { + hash = UpdateModifiedUtf8Hash(hash, (c != '.') ? c : '/'); + } + } else { + std::string dot_name = name->ToModifiedUtf8(); + for (char c : dot_name) { + hash = UpdateModifiedUtf8Hash(hash, (c != '.') ? c : '/'); + } + } + hash = UpdateModifiedUtf8Hash(hash, ';'); + return hash; +} + // TODO: Move this to java_lang_Class.cc? ArtMethod* Class::GetDeclaredConstructor( Thread* self, Handle<ObjectArray<Class>> args, PointerSize pointer_size) { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 7b967aca69..90efce556f 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1208,6 +1208,8 @@ class MANAGED Class final : public Object { bool DescriptorEquals(const char* match) REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t DescriptorHash() REQUIRES_SHARED(Locks::mutator_lock_); + const dex::ClassDef* GetClassDef() REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE uint32_t NumDirectInterfaces() REQUIRES_SHARED(Locks::mutator_lock_); @@ -1393,6 +1395,9 @@ class MANAGED Class final : public Object { ALWAYS_INLINE uint32_t GetDirectMethodsStartOffset() REQUIRES_SHARED(Locks::mutator_lock_); bool ProxyDescriptorEquals(const char* match) REQUIRES_SHARED(Locks::mutator_lock_); + static uint32_t UpdateHashForProxyClass(uint32_t hash, ObjPtr<mirror::Class> proxy_class) + REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags> void GetAccessFlagsDCheck() REQUIRES_SHARED(Locks::mutator_lock_); |