Make some hash/equals operators inline.
Namely class descriptor hash/equals in ClassTable and
string hash/equals in InternTable.
This should reduce reliance on ThinLTO for performance.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 179799979
Bug: 179837605
Change-Id: Ie513b2312d30e1b52efefd705a26d13035789e4a
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index d043af3..3645b64 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -20,6 +20,7 @@
#include "class_table.h"
#include "base/mutex-inl.h"
+#include "dex/utf.h"
#include "gc_root-inl.h"
#include "mirror/class.h"
#include "oat_file.h"
@@ -27,6 +28,44 @@
namespace art {
+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));
+}
+
+inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const {
+ DCHECK_EQ(ComputeModifiedUtf8Hash(pair.first), pair.second);
+ return pair.second;
+}
+
+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.
+ if (a.Hash() != b.Hash()) {
+ std::string temp;
+ DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(
+ b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp)));
+ return false;
+ }
+ std::string temp;
+ return a.Read<kWithoutReadBarrier>()->DescriptorEquals(
+ b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp));
+}
+
+inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a,
+ const DescriptorHashPair& 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.
+ if (!a.MaskedHashEquals(b.second)) {
+ DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first));
+ return false;
+ }
+ return a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first);
+}
+
template<class Visitor>
void ClassTable::VisitRoots(Visitor& visitor) {
ReaderMutexLock mu(Thread::Current(), lock_);
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index fc2640c..288e312 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -164,44 +164,6 @@
return false;
}
-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));
-}
-
-uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const {
- DCHECK_EQ(ComputeModifiedUtf8Hash(pair.first), pair.second);
- return pair.second;
-}
-
-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.
- if (a.Hash() != b.Hash()) {
- std::string temp;
- DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(
- b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp)));
- return false;
- }
- std::string temp;
- return a.Read<kWithoutReadBarrier>()->DescriptorEquals(
- b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp));
-}
-
-bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a,
- const DescriptorHashPair& 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.
- if (!a.MaskedHashEquals(b.second)) {
- DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first));
- return false;
- }
- return a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first);
-}
-
bool ClassTable::InsertStrongRoot(ObjPtr<mirror::Object> obj) {
WriterMutexLock mu(Thread::Current(), lock_);
DCHECK(obj != nullptr);
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index 6208a73..0b22a6f 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -24,7 +24,7 @@
#include "class_linker.h"
#include "dexopt_test.h"
#include "dex/utf.h"
-#include "intern_table.h"
+#include "intern_table-inl.h"
#include "noop_compiler_callbacks.h"
#include "oat_file.h"
diff --git a/runtime/intern_table-inl.h b/runtime/intern_table-inl.h
index 687f5ee..44bdb1f 100644
--- a/runtime/intern_table-inl.h
+++ b/runtime/intern_table-inl.h
@@ -19,12 +19,61 @@
#include "intern_table.h"
+#include "dex/utf.h"
#include "gc/space/image_space.h"
+#include "gc_root-inl.h"
#include "image.h"
-#include "mirror/string-inl.h" // Required for ToModifiedUtf8 below.
+#include "mirror/string-inl.h"
+#include "thread-current-inl.h"
namespace art {
+inline std::size_t InternTable::StringHash::operator()(const GcRoot<mirror::String>& root) const {
+ if (kIsDebugBuild) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ }
+ // An additional cast to prevent undesired sign extension.
+ return static_cast<size_t>(
+ static_cast<uint32_t>(root.Read<kWithoutReadBarrier>()->GetHashCode()));
+}
+
+inline bool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a,
+ const GcRoot<mirror::String>& b) const {
+ if (kIsDebugBuild) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ }
+ return a.Read<kWithoutReadBarrier>()->Equals(b.Read<kWithoutReadBarrier>());
+}
+
+inline bool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a,
+ const Utf8String& b) const {
+ if (kIsDebugBuild) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ }
+ ObjPtr<mirror::String> a_string = a.Read<kWithoutReadBarrier>();
+ uint32_t a_length = static_cast<uint32_t>(a_string->GetLength());
+ if (a_length != b.GetUtf16Length()) {
+ return false;
+ }
+ if (a_string->IsCompressed()) {
+ size_t b_byte_count = strlen(b.GetUtf8Data());
+ size_t b_utf8_length = CountModifiedUtf8Chars(b.GetUtf8Data(), b_byte_count);
+ // Modified UTF-8 single byte character range is 0x01 .. 0x7f
+ // The string compression occurs on regular ASCII with same exact range,
+ // not on extended ASCII which up to 0xff
+ const bool is_b_regular_ascii = (b_byte_count == b_utf8_length);
+ if (is_b_regular_ascii) {
+ return memcmp(b.GetUtf8Data(),
+ a_string->GetValueCompressed(), a_length * sizeof(uint8_t)) == 0;
+ } else {
+ return false;
+ }
+ } else {
+ const uint16_t* a_value = a_string->GetValue();
+ return CompareModifiedUtf8ToUtf16AsCodePointValues(b.GetUtf8Data(), a_value, a_length) == 0;
+ }
+}
+
template <typename Visitor>
inline void InternTable::AddImageStringsToTable(gc::space::ImageSpace* image_space,
const Visitor& visitor) {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index b11de51..6af0455 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "intern_table.h"
+#include "intern_table-inl.h"
#include <memory>
@@ -100,8 +100,8 @@
}
ObjPtr<mirror::String> InternTable::LookupStrong(Thread* self,
- uint32_t utf16_length,
- const char* utf8_data) {
+ uint32_t utf16_length,
+ const char* utf8_data) {
DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data));
Utf8String string(utf16_length,
utf8_data,
@@ -307,52 +307,6 @@
weak_interns_.SweepWeaks(visitor);
}
-std::size_t InternTable::StringHash::operator()(const GcRoot<mirror::String>& root) const {
- if (kIsDebugBuild) {
- Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
- }
- // An additional cast to prevent undesired sign extension.
- return static_cast<size_t>(
- static_cast<uint32_t>(root.Read<kWithoutReadBarrier>()->GetHashCode()));
-}
-
-bool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a,
- const GcRoot<mirror::String>& b) const {
- if (kIsDebugBuild) {
- Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
- }
- return a.Read<kWithoutReadBarrier>()->Equals(b.Read<kWithoutReadBarrier>());
-}
-
-bool InternTable::StringEquals::operator()(const GcRoot<mirror::String>& a,
- const Utf8String& b) const {
- if (kIsDebugBuild) {
- Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
- }
- ObjPtr<mirror::String> a_string = a.Read<kWithoutReadBarrier>();
- uint32_t a_length = static_cast<uint32_t>(a_string->GetLength());
- if (a_length != b.GetUtf16Length()) {
- return false;
- }
- if (a_string->IsCompressed()) {
- size_t b_byte_count = strlen(b.GetUtf8Data());
- size_t b_utf8_length = CountModifiedUtf8Chars(b.GetUtf8Data(), b_byte_count);
- // Modified UTF-8 single byte character range is 0x01 .. 0x7f
- // The string compression occurs on regular ASCII with same exact range,
- // not on extended ASCII which up to 0xff
- const bool is_b_regular_ascii = (b_byte_count == b_utf8_length);
- if (is_b_regular_ascii) {
- return memcmp(b.GetUtf8Data(),
- a_string->GetValueCompressed(), a_length * sizeof(uint8_t)) == 0;
- } else {
- return false;
- }
- } else {
- const uint16_t* a_value = a_string->GetValue();
- return CompareModifiedUtf8ToUtf16AsCodePointValues(b.GetUtf8Data(), a_value, a_length) == 0;
- }
-}
-
void InternTable::Table::Remove(ObjPtr<mirror::String> s) {
for (InternalTable& table : tables_) {
auto it = table.set_.find(GcRoot<mirror::String>(s));
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index b64ca7d..e4eed55 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "intern_table.h"
+#include "intern_table-inl.h"
#include "base/hash_set.h"
#include "common_runtime_test.h"