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 ¶ms, 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