diff options
author | 2022-03-31 12:39:21 +0000 | |
---|---|---|
committer | 2022-04-04 08:21:08 +0000 | |
commit | 65258db896c8270873f362d95204336d7d1e333d (patch) | |
tree | c3975d3849fe798dfae91343e48d4c06369d8930 | |
parent | 4ebfcac9d1e32c84ebe583f1d9c9b532a1b1c05d (diff) |
Faster class descriptor hashing.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: I94612e8229b6d21abd51ade36ed88c1b5db77764
-rw-r--r-- | runtime/class_table-inl.h | 39 | ||||
-rw-r--r-- | runtime/class_table.cc | 37 | ||||
-rw-r--r-- | runtime/class_table.h | 3 |
3 files changed, 67 insertions, 12 deletions
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index 088ad3dbd8..ff775d774f 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -28,11 +28,42 @@ 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; +} + inline uint32_t ClassTable::ClassDescriptorHash::operator()(const TableSlot& slot) const { - std::string temp; - // No read barrier needed, we're reading a chain of constant references for comparison - // with null and retrieval of constant primitive data. See ReadBarrierOption. - return ComputeModifiedUtf8Hash(slot.Read<kWithoutReadBarrier>()->GetDescriptor(&temp)); + // 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>()); } inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const { diff --git a/runtime/class_table.cc b/runtime/class_table.cc index bd5d38f80d..acfbcb09a3 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -18,10 +18,39 @@ #include "base/stl_util.h" #include "mirror/class-inl.h" +#include "mirror/string-inl.h" #include "oat_file.h" 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(), @@ -189,12 +218,4 @@ void ClassTable::ClearStrongRoots() { strong_roots_.clear(); } -ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass) - : TableSlot(klass, HashDescriptor(klass)) {} - -uint32_t ClassTable::TableSlot::HashDescriptor(ObjPtr<mirror::Class> klass) { - std::string temp; - return ComputeModifiedUtf8Hash(klass->GetDescriptor(&temp)); -} - } // namespace art diff --git a/runtime/class_table.h b/runtime/class_table.h index 17b87866b7..4c5fc62b2d 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -96,6 +96,9 @@ 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; |