summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2022-04-14 10:59:53 +0100
committerTreehugger Robot <treehugger-gerrit@google.com>2022-04-21 11:01:45 +0000
commit10137abcd09d51f263f56d64bb0b41fb4f8e5070 (patch)
tree5ed1f202dcaae81e60e24f32a3579731ba4a86f3
parent86f1b3f30fa72c3f3e712c930c4444c51054b615 (diff)
downloadart-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.cc6
-rw-r--r--runtime/class_table-inl.h39
-rw-r--r--runtime/class_table.cc30
-rw-r--r--runtime/class_table.h6
-rw-r--r--runtime/mirror/class-inl.h28
-rw-r--r--runtime/mirror/class.cc27
-rw-r--r--runtime/mirror/class.h5
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_);