1/*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/js_api/js_api_lightweightmap.h"
17
18#include "ecmascript/containers/containers_errors.h"
19#include "ecmascript/js_object-inl.h"
20
21#include <codecvt>
22
23namespace panda::ecmascript {
24using ContainerError = containers::ContainerError;
25using ErrorFlag = containers::ErrorFlag;
26JSTaggedValue JSAPILightWeightMap::IncreaseCapacityTo(JSThread *thread,
27                                                      const JSHandle<JSAPILightWeightMap> &lightWeightMap,
28                                                      int32_t index)
29{
30    uint32_t num = lightWeightMap->GetSize();
31    if (index < DEFAULT_CAPACITY_LENGTH || static_cast<int32_t>(num) >= index) {
32        return JSTaggedValue::False();
33    }
34    JSHandle<TaggedArray> hashArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::HASH);
35    JSHandle<TaggedArray> keyArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::KEY);
36    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
37    JSHandle<TaggedArray> newHashArray = GrowCapacity(thread, hashArray, index);
38    JSHandle<TaggedArray> newKeyArray = GrowCapacity(thread, keyArray, index);
39    JSHandle<TaggedArray> newValueArray = GrowCapacity(thread, valueArray, index);
40    lightWeightMap->SetHashes(thread, newHashArray);
41    lightWeightMap->SetKeys(thread, newKeyArray);
42    lightWeightMap->SetValues(thread, newValueArray);
43    return JSTaggedValue::True();
44}
45
46void JSAPILightWeightMap::InsertValue(const JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
47                                      int32_t index, const JSHandle<JSTaggedValue> &value, AccossorsKind kind)
48{
49    JSHandle<TaggedArray> array = GetArrayByKind(thread, lightWeightMap, kind);
50    uint32_t len = lightWeightMap->GetSize();
51    JSHandle<TaggedArray> newArray = GrowCapacity(thread, array, len + 1);
52    TaggedArray::InsertElementByIndex(thread, newArray, value, index, len);
53    SetArrayByKind(thread, lightWeightMap, newArray, kind);
54}
55
56void JSAPILightWeightMap::ReplaceValue(const JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
57                                       int32_t index, const JSHandle<JSTaggedValue> &value, AccossorsKind kind)
58{
59    JSHandle<TaggedArray> array = GetArrayByKind(thread, lightWeightMap, kind);
60    ASSERT(0 <= index || index < static_cast<int32_t>(lightWeightMap->GetSize()));
61    array->Set(thread, index, value.GetTaggedValue());
62}
63
64void JSAPILightWeightMap::RemoveValue(const JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
65                                      uint32_t index, AccossorsKind kind)
66{
67    JSHandle<TaggedArray> array = GetArrayByKind(thread, lightWeightMap, kind);
68    uint32_t len = lightWeightMap->GetLength();
69    ASSERT(index < len);
70    TaggedArray::RemoveElementByIndex(thread, array, index, len);
71}
72
73void JSAPILightWeightMap::Set(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
74                              const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
75{
76    KeyState keyState = GetStateOfKey(thread, lightWeightMap, key);
77    int32_t index = keyState.index;
78    if (keyState.existed) {
79        ReplaceValue(thread, lightWeightMap, index, value, AccossorsKind::VALUE);
80    } else {
81        JSHandle<JSTaggedValue> hashHandle(thread, JSTaggedValue(keyState.hash));
82        InsertValue(thread, lightWeightMap, index, hashHandle, AccossorsKind::HASH);
83        InsertValue(thread, lightWeightMap, index, key, AccossorsKind::KEY);
84        InsertValue(thread, lightWeightMap, index, value, AccossorsKind::VALUE);
85        lightWeightMap->SetLength(lightWeightMap->GetLength() + 1);
86    }
87}
88
89JSTaggedValue JSAPILightWeightMap::Get(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
90                                       const JSHandle<JSTaggedValue> &key)
91{
92    int32_t index = GetIndexOfKey(thread, lightWeightMap, key);
93    if (index < 0) {
94        return JSTaggedValue::Undefined();
95    }
96    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
97    return valueArray->Get(index);
98}
99
100JSTaggedValue JSAPILightWeightMap::HasAll(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
101                                          const JSHandle<JSAPILightWeightMap> &newLightWeightMap)
102{
103    uint32_t length = newLightWeightMap->GetSize();
104    uint32_t len = lightWeightMap->GetSize();
105    if (length > len) {
106        return JSTaggedValue::False();
107    }
108    JSHandle<TaggedArray> oldHashArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::HASH);
109    JSHandle<TaggedArray> oldKeyArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::KEY);
110    JSHandle<TaggedArray> oldValueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
111    JSHandle<TaggedArray> newKeyArray = GetArrayByKind(thread, newLightWeightMap, AccossorsKind::KEY);
112    JSHandle<TaggedArray> newValueArray = GetArrayByKind(thread, newLightWeightMap, AccossorsKind::VALUE);
113    JSTaggedValue dealKey = JSTaggedValue::Undefined();
114    int32_t index = -1;
115    int32_t hash = 0;
116
117    for (uint32_t num = 0; num < length; num++) {
118        dealKey = newKeyArray->Get(num);
119        hash = Hash(thread, dealKey);
120        index = BinarySearchHashes(oldHashArray, hash, static_cast<int32_t>(len));
121        if (index < 0 || index >= static_cast<int32_t>(len)) {
122            return JSTaggedValue::False();
123        }
124        HashParams params { oldHashArray, oldKeyArray, &dealKey };
125        index = AvoidHashCollision(params, index, len, hash);
126        if (!JSTaggedValue::SameValue(oldKeyArray->Get(index), dealKey) ||
127            !JSTaggedValue::SameValue(oldValueArray->Get(index), newValueArray->Get(num))) {
128            // avoid Hash collision
129            return JSTaggedValue::False();
130        }
131    }
132    return JSTaggedValue::True();
133}
134
135JSTaggedValue JSAPILightWeightMap::HasKey(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
136                                          const JSHandle<JSTaggedValue> &key)
137{
138    KeyState keyState = GetStateOfKey(thread, lightWeightMap, key);
139    return keyState.existed ? JSTaggedValue::True() : JSTaggedValue::False();
140}
141
142JSTaggedValue JSAPILightWeightMap::HasValue(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
143                                            const JSHandle<JSTaggedValue> &value)
144{
145    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
146    uint32_t length = lightWeightMap->GetSize();
147    for (uint32_t num = 0; num < length; num++) {
148        if (JSTaggedValue::SameValue(valueArray->Get(num), value.GetTaggedValue())) {
149            return JSTaggedValue::True();
150        }
151    }
152    return JSTaggedValue::False();
153}
154
155int32_t JSAPILightWeightMap::GetIndexOfKey(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
156                                           const JSHandle<JSTaggedValue> &key)
157{
158    KeyState keyState = GetStateOfKey(thread, lightWeightMap, key);
159    return keyState.existed ? keyState.index : -1;
160}
161
162KeyState JSAPILightWeightMap::GetStateOfKey(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
163                                            const JSHandle<JSTaggedValue> &key)
164{
165    int32_t hash = Hash(thread, key.GetTaggedValue());
166    int32_t length = static_cast<int32_t>(lightWeightMap->GetSize());
167    JSHandle<TaggedArray> hashArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::HASH);
168    int32_t index = BinarySearchHashes(hashArray, hash, length);
169    if (index >= 0) {
170        // avoid Hash Collision
171        JSHandle<TaggedArray> keyArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::KEY);
172        int32_t right = index;
173        while ((right < length) && (hashArray->Get(right).GetInt() == hash)) {
174            if (JSTaggedValue::SameValue(keyArray->Get(right), key.GetTaggedValue())) {
175                return KeyState {true, hash, right};
176            }
177            right++;
178        }
179        int32_t left = index - 1;
180        while ((left >= 0) && ((hashArray->Get(left).GetInt() == hash))) {
181            if (JSTaggedValue::SameValue(keyArray->Get(left), key.GetTaggedValue())) {
182                return KeyState {true, hash, left};
183            }
184            left--;
185        }
186        return KeyState {false, hash, right}; // first index whose element is bigger than hash
187    }
188    return KeyState {false, hash, index ^ HASH_REBELLION}; // first index whose element is bigger than hash
189}
190
191int32_t JSAPILightWeightMap::GetIndexOfValue(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
192                                             const JSHandle<JSTaggedValue> &value)
193{
194    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
195    uint32_t length = lightWeightMap->GetSize();
196    JSTaggedValue compValue = value.GetTaggedValue();
197    for (uint32_t i = 0; i < length; i++) {
198        if (valueArray->Get(i) == compValue) {
199            return i;
200        }
201    }
202    return -1; // not find, default return -1
203}
204
205JSTaggedValue JSAPILightWeightMap::GetKeyAt(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
206                                            int32_t index)
207{
208    int32_t length = static_cast<int32_t>(lightWeightMap->GetSize());
209    if (length <= 0) {
210        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
211        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
212    }
213    if (index < 0 || length <= index) {
214        std::ostringstream oss;
215        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
216            << ". Received value is: " << index;
217        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
218        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
219    }
220    JSHandle<TaggedArray> keyArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::KEY);
221    return keyArray->Get(index);
222}
223
224JSTaggedValue JSAPILightWeightMap::GetValueAt(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
225                                              int32_t index)
226{
227    int32_t length = static_cast<int32_t>(lightWeightMap->GetSize());
228    if (length <= 0) {
229        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
230        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
231    }
232    if (index < 0 || length <= index) {
233        std::ostringstream oss;
234        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
235            << ". Received value is: " << index;
236        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
237        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
238    }
239    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
240    return valueArray->Get(index);
241}
242
243void JSAPILightWeightMap::SetAll(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
244                                 const JSHandle<JSAPILightWeightMap> &needLightWeightMap)
245{
246    JSHandle<TaggedArray> needKeyArray = GetArrayByKind(thread, needLightWeightMap, AccossorsKind::KEY);
247    JSHandle<TaggedArray> needValueArray = GetArrayByKind(thread, needLightWeightMap, AccossorsKind::VALUE);
248    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
249    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
250    uint32_t length = needLightWeightMap->GetSize();
251    for (uint32_t num = 0; num < length; num++) {
252        key.Update(needKeyArray->Get(num));
253        value.Update(needValueArray->Get(num));
254        JSAPILightWeightMap::Set(thread, lightWeightMap, key, value);
255    }
256}
257
258JSTaggedValue JSAPILightWeightMap::Remove(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
259                                          const JSHandle<JSTaggedValue> &key)
260{
261    KeyState keyState = GetStateOfKey(thread, lightWeightMap, key);
262    if (!keyState.existed) {
263        return JSTaggedValue::Undefined();
264    }
265    int32_t index = keyState.index;
266    JSHandle<TaggedArray> valueArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::VALUE);
267    JSTaggedValue value = valueArray->Get(index);
268    RemoveValue(thread, lightWeightMap, index, AccossorsKind::HASH);
269    RemoveValue(thread, lightWeightMap, index, AccossorsKind::VALUE);
270    RemoveValue(thread, lightWeightMap, index, AccossorsKind::KEY);
271    ASSERT(lightWeightMap->GetLength() > 0);
272    lightWeightMap->SetLength(lightWeightMap->GetLength() - 1);
273    return value;
274}
275
276JSTaggedValue JSAPILightWeightMap::RemoveAt(JSThread *thread,
277                                            const JSHandle<JSAPILightWeightMap> &lightWeightMap, int32_t index)
278{
279    uint32_t length = lightWeightMap->GetSize();
280    if (index < 0 || static_cast<int32_t>(length) <= index) {
281        return JSTaggedValue::False();
282    }
283    RemoveValue(thread, lightWeightMap, index, AccossorsKind::HASH);
284    RemoveValue(thread, lightWeightMap, index, AccossorsKind::VALUE);
285    RemoveValue(thread, lightWeightMap, index, AccossorsKind::KEY);
286    lightWeightMap->SetLength(length - 1);
287    return JSTaggedValue::True();
288}
289
290JSTaggedValue JSAPILightWeightMap::IsEmpty()
291{
292    if (GetLength() == 0) {
293        return JSTaggedValue::True();
294    } else {
295        return JSTaggedValue::False();
296    }
297}
298
299void JSAPILightWeightMap::Clear(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap)
300{
301    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
302    JSHandle<TaggedArray> hashArray = factory->NewTaggedArray(DEFAULT_CAPACITY_LENGTH);
303    JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(DEFAULT_CAPACITY_LENGTH);
304    JSHandle<TaggedArray> valueArray = factory->NewTaggedArray(DEFAULT_CAPACITY_LENGTH);
305    lightWeightMap->SetHashes(thread, hashArray.GetTaggedValue());
306    lightWeightMap->SetKeys(thread, keyArray.GetTaggedValue());
307    lightWeightMap->SetValues(thread, valueArray.GetTaggedValue());
308    lightWeightMap->SetLength(0);
309}
310
311JSTaggedValue JSAPILightWeightMap::SetValueAt(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap,
312                                              int32_t index, const JSHandle<JSTaggedValue> &value)
313{
314    int32_t length = static_cast<int32_t>(lightWeightMap->GetSize());
315    if (length <= 0) {
316        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
317        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
318    }
319    if (index < 0 || length <= index) {
320        std::ostringstream oss;
321        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
322            << ". Received value is: " << index;
323        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
324        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
325    }
326    ReplaceValue(thread, lightWeightMap, index, value, AccossorsKind::VALUE);
327    return JSTaggedValue::True();
328}
329
330int32_t JSAPILightWeightMap::AvoidHashCollision(HashParams &params, int32_t index, uint32_t size, int32_t hash)
331{
332    int32_t right = index;
333    while ((right < static_cast<int32_t>(size)) && ((params.hashArray)->Get(right).GetInt() == hash)) {
334        if (JSTaggedValue::SameValue((params.keyArray)->Get(right), *(params.key))) {
335            return right;
336        }
337        right++;
338    }
339    int32_t left = index - 1;
340    while ((left >= 0) && ((params.hashArray)->Get(left).GetInt() == hash)) {
341        if (JSTaggedValue::SameValue((params.keyArray)->Get(left), *(params.key))) {
342            return left;
343        }
344        left--;
345    }
346
347    int32_t res = (-right) ^ HASH_REBELLION;
348    return res;
349}
350
351JSTaggedValue JSAPILightWeightMap::GetIteratorObj(JSThread *thread, const JSHandle<JSAPILightWeightMap> &obj,
352                                                  IterationKind type)
353{
354    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
355    JSHandle<JSAPILightWeightMapIterator> iter(factory->NewJSAPILightWeightMapIterator(obj, type));
356
357    return iter.GetTaggedValue();
358}
359
360JSTaggedValue JSAPILightWeightMap::ToString(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap)
361{
362    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
363    std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
364    std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
365    uint32_t length = lightWeightMap->GetLength();
366    std::u16string concatStr;
367    JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
368    JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
369
370    for (uint32_t k = 0; k < length; k++) {
371        std::u16string valueStr;
372        valueHandle.Update(lightWeightMap->GetValueAt(thread, lightWeightMap, k));
373        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374        if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
375            JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
376            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
377            valueStr = EcmaStringAccessor(valueStringHandle).ToU16String();
378        }
379
380        std::u16string nextStr;
381        keyHandle.Update(lightWeightMap->GetKeyAt(thread, lightWeightMap, k));
382        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
383        if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
384            JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
385            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
386            nextStr = EcmaStringAccessor(keyStringHandle).ToU16String();
387        }
388
389        nextStr.append(colonStr);
390        nextStr.append(valueStr);
391
392        if (k > 0) {
393            concatStr.append(sepStr);
394            concatStr.append(nextStr);
395            continue;
396        }
397        concatStr.append(nextStr);
398    }
399
400    char16_t *char16tData = concatStr.data();
401    auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
402    uint32_t u16strSize = concatStr.size();
403    return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
404}
405
406JSHandle<TaggedArray> JSAPILightWeightMap::GrowCapacity(const JSThread *thread, JSHandle<TaggedArray> &oldArray,
407                                                        uint32_t needCapacity)
408{
409    uint32_t oldLength = oldArray->GetLength();
410    if (needCapacity <= oldLength) {
411        return oldArray;
412    }
413    uint32_t newCapacity = ComputeCapacity(needCapacity);
414    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
415    JSHandle<TaggedArray> newArray = factory->CopyArray(oldArray, oldLength, newCapacity);
416    return newArray;
417}
418
419void JSAPILightWeightMap::SetArrayByKind(const JSThread *thread,
420                                         const JSHandle<JSAPILightWeightMap> &lightWeightMap,
421                                         const JSHandle<TaggedArray> &array,
422                                         AccossorsKind kind)
423{
424    switch (kind) {
425        case AccossorsKind::HASH:
426            lightWeightMap->SetHashes(thread, array);
427            break;
428        case AccossorsKind::KEY:
429            lightWeightMap->SetKeys(thread, array);
430            break;
431        case AccossorsKind::VALUE:
432            lightWeightMap->SetValues(thread, array);
433            break;
434        default:
435            LOG_ECMA(FATAL) << "this branch is unreachable";
436            UNREACHABLE();
437    }
438}
439
440JSHandle<TaggedArray> JSAPILightWeightMap::GetArrayByKind(const JSThread *thread,
441                                                          const JSHandle<JSAPILightWeightMap> &lightWeightMap,
442                                                          AccossorsKind kind)
443{
444    JSHandle<TaggedArray> array;
445    switch (kind) {
446        case AccossorsKind::HASH:
447            array = JSHandle<TaggedArray>(thread, lightWeightMap->GetHashes());
448            break;
449        case AccossorsKind::KEY:
450            array = JSHandle<TaggedArray>(thread, lightWeightMap->GetKeys());
451            break;
452        case AccossorsKind::VALUE:
453            array = JSHandle<TaggedArray>(thread, lightWeightMap->GetValues());
454            break;
455        default:
456            LOG_ECMA(FATAL) << "this branch is unreachable";
457            UNREACHABLE();
458    }
459    return array;
460}
461
462int32_t JSAPILightWeightMap::Hash(const JSThread *thread, JSTaggedValue key)
463{
464    if (key.IsDouble() && key.GetDouble() == 0.0) {
465        key = JSTaggedValue(0);
466    }
467    if (key.IsSymbol()) {
468        auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
469        return symbolString->GetHashField();
470    }
471    if (key.IsString()) {
472        auto keyString = EcmaString::Cast(key.GetTaggedObject());
473        return EcmaStringAccessor(keyString).GetHashcode();
474    }
475    if (key.IsECMAObject()) {
476        uint32_t hash = static_cast<uint32_t>(ECMAObject::Cast(key.GetTaggedObject())->GetHash());
477        if (hash == 0) {
478            hash = base::RandomGenerator::GenerateIdentityHash();
479            JSHandle<ECMAObject> ecmaObj(thread, key);
480            ECMAObject::SetHash(thread, hash, ecmaObj);
481        }
482        return hash;
483    }
484    if (key.IsInt()) {
485        int32_t hash = key.GetInt();
486        return hash;
487    }
488    if (key.IsBigInt()) {
489        uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0);
490        return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
491    }
492    uint64_t keyValue = key.GetRawData();
493    return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
494}
495
496int32_t JSAPILightWeightMap::BinarySearchHashes(JSHandle<TaggedArray> &array, int32_t hash, int32_t size)
497{
498    int32_t low = 0;
499    int32_t high = size - 1;
500    while (low <= high) {
501        uint32_t mid = static_cast<uint32_t>(low + high) >> 1U;
502        int32_t midHash = array->Get(mid).GetInt();
503        if (midHash < hash) {
504            low = static_cast<int32_t>(mid) + 1;
505        } else {
506            if (midHash == hash) {
507                return mid;
508            }
509            high = static_cast<int32_t>(mid) - 1;
510        }
511    }
512    return -(low + 1);
513}
514}  // namespace panda::ecmascript
515