summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2024-05-06 07:43:35 +0000
committerVladimĂ­r Marko <vmarko@google.com>2024-05-09 09:24:11 +0000
commit1ca987e8b5cc2b9b3a15fc8187b987678c54b899 (patch)
tree27d9c4d9406713d2287e2e9abfbb068198a02d50
parent8e4b50a62ddb7ecfecb3e0caf3cab9f0e35eee76 (diff)
downloadart-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.h18
-rw-r--r--runtime/mirror/class.cc62
-rw-r--r--runtime/mirror/class.h2
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_);