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