From 6d26f25f8b9ee4ad0ffc965d9ce278638b70b4a9 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Thu, 17 Jul 2025 17:21:01 +0800 Subject: [PATCH] use integer as hash for contained Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICN18D Signed-off-by: ZhouGuangyuan Change-Id: If9f870d1a63e2b75bb90434c8cff085eedadcf6c --- ecmascript/ecma_string.cpp | 12 ++++- ecmascript/js_api/js_api_hashmap.cpp | 55 +++++++++++++++++++-- ecmascript/js_api/js_api_hashmap.h | 1 + ecmascript/js_api/js_api_hashset.cpp | 51 +++++++++++++++++-- ecmascript/js_api/js_api_hashset.h | 2 +- ecmascript/js_api/js_api_lightweightmap.cpp | 7 ++- ecmascript/js_api/js_api_lightweightset.cpp | 7 ++- 7 files changed, 123 insertions(+), 12 deletions(-) diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index ffde10ca1c..27dd830e3f 100755 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -613,11 +613,21 @@ bool EcmaString::ToElementIndex(const JSThread *thread, uint32_t *index) if (UNLIKELY(IsUtf16())) { return false; } - + common::IntegerCache *cache = nullptr; + if ((len <= common::IntegerCache::MAX_INTEGER_CACHE_SIZE) && IsInternString()) { + cache = common::IntegerCache::Extract(this->ToBaseString()); + if (cache->IsInteger()) { + *index = cache->GetInteger(); + return true; + } + } CVector buf; const uint8_t *data = EcmaString::GetUtf8DataFlat(thread, this, buf); constexpr uint64_t maxValue = std::numeric_limits::max() - 1; if (NumberHelper::StringToUint(std::basic_string_view(data, GetLength()), *index, maxValue)) { + if (cache != nullptr) { + cache->SetInteger(*index); + } return true; } return false; diff --git a/ecmascript/js_api/js_api_hashmap.cpp b/ecmascript/js_api/js_api_hashmap.cpp index d346e5ce00..5d2882cad2 100644 --- a/ecmascript/js_api/js_api_hashmap.cpp +++ b/ecmascript/js_api/js_api_hashmap.cpp @@ -29,7 +29,7 @@ JSTaggedValue JSAPIHashMap::IsEmpty() JSTaggedValue JSAPIHashMap::HasKey(JSThread *thread, JSTaggedValue key) { TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable(thread).GetTaggedObject()); - int hash = TaggedNode::Hash(thread, key); + int hash = JSAPIHashMap::Hash(thread, key); return JSTaggedValue(!(hashArray->GetNode(thread, hash, key).IsHole())); } @@ -91,7 +91,7 @@ bool JSAPIHashMap::HasValueRBTreeNode(JSThread *thread, JSTaggedValue node, JSTa bool JSAPIHashMap::Replace(JSThread *thread, JSTaggedValue key, JSTaggedValue newValue) { TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable(thread).GetTaggedObject()); - int hash = TaggedNode::Hash(thread, key); + int hash = JSAPIHashMap::Hash(thread, key); JSTaggedValue nodeVa = hashArray->GetNode(thread, hash, key); if (nodeVa.IsHole()) { return false; @@ -115,7 +115,7 @@ void JSAPIHashMap::Set(JSThread *thread, JSHandle hashMap, THROW_NEW_ERROR_AND_RETURN(thread, error); } JSHandle hashArray(thread, hashMap->GetTable(thread)); - int hash = TaggedNode::Hash(thread, key.GetTaggedValue()); + int hash = JSAPIHashMap::Hash(thread, key.GetTaggedValue()); JSTaggedValue setValue = TaggedHashArray::SetVal(thread, hashArray, hash, key, value); uint32_t nodeNum = hashMap->GetSize(); if (!setValue.IsUndefined()) { @@ -131,7 +131,7 @@ void JSAPIHashMap::Set(JSThread *thread, JSHandle hashMap, JSTaggedValue JSAPIHashMap::Get(JSThread *thread, JSTaggedValue key) { TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable(thread).GetTaggedObject()); - int hash = TaggedNode::Hash(thread, key); + int hash = JSAPIHashMap::Hash(thread, key); JSTaggedValue node = hashArray->GetNode(thread, hash, key); if (node.IsHole()) { return JSTaggedValue::Undefined(); @@ -212,7 +212,7 @@ JSTaggedValue JSAPIHashMap::Remove(JSThread *thread, JSHandle hash if (nodeNum == 0) { return JSTaggedValue::Undefined(); } - uint32_t hash = static_cast(TaggedNode::Hash(thread, key)); + uint32_t hash = static_cast(JSAPIHashMap::Hash(thread, key)); JSHandle removeValue(thread, hashArray->RemoveNode(thread, hash, key)); if (removeValue->IsHole()) { return JSTaggedValue::Undefined(); @@ -234,4 +234,49 @@ JSTaggedValue JSAPIHashMap::Remove(JSThread *thread, JSHandle hash } return removeValue.GetTaggedValue(); } + +int JSAPIHashMap::Hash(const JSThread *thread, JSTaggedValue key) +{ + if (key.IsInt()) { + return key.GetInt(); + } + if (key.IsDouble()) { + double keyDoubleVal = key.GetDouble(); + int32_t tryIntKey = static_cast(keyDoubleVal); + if (tryIntKey == keyDoubleVal) { + return tryIntKey; + } + uint64_t keyValue = key.GetRawData(); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } + if (key.IsSymbol()) { + auto symbolString = JSSymbol::Cast(key.GetTaggedObject()); + return static_cast(symbolString->GetHashField()).GetInt(); + } + if (key.IsString()) { + auto keyString = reinterpret_cast(key.GetTaggedObject()); + EcmaStringAccessor strAcc(keyString); + uint32_t index = 0; + if (strAcc.ToElementIndex(thread, &index)) { + return index; + } + return strAcc.GetHashcode(thread); + } + if (key.IsECMAObject()) { + int32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread); + if (hash == 0) { + hash = base::RandomGenerator::GenerateIdentityHash(); + JSHandle ecmaObj(thread, key); + ECMAObject::Cast(key.GetTaggedObject())->SetHash(thread, hash, ecmaObj); + } + return hash; + } + if (key.IsBigInt()) { + uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } + // Special and HeapObject(except symbol and string) + uint64_t keyValue = key.GetRawData(); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); +} } diff --git a/ecmascript/js_api/js_api_hashmap.h b/ecmascript/js_api/js_api_hashmap.h index dafbb96d9b..836775b3e1 100644 --- a/ecmascript/js_api/js_api_hashmap.h +++ b/ecmascript/js_api/js_api_hashmap.h @@ -32,6 +32,7 @@ public: static void Set(JSThread *thread, JSHandle hashMap, JSHandle key, JSHandle value); + static int Hash(const JSThread *thread, JSTaggedValue key); static JSTaggedValue HasValue(JSThread *thread, JSHandle hashMap, JSHandle value); static void SetAll(JSThread *thread, JSHandle dst, JSHandle src); diff --git a/ecmascript/js_api/js_api_hashset.cpp b/ecmascript/js_api/js_api_hashset.cpp index 64b1a85f25..3e55f36200 100644 --- a/ecmascript/js_api/js_api_hashset.cpp +++ b/ecmascript/js_api/js_api_hashset.cpp @@ -37,7 +37,7 @@ JSTaggedValue JSAPIHashSet::Has(JSThread *thread, JSTaggedValue value) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable(thread).GetTaggedObject()); - int hash = TaggedNode::Hash(thread, value); + int hash = JSAPIHashSet::Hash(thread, value); return JSTaggedValue(!(hashArray->GetNode(thread, hash, value).IsHole())); } @@ -51,7 +51,7 @@ void JSAPIHashSet::Add(JSThread *thread, JSHandle hashSet, JSHandl THROW_NEW_ERROR_AND_RETURN(thread, error); } JSHandle hashArray(thread, hashSet->GetTable(thread)); - int hash = TaggedNode::Hash(thread, value.GetTaggedValue()); + int hash = JSAPIHashSet::Hash(thread, value.GetTaggedValue()); JSHandle nullHandle(thread, JSTaggedValue::Null()); JSTaggedValue setValue = TaggedHashArray::SetVal(thread, hashArray, hash, value, nullHandle); uint32_t nodeNum = hashSet->GetSize(); @@ -91,7 +91,7 @@ JSTaggedValue JSAPIHashSet::Remove(JSThread *thread, JSHandle hash if (nodeNum == 0) { return JSTaggedValue::False(); } - uint32_t hash = static_cast(TaggedNode::Hash(thread, key)); + uint32_t hash = static_cast(JSAPIHashSet::Hash(thread, key)); JSTaggedValue removeValue = hashArray->RemoveNode(thread, hash, key); if (removeValue.IsHole()) { return JSTaggedValue::False(); @@ -111,4 +111,49 @@ JSTaggedValue JSAPIHashSet::Remove(JSThread *thread, JSHandle hash } return JSTaggedValue::True(); } + +int JSAPIHashSet::Hash(const JSThread *thread, JSTaggedValue key) +{ + if (key.IsInt()) { + return key.GetInt(); + } + if (key.IsDouble()) { + double keyDoubleVal = key.GetDouble(); + int32_t tryIntKey = static_cast(keyDoubleVal); + if (tryIntKey == keyDoubleVal) { + return tryIntKey; + } + uint64_t keyValue = key.GetRawData(); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } + if (key.IsSymbol()) { + auto symbolString = JSSymbol::Cast(key.GetTaggedObject()); + return static_cast(symbolString->GetHashField()).GetInt(); + } + if (key.IsString()) { + auto keyString = reinterpret_cast(key.GetTaggedObject()); + EcmaStringAccessor strAcc(keyString); + uint32_t index = 0; + if (strAcc.ToElementIndex(thread, &index)) { + return index; + } + return strAcc.GetHashcode(thread); + } + if (key.IsECMAObject()) { + int32_t hash = ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread); + if (hash == 0) { + hash = base::RandomGenerator::GenerateIdentityHash(); + JSHandle ecmaObj(thread, key); + ECMAObject::Cast(key.GetTaggedObject())->SetHash(thread, hash, ecmaObj); + } + return hash; + } + if (key.IsBigInt()) { + uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); + } + // Special and HeapObject(except symbol and string) + uint64_t keyValue = key.GetRawData(); + return GetHash32(reinterpret_cast(&keyValue), sizeof(keyValue) / sizeof(uint8_t)); +} } diff --git a/ecmascript/js_api/js_api_hashset.h b/ecmascript/js_api/js_api_hashset.h index 59dbaab5f7..f22c8fd7a0 100644 --- a/ecmascript/js_api/js_api_hashset.h +++ b/ecmascript/js_api/js_api_hashset.h @@ -29,7 +29,7 @@ public: } static void Add(JSThread *thread, JSHandle hashSet, JSHandle value); static JSTaggedValue Remove(JSThread *thread, JSHandle hashSet, JSTaggedValue key); - + static int Hash(const JSThread *thread, JSTaggedValue key); JSTaggedValue IsEmpty(); JSTaggedValue Has(JSThread *thread, JSTaggedValue value); void Clear(JSThread *thread); diff --git a/ecmascript/js_api/js_api_lightweightmap.cpp b/ecmascript/js_api/js_api_lightweightmap.cpp index a341b3b61f..dc804c13bc 100644 --- a/ecmascript/js_api/js_api_lightweightmap.cpp +++ b/ecmascript/js_api/js_api_lightweightmap.cpp @@ -471,7 +471,12 @@ int32_t JSAPILightWeightMap::Hash(const JSThread *thread, JSTaggedValue key) } if (key.IsString()) { auto keyString = EcmaString::Cast(key.GetTaggedObject()); - return EcmaStringAccessor(keyString).GetHashcode(thread); + EcmaStringAccessor strAcc(keyString); + uint32_t index = 0; + if (strAcc.ToElementIndex(thread, &index)) { + return index; + } + return strAcc.GetHashcode(thread); } if (key.IsECMAObject()) { uint32_t hash = static_cast(ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread)); diff --git a/ecmascript/js_api/js_api_lightweightset.cpp b/ecmascript/js_api/js_api_lightweightset.cpp index ca89ccf033..ed88962f7c 100644 --- a/ecmascript/js_api/js_api_lightweightset.cpp +++ b/ecmascript/js_api/js_api_lightweightset.cpp @@ -459,7 +459,12 @@ uint32_t JSAPILightWeightSet::Hash(const JSThread *thread, JSTaggedValue key) } if (key.IsString()) { auto keyString = EcmaString::Cast(key.GetTaggedObject()); - return EcmaStringAccessor(keyString).GetHashcode(thread); + EcmaStringAccessor strAcc(keyString); + uint32_t index = 0; + if (strAcc.ToElementIndex(thread, &index)) { + return index; + } + return strAcc.GetHashcode(thread); } if (key.IsECMAObject()) { uint32_t hash = static_cast(ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread)); -- Gitee