diff --git a/common_components/objects/string_table/hashtriemap-inl.h b/common_components/objects/string_table/hashtriemap-inl.h index 925628b3304268446d04d7af1fbc924695667af3..a9606f1b617340d19a4213fe3b003a119c01fac9 100644 --- a/common_components/objects/string_table/hashtriemap-inl.h +++ b/common_components/objects/string_table/hashtriemap-inl.h @@ -28,8 +28,9 @@ namespace common { template template typename HashTrieMap::Node* HashTrieMap::Expand( - Entry* oldEntry, Entry* newEntry, uint32_t oldHash, uint32_t newHash, uint32_t hashShift, Indirect* parent) + Entry* oldEntry, Entry* newEntry, uint32_t newHash, uint32_t hashShift, Indirect* parent) { + uint32_t oldHash = oldEntry->Key(); // Check for hash conflicts. if (oldHash == newHash) { // Store the old entry in the overflow list of the new entry, and then store @@ -39,7 +40,7 @@ typename HashTrieMap::Node* HashTrieMap::Node* HashTrieMap> hashShift) & TrieMapConfig::N_CHILDREN_MASK; uint32_t newIdx = (newHash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; if (oldIdx != newIdx) { - newIndirect->GetChild(oldIdx).store(oldEntry, std::memory_order_release); - newIndirect->GetChild(newIdx).store(newEntry, std::memory_order_release); + newIndirect->children_[oldIdx].store(oldEntry, std::memory_order_release); + newIndirect->children_[newIdx].store(newEntry, std::memory_order_release); break; } - Indirect* nextIndirect = new Indirect(); + Indirect* nextIndirect = new Indirect(newIndirect); - newIndirect->GetChild(oldIdx).store(nextIndirect, std::memory_order_release); + newIndirect->children_[oldIdx].store(nextIndirect, std::memory_order_release); newIndirect = nextIndirect; } return top; @@ -83,7 +84,7 @@ BaseString* HashTrieMap::Load(ReadBarrier&& re TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - std::atomic* slot = ¤t->GetChild(index); + std::atomic* slot = ¤t->children_[index]; Node* node = slot->load(std::memory_order_acquire); if (node == nullptr) { return nullptr; @@ -94,6 +95,9 @@ BaseString* HashTrieMap::Load(ReadBarrier&& re } for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } auto oldValue = currentEntry->Value(); bool valuesEqual = false; if (!IsNull(oldValue) && BaseString::StringsAreEqual(std::forward(readBarrier), oldValue, @@ -138,7 +142,7 @@ BaseString* HashTrieMap::LoadOrStore(ThreadHol // find the key or insert the candidate position. for (; hashShift < TrieMapConfig::TOTAL_HASH_BITS; hashShift += TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - slot = ¤t->GetChild(index); + slot = ¤t->children_[index]; node = slot->load(std::memory_order_acquire); if (node == nullptr) { haveInsertPoint = true; @@ -152,6 +156,9 @@ BaseString* HashTrieMap::LoadOrStore(ThreadHol } for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } auto oldValue = currentEntry->Value(); if (IsNull(oldValue)) { continue; @@ -199,17 +206,15 @@ BaseString* HashTrieMap::LoadOrStore(ThreadHol TraceFindFail(); #endif Entry* oldEntry = nullptr; - uint32_t oldHash = key; if (node != nullptr) { oldEntry = node->AsEntry(); for (Entry* currentEntry = oldEntry; currentEntry; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { - auto oldValue = currentEntry->Value(); - if (IsNull(oldValue)) { + if (currentEntry->Key() != hash) { continue; } - if (currentEntry->Key() != key) { - oldHash = currentEntry->Key(); + auto oldValue = currentEntry->Value(); + if (IsNull(oldValue)) { continue; } if (std::invoke(std::forward(equalsCallback), oldValue)) { @@ -224,7 +229,7 @@ BaseString* HashTrieMap::LoadOrStore(ThreadHol BaseString* value = *str; value->SetIsInternString(); IntegerCache::InitIntegerCache(value); - Entry* newEntry = new Entry(value); + Entry* newEntry = new Entry(hash, value); oldEntry = PruneHead(oldEntry); if (oldEntry == nullptr) { // The simple case: Create a new entry and store it. @@ -232,8 +237,7 @@ BaseString* HashTrieMap::LoadOrStore(ThreadHol } else { // Expand an existing entry to one or more new nodes. // Release the node, which will make both oldEntry and newEntry visible - auto expandedNode = Expand(oldEntry, newEntry, - oldHash >> TrieMapConfig::ROOT_BIT, hash, hashShift, current); + auto expandedNode = Expand(oldEntry, newEntry, hash, hashShift, current); slot->store(expandedNode, std::memory_order_release); } if constexpr (IsLock) { @@ -265,7 +269,7 @@ BaseString* HashTrieMap::LoadOrStoreForJit(Thr // find the key or insert the candidate position. for (; hashShift < TrieMapConfig::TOTAL_HASH_BITS; hashShift += TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - slot = ¤t->GetChild(index); + slot = ¤t->children_[index]; node = slot->load(std::memory_order_acquire); if (node == nullptr) { haveInsertPoint = true; @@ -279,6 +283,9 @@ BaseString* HashTrieMap::LoadOrStoreForJit(Thr } for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } auto oldValue = currentEntry->Value(); if (IsNull(oldValue)) { continue; @@ -313,17 +320,15 @@ BaseString* HashTrieMap::LoadOrStoreForJit(Thr } Entry* oldEntry = nullptr; - uint32_t oldHash = key; if (node != nullptr) { oldEntry = node->AsEntry(); for (Entry* currentEntry = oldEntry; currentEntry; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { - auto oldValue = currentEntry->Value(); - if (IsNull(oldValue)) { + if (currentEntry->Key() != hash) { continue; } - if (currentEntry->Key() != key) { - oldHash = currentEntry->Key(); + auto oldValue = currentEntry->Value(); + if (IsNull(oldValue)) { continue; } if (std::invoke(std::forward(equalsCallback), oldValue)) { @@ -335,7 +340,7 @@ BaseString* HashTrieMap::LoadOrStoreForJit(Thr value->SetIsInternString(); IntegerCache::InitIntegerCache(value); - Entry* newEntry = new Entry(value); + Entry* newEntry = new Entry(hash, value); oldEntry = PruneHead(oldEntry); if (oldEntry == nullptr) { // The simple case: Create a new entry and store it. @@ -343,8 +348,7 @@ BaseString* HashTrieMap::LoadOrStoreForJit(Thr } else { // Expand an existing entry to one or more new nodes. // Release the node, which will make both oldEntry and newEntry visible - auto expandedNode = Expand(oldEntry, newEntry, - oldHash >> TrieMapConfig::ROOT_BIT, hash, hashShift, current); + auto expandedNode = Expand(oldEntry, newEntry, hash, hashShift, current); slot->store(expandedNode, std::memory_order_release); } GetMutex().Unlock(); @@ -381,7 +385,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol // find the key or insert the candidate position. for (; hashShift < TrieMapConfig::TOTAL_HASH_BITS; hashShift += TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - slot = ¤t->GetChild(index); + slot = ¤t->children_[index]; node = slot->load(std::memory_order_acquire); if (node == nullptr) { haveInsertPoint = true; @@ -391,10 +395,12 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol if (node->IsEntry()) { for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { - auto oldValue = currentEntry->Value(); - if (!IsNull(oldValue) && std::invoke(std::forward(equalsCallback), - oldValue)) { - return oldValue; + if (currentEntry->Key() == hash) { + auto oldValue = currentEntry->Value(); + if (!IsNull(oldValue) && std::invoke(std::forward(equalsCallback), + oldValue)) { + return oldValue; + } } } haveInsertPoint = true; @@ -422,17 +428,15 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol } } Entry* oldEntry = nullptr; - uint32_t oldHash = key; if (node != nullptr) { oldEntry = node->AsEntry(); for (Entry* currentEntry = oldEntry; currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { - auto oldValue = currentEntry->Value(); - if (IsNull(oldValue)) { + if (currentEntry->Key() != hash) { continue; } - if (currentEntry->Key() != key) { - oldHash = currentEntry->Key(); + auto oldValue = currentEntry->Value(); + if (IsNull(oldValue)) { continue; } if (std::invoke(std::forward(equalsCallback), oldValue)) { @@ -445,7 +449,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol BaseString* value = *str; value->SetIsInternString(); IntegerCache::InitIntegerCache(value); - Entry* newEntry = new Entry(value); + Entry* newEntry = new Entry(hash, value); oldEntry = PruneHead(oldEntry); if (oldEntry == nullptr) { // The simple case: Create a new entry and store it. @@ -453,8 +457,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol } else { // Expand an existing entry to one or more new nodes. // Release the node, which will make both oldEntry and newEntry visible - auto expandedNode = Expand(oldEntry, newEntry, - oldHash >> TrieMapConfig::ROOT_BIT, hash, hashShift, current); + auto expandedNode = Expand(oldEntry, newEntry, hash, hashShift, current); slot->store(expandedNode, std::memory_order_release); } @@ -474,7 +477,7 @@ HashTrieMapLoadResult HashTrieMap::Load(ReadBa TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - std::atomic* slot = ¤t->GetChild(index); + std::atomic* slot = ¤t->children_[index]; Node* node = slot->load(std::memory_order_acquire); if (node == nullptr) { return {nullptr, current, hashShift, slot}; @@ -482,6 +485,9 @@ HashTrieMapLoadResult HashTrieMap::Load(ReadBa if (node->IsEntry()) { for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } auto oldValue = currentEntry->Value(); if (IsNull(oldValue)) { continue; @@ -513,7 +519,7 @@ HashTrieMapLoadResult HashTrieMap::Load(ReadBa TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - std::atomic* slot = ¤t->GetChild(index); + std::atomic* slot = ¤t->children_[index]; Node* node = slot->load(std::memory_order_acquire); if (node == nullptr) { return {nullptr, current, hashShift, slot}; @@ -524,6 +530,9 @@ HashTrieMapLoadResult HashTrieMap::Load(ReadBa } for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } auto oldValue = currentEntry->Value(); if (IsNull(oldValue)) { continue; @@ -571,7 +580,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol haveInsertPoint = false; for (; hashShift < TrieMapConfig::TOTAL_HASH_BITS; hashShift += TrieMapConfig::N_CHILDREN_LOG2) { size_t index = (hash >> hashShift) & TrieMapConfig::N_CHILDREN_MASK; - slot = ¤t->GetChild(index); + slot = ¤t->children_[index]; node = slot->load(std::memory_order_acquire); if (node == nullptr) { haveInsertPoint = true; @@ -585,6 +594,9 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol } for (Entry* currentEntry = node->AsEntry(); currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { + if (currentEntry->Key() != hash) { + continue; + } BaseString* oldValue = currentEntry->Value(); if (IsNull(oldValue)) { continue; @@ -620,17 +632,15 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol } Entry* oldEntry = nullptr; - uint32_t oldHash = key; if (node != nullptr) { oldEntry = node->AsEntry(); for (Entry* currentEntry = oldEntry; currentEntry != nullptr; currentEntry = currentEntry->Overflow().load(std::memory_order_acquire)) { - BaseString* oldValue = currentEntry->Value(); - if (IsNull(oldValue)) { + if (currentEntry->Key() != hash) { continue; } - if (currentEntry->Key() != key) { - oldHash = currentEntry->Key(); + BaseString* oldValue = currentEntry->Value(); + if (IsNull(oldValue)) { continue; } if (BaseString::StringsAreEqual(std::forward(readBarrier), oldValue, *str)) { @@ -643,7 +653,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol BaseString* value = *str; value->SetIsInternString(); IntegerCache::InitIntegerCache(value); - Entry* newEntry = new Entry(value); + Entry* newEntry = new Entry(hash, value); oldEntry = PruneHead(oldEntry); if (oldEntry == nullptr) { // The simple case: Create a new entry and store it. @@ -651,8 +661,7 @@ BaseString* HashTrieMap::StoreOrLoad(ThreadHol } else { // Expand an existing entry to one or more new nodes. // Release the node, which will make both oldEntry and newEntry visible - auto expandedNode = Expand(oldEntry, newEntry, - oldHash >> TrieMapConfig::ROOT_BIT, hash, hashShift, current); + auto expandedNode = Expand(oldEntry, newEntry, hash, hashShift, current); slot->store(expandedNode, std::memory_order_release); } GetMutex().Unlock(); @@ -700,8 +709,7 @@ void HashTrieMap::Iter(ReadBarrier&& readBarri if (node == nullptr) return; - for (std::atomic& temp : node->children_) { - auto &child = reinterpret_cast&>(temp); + for (std::atomic& child : node->children_) { Node* childNode = child.load(std::memory_order_relaxed); if (childNode == nullptr) continue; @@ -750,7 +758,7 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa std::vector& waitDeleteEntries) { // load sub-nodes - Node* child = parent->GetChild(index).load(std::memory_order_relaxed); + Node* child = parent->children_[index].load(std::memory_order_relaxed); if (child == nullptr) return true; @@ -785,7 +793,7 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa const WeakRefFieldVisitor& visitor) { // load sub-nodes - Node* child = parent->GetChild(index).load(std::memory_order_relaxed); + Node* child = parent->children_[index].load(std::memory_order_relaxed); if (child == nullptr) { return true; } @@ -814,12 +822,12 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa if (e == nullptr) { // Delete the empty Entry node and update the parent reference delete entry; - parent->GetChild(index).store(nullptr, std::memory_order_relaxed); + parent->children_[index].store(nullptr, std::memory_order_relaxed); return true; } // Delete the Entry node and update the parent reference delete entry; - parent->GetChild(index).store(e, std::memory_order_relaxed); + parent->children_[index].store(e, std::memory_order_relaxed); } return false; } else { @@ -835,7 +843,7 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa if (cleanCount == TrieMapConfig::INDIRECT_SIZE) { // Remove the empty Indirect and update the parent reference delete indirect; - parent->GetChild(index).store(nullptr, std::memory_order_relaxed); + parent->children_[index].store(nullptr, std::memory_order_relaxed); return true; } return false; @@ -848,7 +856,7 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa const WeakRootVisitor& visitor) { // load sub-nodes - Node* child = parent->GetChild(index).load(std::memory_order_relaxed); + Node* child = parent->children_[index].load(std::memory_order_relaxed); if (child == nullptr) return true; @@ -876,12 +884,12 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa if (e == nullptr) { // Delete the empty Entry node and update the parent reference delete entry; - parent->GetChild(index).store(nullptr, std::memory_order_relaxed); + parent->children_[index].store(nullptr, std::memory_order_relaxed); return true; } // Delete the Entry node and update the parent reference delete entry; - parent->GetChild(index).store(e, std::memory_order_relaxed); + parent->children_[index].store(e, std::memory_order_relaxed); } return false; } else { @@ -897,7 +905,7 @@ bool HashTrieMap::ClearNodeFromGC(Indirect* pa if (cleanCount == TrieMapConfig::INDIRECT_SIZE && inuseCount_ == 0) { // Remove the empty Indirect and update the parent reference delete indirect; - parent->GetChild(index).store(nullptr, std::memory_order_relaxed); + parent->children_[index].store(nullptr, std::memory_order_relaxed); return true; } return false; diff --git a/common_components/objects/string_table/hashtriemap.h b/common_components/objects/string_table/hashtriemap.h index 73c3ce032b124424758e7870d42dcc1c3f6389cf..bae8d1ed009218dc39ccf90b129d4bbb4c55f6e7 100644 --- a/common_components/objects/string_table/hashtriemap.h +++ b/common_components/objects/string_table/hashtriemap.h @@ -52,51 +52,42 @@ class HashTrieMapIndirect; class HashTrieMapNode { public: - static constexpr uint64_t POINTER_LENGTH = 63; - static constexpr uint64_t ENTRY_TAG_MASK = 1ULL << POINTER_LENGTH; - - using Pointer = BitField; - using EntryBit = Pointer::NextFlag; - - explicit HashTrieMapNode() {} + explicit HashTrieMapNode(bool isEntry) : isEntry_(isEntry) {} bool IsEntry() const { - uint64_t bitField = *reinterpret_cast(this); - return EntryBit::Decode(bitField); + return isEntry_; } HashTrieMapEntry* AsEntry(); HashTrieMapIndirect* AsIndirect(); + +private: + const bool isEntry_; }; class HashTrieMapEntry final : public HashTrieMapNode { public: - HashTrieMapEntry(BaseString* v) : overflow_(nullptr) - { - bitField_ = (ENTRY_TAG_MASK | reinterpret_cast(v)); - } + HashTrieMapEntry(uint32_t k, BaseString* v) : HashTrieMapNode(true), key_(k), value_(v), overflow_(nullptr) {} - template uint32_t Key() const { - return Value()->GetRawHashcode(); + return key_; } template BaseString* Value() const { - uint64_t value = Pointer::Decode(bitField_); if constexpr (SlotBarrier == TrieMapConfig::NoSlotBarrier) { - return reinterpret_cast(static_cast(value)); + return value_; } return reinterpret_cast(Heap::GetBarrier().ReadStringTableStaticRef( - *reinterpret_cast*>((void*)(&value)))); + *reinterpret_cast*>((void*)(&value_)))); } void SetValue(BaseString* v) { - bitField_ = ENTRY_TAG_MASK | reinterpret_cast(v); + value_ = v; } std::atomic& Overflow() @@ -105,20 +96,21 @@ public: } private: - uint64_t bitField_; + uint32_t key_; + BaseString* value_; std::atomic overflow_; }; class HashTrieMapIndirect final : public HashTrieMapNode { public: - std::array, TrieMapConfig::INDIRECT_SIZE> children_{}; + std::array, TrieMapConfig::INDIRECT_SIZE> children_{}; + HashTrieMapIndirect* parent_; - explicit HashTrieMapIndirect() {} + explicit HashTrieMapIndirect(HashTrieMapIndirect* p = nullptr) : HashTrieMapNode(false), parent_(p) {}; ~HashTrieMapIndirect() { - for (std::atomic& temp : children_) { - auto &child = reinterpret_cast&>(temp); + for (std::atomic& child : children_) { HashTrieMapNode* node = child.exchange(nullptr, std::memory_order_relaxed); if (node == nullptr) { continue; @@ -142,11 +134,6 @@ public: delete e; } } - - std::atomic& GetChild(size_t index) - { - return reinterpret_cast&>(children_[index]); - } }; struct HashTrieMapLoadResult { @@ -158,13 +145,13 @@ struct HashTrieMapLoadResult { inline HashTrieMapEntry* HashTrieMapNode::AsEntry() { - ASSERT(IsEntry() && "HashTrieMap: called entry on non-entry node"); + ASSERT(isEntry_ && "HashTrieMap: called entry on non-entry node"); return static_cast(this); } inline HashTrieMapIndirect* HashTrieMapNode::AsIndirect() { - ASSERT(!IsEntry() && "HashTrieMap: called indirect on entry node"); + ASSERT(!isEntry_ && "HashTrieMap: called indirect on entry node"); return static_cast(this); } @@ -296,7 +283,7 @@ public: return root; } else { Indirect* expected = nullptr; - Indirect* newRoot = new Indirect(); + Indirect* newRoot = new Indirect(nullptr); if (root_[rootID].compare_exchange_strong(expected, newRoot, std::memory_order_release, std::memory_order_acquire)) { @@ -396,8 +383,7 @@ private: std::atomic inuseCount_{0}; bool isSweeping{false}; template - Node* Expand(Entry* oldEntry, Entry* newEntry, - uint32_t oldHash, uint32_t newHash, uint32_t hashShift, Indirect* parent); + Node* Expand(Entry* oldEntry, Entry* newEntry, uint32_t newHash, uint32_t hashShift, Indirect* parent); template void Iter(ReadBarrier&& readBarrier, Indirect* node, bool& isValid); bool CheckWeakRef(const WeakRefFieldVisitor& visitor, Entry* entry); diff --git a/ecmascript/tests/ecma_string_table_test.cpp b/ecmascript/tests/ecma_string_table_test.cpp index f6d4ca96a3d0417865ecfd2dfa694b5fb216c102..e67e7914642e7ebd3656cb41ec5980f6430ab85a 100644 --- a/ecmascript/tests/ecma_string_table_test.cpp +++ b/ecmascript/tests/ecma_string_table_test.cpp @@ -193,8 +193,7 @@ void EcmaStringTableTest::TestLoadOrStoreConcurrentAccess() auto readBarrier = [vm](const void *obj, size_t offset) -> TaggedObject * { return Barriers::GetTaggedObject(vm->GetAssociatedJSThread(), obj, offset); }; - uint32_t key = value1->ToBaseString()->GetRawHashcode(); - ASSERT_TRUE(map->template Load(std::move(readBarrier), key, value1->ToBaseString()) != nullptr); + ASSERT_TRUE(map->template Load(std::move(readBarrier), i, value1->ToBaseString()) != nullptr); } delete map; } @@ -215,8 +214,8 @@ void EcmaStringTableTest::TestLoadOrStoreInsertNewKey() { EcmaVM* vm = thread->GetEcmaVM(); auto* map = new common::HashTrieMap(); + uint32_t key = 0x12345678; JSHandle value(thread, *vm->GetFactory()->NewFromASCII("test_value")); - uint32_t key = value->ToBaseString()->GetRawHashcode(); auto readBarrier = [vm](const void *obj, size_t offset) -> TaggedObject * { return Barriers::GetTaggedObject(vm->GetAssociatedJSThread(), obj, offset); }; @@ -253,22 +252,20 @@ void EcmaStringTableTest::TestLoadOrStoreStoreExistingKey() { EcmaVM *vm = thread->GetEcmaVM(); auto *map = new common::HashTrieMap(); - JSHandle original(thread, *vm->GetFactory()->NewFromASCII("Aa1")); - JSHandle origina2(thread, *vm->GetFactory()->NewFromASCII("BB1")); - // key1 = key2 = 0x0000FFF1 - uint32_t key1 = original->ToBaseString()->GetRawHashcode(); - uint32_t key2 = origina2->ToBaseString()->GetRawHashcode(); + uint32_t key = 0x12345678; + JSHandle original(thread, *vm->GetFactory()->NewFromASCII("original")); + JSHandle origina2(thread, *vm->GetFactory()->NewFromASCII("origina2")); // Initial insertion map->template LoadOrStore( - vm->GetJSThread(), key1, [original]() { return original; }, + vm->GetJSThread(), key, [original]() { return original; }, [this, original](BaseString *foudString) { return EcmaStringAccessor::StringsAreEqual(thread, *original, EcmaString::FromBaseString(foudString)); }); // store overflow map->template LoadOrStore( - vm->GetJSThread(), key2, [origina2]() { return origina2; }, + vm->GetJSThread(), key, [origina2]() { return origina2; }, [vm, origina2](BaseString *foudString) { return EcmaStringAccessor::StringsAreEqual(vm->GetAssociatedJSThread(), *origina2, EcmaString::FromBaseString(foudString)); @@ -276,9 +273,9 @@ void EcmaStringTableTest::TestLoadOrStoreStoreExistingKey() auto readBarrier = [vm](const void *obj, size_t offset) -> TaggedObject * { return Barriers::GetTaggedObject(vm->GetAssociatedJSThread(), obj, offset); }; - EXPECT_EQ(map->template Load(std::move(readBarrier), key1, original->ToBaseString()), + EXPECT_EQ(map->template Load(std::move(readBarrier), key, original->ToBaseString()), original->ToBaseString()); - EXPECT_EQ(map->template Load(std::move(readBarrier), key2, origina2->ToBaseString()), + EXPECT_EQ(map->template Load(std::move(readBarrier), key, origina2->ToBaseString()), origina2->ToBaseString()); delete map; } @@ -300,16 +297,15 @@ void EcmaStringTableTest::TestExpandHashCollisionHandling() { EcmaVM* vm = thread->GetEcmaVM(); auto* map = new common::HashTrieMap(); - - JSHandle value1(thread, *vm->GetFactory()->NewFromASCII("ADF3")); - JSHandle value2(thread, *vm->GetFactory()->NewFromASCII("A ?0")); - JSHandle value3(thread, *vm->GetFactory()->NewFromASCII("AAa1")); - JSHandle value4(thread, *vm->GetFactory()->NewFromASCII("ABB1")); - uint32_t key1 = value1->ToBaseString()->GetRawHashcode(); - uint32_t key2 = value2->ToBaseString()->GetRawHashcode(); - uint32_t key3 = value3->ToBaseString()->GetRawHashcode(); - uint32_t key4 = value4->ToBaseString()->GetRawHashcode(); - uint32_t ROOT_ID = key1 & common::TrieMapConfig::ROOT_BIT_MASK; + constexpr uint32_t ROOT_SIZE = common::TrieMapConfig::ROOT_BIT; + constexpr uint32_t ROOT_ID = 5; + uint32_t key1 = ((0b11111001) << ROOT_SIZE) | ROOT_ID; + uint32_t key2 = ((0b11000000) << ROOT_SIZE) | ROOT_ID; + uint32_t key3 = ((0b11010000) << ROOT_SIZE) | ROOT_ID; + JSHandle value1(thread, *vm->GetFactory()->NewFromASCII("value1")); + JSHandle value2(thread, *vm->GetFactory()->NewFromASCII("value2")); + JSHandle value3(thread, *vm->GetFactory()->NewFromASCII("value3")); + JSHandle value4(thread, *vm->GetFactory()->NewFromASCII("value4")); // Insert first key map->template LoadOrStore( vm->GetJSThread(), key1, [value1]() { return value1; }, @@ -317,13 +313,6 @@ void EcmaStringTableTest::TestExpandHashCollisionHandling() return EcmaStringAccessor::StringsAreEqual(thread, *value1, EcmaString::FromBaseString(foudString)); }); - // Insert second key causing collision - map->template LoadOrStore( - vm->GetJSThread(), key1, [value1]() { return value1; }, - [this, value1](BaseString *foudString) { - return EcmaStringAccessor::StringsAreEqual(thread, *value1, EcmaString::FromBaseString(foudString)); - }); - // Insert second key causing collision map->template LoadOrStore( vm->GetJSThread(), key2, [value2]() { return value2; }, @@ -338,42 +327,36 @@ void EcmaStringTableTest::TestExpandHashCollisionHandling() }); map->template LoadOrStore( - vm->GetJSThread(), key4, [value4]() { return value4; }, + vm->GetJSThread(), key3, [value4]() { return value4; }, [this, value4](BaseString *foudString) { return EcmaStringAccessor::StringsAreEqual(thread, *value4, EcmaString::FromBaseString(foudString)); }); /*map: └── Indirect (----) - Children: [1, 2] - └── Child[1]: + Children: [0, 1] + └── Child[0]: └── Indirect (----) Children: [0, 1] └── Child[0]: - └── Entry [key2, value=0x001E0C10] + └── Entry [key2, value=0x2bafc81e50] └── Child[2]: - └── Entry [key3, value=0x001E8C10] - └── Overflow -> └── Entry [key4, value=0x001E8C10] - └── Child[2]: - └── Entry [key1, value=0x001E9410] - key1 = 000_000_000_001_111_010_010_10000010000 - key2 = 000_000_000_001_111_000_001_10000010000 - key3 = 000_000_000_001_111_010_001_10000010000 - key4 = 000_000_000_001_111_010_001_10000010000 - + └── Entry [key3, value=0x2bafc01dd0] + └── Overflow -> └── Entry [key=286326800, value=0x2bafc01db8] + └── Child[1]: + └── Entry [key1, value=0x2bafc81e38] */ // Verify structure after expansion common::HashTrieMapIndirect* root = map->GetRoot(ROOT_ID).load(); - ASSERT_TRUE(root->GetChild(0x1).load() != nullptr); // Check first collision level + ASSERT_TRUE(root->children_[0x0].load() != nullptr); // Check first collision level - common::HashTrieMapIndirect* level1 = root->GetChild(0x1). + common::HashTrieMapIndirect* level1 = root->children_[0x0]. load()->AsIndirect(); - ASSERT_TRUE(level1->GetChild(0x0).load() != nullptr); - ASSERT_TRUE(level1->GetChild(0x2).load() != nullptr); - common::HashTrieMapEntry* entry = level1->GetChild(0x2).load()->AsEntry(); + ASSERT_TRUE(level1->children_[0x0].load() != nullptr); + ASSERT_TRUE(level1->children_[0x2].load() != nullptr); + common::HashTrieMapEntry* entry = level1->children_[0x2].load()->AsEntry(); // Verify overflow ASSERT_TRUE(entry->Overflow().load() != nullptr); - ASSERT_TRUE(root->GetChild(0x2).load() != nullptr); delete map; }