summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2022-03-31 12:39:21 +0000
committer Vladimir Marko <vmarko@google.com> 2022-04-04 08:21:08 +0000
commit65258db896c8270873f362d95204336d7d1e333d (patch)
treec3975d3849fe798dfae91343e48d4c06369d8930
parent4ebfcac9d1e32c84ebe583f1d9c9b532a1b1c05d (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.h39
-rw-r--r--runtime/class_table.cc37
-rw-r--r--runtime/class_table.h3
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;