• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
IncreaseCapacityTo(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index)26 JSTaggedValue 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 
InsertValue(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index,const JSHandle<JSTaggedValue> & value,AccossorsKind kind)46 void 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 
ReplaceValue(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index,const JSHandle<JSTaggedValue> & value,AccossorsKind kind)56 void 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 
RemoveValue(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,uint32_t index,AccossorsKind kind)64 void 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 
Set(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)73 void 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 
Get(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key)89 JSTaggedValue 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(thread, index);
98 }
99 
HasAll(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSAPILightWeightMap> & newLightWeightMap)100 JSTaggedValue 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(thread, num);
119         hash = Hash(thread, dealKey);
120         index = BinarySearchHashes(thread, 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(thread, params, index, len, hash);
126         if (!JSTaggedValue::SameValue(thread, oldKeyArray->Get(thread, index), dealKey) ||
127             !JSTaggedValue::SameValue(thread, oldValueArray->Get(thread, index), newValueArray->Get(thread, num))) {
128             // avoid Hash collision
129             return JSTaggedValue::False();
130         }
131     }
132     return JSTaggedValue::True();
133 }
134 
HasKey(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key)135 JSTaggedValue 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 
HasValue(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & value)142 JSTaggedValue 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(thread, valueArray->Get(thread, num), value.GetTaggedValue())) {
149             return JSTaggedValue::True();
150         }
151     }
152     return JSTaggedValue::False();
153 }
154 
GetIndexOfKey(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key)155 int32_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 
GetStateOfKey(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key)162 KeyState 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(thread, 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(thread, right).GetInt() == hash)) {
174             if (JSTaggedValue::SameValue(thread, keyArray->Get(thread, 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(thread, left).GetInt() == hash))) {
181             if (JSTaggedValue::SameValue(thread, keyArray->Get(thread, 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 
GetIndexOfValue(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & value)191 int32_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(thread, i) == compValue) {
199             return i;
200         }
201     }
202     return -1; // not find, default return -1
203 }
204 
GetKeyAt(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index)205 JSTaggedValue 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(thread, index);
222 }
223 
GetValueAt(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index)224 JSTaggedValue 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(thread, index);
241 }
242 
SetAll(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSAPILightWeightMap> & needLightWeightMap)243 void 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(thread, num));
253         value.Update(needValueArray->Get(thread, num));
254         JSAPILightWeightMap::Set(thread, lightWeightMap, key, value);
255     }
256 }
257 
Remove(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<JSTaggedValue> & key)258 JSTaggedValue 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(thread, 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 
RemoveAt(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index)276 JSTaggedValue 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 
IsEmpty()290 JSTaggedValue JSAPILightWeightMap::IsEmpty()
291 {
292     if (GetLength() == 0) {
293         return JSTaggedValue::True();
294     } else {
295         return JSTaggedValue::False();
296     }
297 }
298 
Clear(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap)299 void 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 
SetValueAt(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,int32_t index,const JSHandle<JSTaggedValue> & value)311 JSTaggedValue 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 
AvoidHashCollision(const JSThread * thread,HashParams & params,int32_t index,uint32_t size,int32_t hash)330 int32_t JSAPILightWeightMap::AvoidHashCollision(const JSThread *thread, HashParams &params, int32_t index,
331                                                 uint32_t size, int32_t hash)
332 {
333     int32_t right = index;
334     while ((right < static_cast<int32_t>(size)) && ((params.hashArray)->Get(thread, right).GetInt() == hash)) {
335         if (JSTaggedValue::SameValue(thread, (params.keyArray)->Get(thread, right), *(params.key))) {
336             return right;
337         }
338         right++;
339     }
340     int32_t left = index - 1;
341     while ((left >= 0) && ((params.hashArray)->Get(thread, left).GetInt() == hash)) {
342         if (JSTaggedValue::SameValue(thread, (params.keyArray)->Get(thread, left), *(params.key))) {
343             return left;
344         }
345         left--;
346     }
347 
348     int32_t res = (-right) ^ HASH_REBELLION;
349     return res;
350 }
351 
GetIteratorObj(JSThread * thread,const JSHandle<JSAPILightWeightMap> & obj,IterationKind type)352 JSTaggedValue JSAPILightWeightMap::GetIteratorObj(JSThread *thread, const JSHandle<JSAPILightWeightMap> &obj,
353                                                   IterationKind type)
354 {
355     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
356     JSHandle<JSAPILightWeightMapIterator> iter(factory->NewJSAPILightWeightMapIterator(obj, type));
357 
358     return iter.GetTaggedValue();
359 }
360 
ToString(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap)361 JSTaggedValue JSAPILightWeightMap::ToString(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap)
362 {
363     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
364     std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
365     std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
366     uint32_t length = lightWeightMap->GetLength();
367     std::u16string concatStr;
368     JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
369     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
370 
371     for (uint32_t k = 0; k < length; k++) {
372         std::u16string valueStr;
373         valueHandle.Update(lightWeightMap->GetValueAt(thread, lightWeightMap, k));
374         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
375         if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
376             JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
377             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
378             valueStr = EcmaStringAccessor(valueStringHandle).ToU16String(thread);
379         }
380 
381         std::u16string nextStr;
382         keyHandle.Update(lightWeightMap->GetKeyAt(thread, lightWeightMap, k));
383         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
384         if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
385             JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
386             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
387             nextStr = EcmaStringAccessor(keyStringHandle).ToU16String(thread);
388         }
389 
390         nextStr.append(colonStr);
391         nextStr.append(valueStr);
392 
393         if (k > 0) {
394             concatStr.append(sepStr);
395             concatStr.append(nextStr);
396             continue;
397         }
398         concatStr.append(nextStr);
399     }
400 
401     char16_t *char16tData = concatStr.data();
402     auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
403     uint32_t u16strSize = concatStr.size();
404     return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
405 }
406 
GrowCapacity(const JSThread * thread,JSHandle<TaggedArray> & oldArray,uint32_t needCapacity)407 JSHandle<TaggedArray> JSAPILightWeightMap::GrowCapacity(const JSThread *thread, JSHandle<TaggedArray> &oldArray,
408                                                         uint32_t needCapacity)
409 {
410     uint32_t oldLength = oldArray->GetLength();
411     if (needCapacity <= oldLength) {
412         return oldArray;
413     }
414     uint32_t newCapacity = ComputeCapacity(needCapacity);
415     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
416     JSHandle<TaggedArray> newArray = factory->CopyArray(oldArray, oldLength, newCapacity);
417     return newArray;
418 }
419 
SetArrayByKind(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<TaggedArray> & array,AccossorsKind kind)420 void JSAPILightWeightMap::SetArrayByKind(const JSThread *thread,
421                                          const JSHandle<JSAPILightWeightMap> &lightWeightMap,
422                                          const JSHandle<TaggedArray> &array,
423                                          AccossorsKind kind)
424 {
425     switch (kind) {
426         case AccossorsKind::HASH:
427             lightWeightMap->SetHashes(thread, array);
428             break;
429         case AccossorsKind::KEY:
430             lightWeightMap->SetKeys(thread, array);
431             break;
432         case AccossorsKind::VALUE:
433             lightWeightMap->SetValues(thread, array);
434             break;
435         default:
436             LOG_ECMA(FATAL) << "this branch is unreachable";
437             UNREACHABLE();
438     }
439 }
440 
GetArrayByKind(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,AccossorsKind kind)441 JSHandle<TaggedArray> JSAPILightWeightMap::GetArrayByKind(const JSThread *thread,
442                                                           const JSHandle<JSAPILightWeightMap> &lightWeightMap,
443                                                           AccossorsKind kind)
444 {
445     JSHandle<TaggedArray> array;
446     switch (kind) {
447         case AccossorsKind::HASH:
448             array = JSHandle<TaggedArray>(thread, lightWeightMap->GetHashes(thread));
449             break;
450         case AccossorsKind::KEY:
451             array = JSHandle<TaggedArray>(thread, lightWeightMap->GetKeys(thread));
452             break;
453         case AccossorsKind::VALUE:
454             array = JSHandle<TaggedArray>(thread, lightWeightMap->GetValues(thread));
455             break;
456         default:
457             LOG_ECMA(FATAL) << "this branch is unreachable";
458             UNREACHABLE();
459     }
460     return array;
461 }
462 
Hash(const JSThread * thread,JSTaggedValue key)463 int32_t JSAPILightWeightMap::Hash(const JSThread *thread, JSTaggedValue key)
464 {
465     if (key.IsDouble() && key.GetDouble() == 0.0) {
466         key = JSTaggedValue(0);
467     }
468     if (key.IsSymbol()) {
469         auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
470         return symbolString->GetHashField();
471     }
472     if (key.IsString()) {
473         auto keyString = EcmaString::Cast(key.GetTaggedObject());
474         return EcmaStringAccessor(keyString).GetHashcode(thread);
475     }
476     if (key.IsECMAObject()) {
477         uint32_t hash = static_cast<uint32_t>(ECMAObject::Cast(key.GetTaggedObject())->GetHash(thread));
478         if (hash == 0) {
479             hash = base::RandomGenerator::GenerateIdentityHash();
480             JSHandle<ECMAObject> ecmaObj(thread, key);
481             ECMAObject::SetHash(thread, hash, ecmaObj);
482         }
483         return hash;
484     }
485     if (key.IsInt()) {
486         int32_t hash = key.GetInt();
487         return hash;
488     }
489     if (key.IsBigInt()) {
490         uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0);
491         return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
492     }
493     uint64_t keyValue = key.GetRawData();
494     return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
495 }
496 
BinarySearchHashes(const JSThread * thread,JSHandle<TaggedArray> & array,int32_t hash,int32_t size)497 int32_t JSAPILightWeightMap::BinarySearchHashes(const JSThread *thread, JSHandle<TaggedArray> &array, int32_t hash,
498                                                 int32_t size)
499 {
500     int32_t low = 0;
501     int32_t high = size - 1;
502     while (low <= high) {
503         uint32_t mid = static_cast<uint32_t>(low + high) >> 1U;
504         int32_t midHash = array->Get(thread, mid).GetInt();
505         if (midHash < hash) {
506             low = static_cast<int32_t>(mid) + 1;
507         } else {
508             if (midHash == hash) {
509                 return mid;
510             }
511             high = static_cast<int32_t>(mid) - 1;
512         }
513     }
514     return -(low + 1);
515 }
516 }  // namespace panda::ecmascript
517