diff options
author | Vladimir Marko <vmarko@google.com> | 2024-05-06 07:43:35 +0000 |
---|---|---|
committer | VladimĂr Marko <vmarko@google.com> | 2024-05-09 09:24:11 +0000 |
commit | 1ca987e8b5cc2b9b3a15fc8187b987678c54b899 (patch) | |
tree | 27d9c4d9406713d2287e2e9abfbb068198a02d50 | |
parent | 8e4b50a62ddb7ecfecb3e0caf3cab9f0e35eee76 (diff) | |
download | art-1ca987e8b5cc2b9b3a15fc8187b987678c54b899.tar.gz |
Avoid some `std::string` construction in `ClassTable`.
Do not construct a `std::string` when compaing most class
descriptors for `Class` objects. We still construct it for
the edge case when comparing a proxy class and non-proxy
class descriptors which should really yield false, except
that ART does not propely enforce the namespace separation.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 338123769
Change-Id: I001abf9dd6648621e86f43a8234d2c0c1d02471c
-rw-r--r-- | runtime/class_table-inl.h | 18 | ||||
-rw-r--r-- | runtime/mirror/class.cc | 62 | ||||
-rw-r--r-- | runtime/mirror/class.h | 2 |
3 files changed, 72 insertions, 10 deletions
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index 8a8487c412..2ea49dbef0 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -32,8 +32,9 @@ inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass) : 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::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::DescriptorHash()`. return slot.Read<kWithoutReadBarrier>()->DescriptorHash(); } @@ -44,17 +45,14 @@ inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHash inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a, const TableSlot& b) const { - // No read barrier needed, we're reading a chain of constant references for comparison - // with null and retrieval of constant primitive data. See ReadBarrierOption. + // No read barrier needed, we're reading a chain of constant references + // for comparison with null and retrieval of constant primitive data. + // See ReadBarrierOption and `Class::DescriptorEquals()`. if (a.Hash() != b.Hash()) { - std::string temp; - DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals( - b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp))); + DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.Read<kWithoutReadBarrier>())); return false; } - std::string temp; - return a.Read<kWithoutReadBarrier>()->DescriptorEquals( - b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp)); + return a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.Read<kWithoutReadBarrier>()); } inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a, diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 828ab968a3..c69a6721bc 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -1691,6 +1691,68 @@ ObjPtr<Class> Class::CopyOf(Handle<Class> h_this, return new_class->AsClass(); } +bool Class::DescriptorEquals(ObjPtr<mirror::Class> match) { + DCHECK(match != nullptr); + ObjPtr<mirror::Class> klass = this; + while (klass->IsArrayClass()) { + // No read barrier needed, we're reading a chain of constant references for comparison + // with null. Then we follow up below with reading constant references to read constant + // primitive data in both proxy and non-proxy paths. See ReadBarrierOption. + klass = klass->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>(); + DCHECK(klass != nullptr); + match = match->GetComponentType<kDefaultVerifyFlags, kWithoutReadBarrier>(); + if (match == nullptr){ + return false; + } + } + if (match->IsArrayClass()) { + return false; + } + + if (UNLIKELY(klass->IsPrimitive()) || UNLIKELY(match->IsPrimitive())) { + return klass->GetPrimitiveType() == match->GetPrimitiveType(); + } + + if (UNLIKELY(klass->IsProxyClass())) { + return klass->ProxyDescriptorEquals(match); + } + if (UNLIKELY(match->IsProxyClass())) { + return match->ProxyDescriptorEquals(klass); + } + + const DexFile& klass_dex_file = klass->GetDexFile(); + const DexFile& match_dex_file = match->GetDexFile(); + dex::TypeIndex klass_type_index = klass->GetDexTypeIndex(); + dex::TypeIndex match_type_index = match->GetDexTypeIndex(); + if (&klass_dex_file == &match_dex_file) { + return klass_type_index == match_type_index; + } + std::string_view klass_descriptor = klass_dex_file.GetTypeDescriptorView(klass_type_index); + std::string_view match_descriptor = match_dex_file.GetTypeDescriptorView(match_type_index); + return klass_descriptor == match_descriptor; +} + +bool Class::ProxyDescriptorEquals(ObjPtr<mirror::Class> match) { + DCHECK(IsProxyClass()); + ObjPtr<mirror::String> name = GetName<kVerifyNone, kWithoutReadBarrier>(); + DCHECK(name != nullptr); + + DCHECK(match != nullptr); + DCHECK(!match->IsArrayClass()); + DCHECK(!match->IsPrimitive()); + if (match->IsProxyClass()) { + ObjPtr<mirror::String> match_name = match->GetName<kVerifyNone, kWithoutReadBarrier>(); + DCHECK(name != nullptr); + return name->Equals(match_name); + } + + // Note: Proxy descriptor should never match a non-proxy descriptor but ART does not enforce that. + std::string descriptor = DotToDescriptor(name->ToModifiedUtf8().c_str()); + std::string_view match_descriptor = + match->GetDexFile().GetTypeDescriptorView(match->GetDexTypeIndex()); + return descriptor == match_descriptor; +} + bool Class::ProxyDescriptorEquals(const char* match) { DCHECK(IsProxyClass()); std::string storage; diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 42ce9d1349..2a95d2227d 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1231,6 +1231,7 @@ class EXPORT MANAGED Class final : public Object { // this to avoid memory allocation in the common case. const char* GetDescriptor(std::string* storage) REQUIRES_SHARED(Locks::mutator_lock_); + bool DescriptorEquals(ObjPtr<mirror::Class> match) REQUIRES_SHARED(Locks::mutator_lock_); bool DescriptorEquals(const char* match) REQUIRES_SHARED(Locks::mutator_lock_); uint32_t DescriptorHash() REQUIRES_SHARED(Locks::mutator_lock_); @@ -1418,6 +1419,7 @@ class EXPORT MANAGED Class final : public Object { // The index in the methods_ array where the first direct method is. ALWAYS_INLINE uint32_t GetDirectMethodsStartOffset() REQUIRES_SHARED(Locks::mutator_lock_); + bool ProxyDescriptorEquals(ObjPtr<mirror::Class> match) 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_); |