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