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(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(num);
119 hash = Hash(thread, dealKey);
120 index = BinarySearchHashes(oldHashArray, hash, static_cast<int32_t>(len));
121 if (index < 0 || index >= static_cast<int32_t>(len)) {
122 return JSTaggedValue::False();
123 }
124 HashParams params { oldHashArray, oldKeyArray, &dealKey };
125 index = AvoidHashCollision(params, index, len, hash);
126 if (!JSTaggedValue::SameValue(oldKeyArray->Get(index), dealKey) ||
127 !JSTaggedValue::SameValue(oldValueArray->Get(index), newValueArray->Get(num))) {
128 // avoid Hash collision
129 return JSTaggedValue::False();
130 }
131 }
132 return JSTaggedValue::True();
133 }
134
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(valueArray->Get(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(hashArray, hash, length);
169 if (index >= 0) {
170 // avoid Hash Collision
171 JSHandle<TaggedArray> keyArray = GetArrayByKind(thread, lightWeightMap, AccossorsKind::KEY);
172 int32_t right = index;
173 while ((right < length) && (hashArray->Get(right).GetInt() == hash)) {
174 if (JSTaggedValue::SameValue(keyArray->Get(right), key.GetTaggedValue())) {
175 return KeyState {true, hash, right};
176 }
177 right++;
178 }
179 int32_t left = index - 1;
180 while ((left >= 0) && ((hashArray->Get(left).GetInt() == hash))) {
181 if (JSTaggedValue::SameValue(keyArray->Get(left), key.GetTaggedValue())) {
182 return KeyState {true, hash, left};
183 }
184 left--;
185 }
186 return KeyState {false, hash, right}; // first index whose element is bigger than hash
187 }
188 return KeyState {false, hash, index ^ HASH_REBELLION}; // first index whose element is bigger than hash
189 }
190
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(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(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(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(num));
253 value.Update(needValueArray->Get(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(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(HashParams & params,int32_t index,uint32_t size,int32_t hash)330 int32_t JSAPILightWeightMap::AvoidHashCollision(HashParams ¶ms, int32_t index, uint32_t size, int32_t hash)
331 {
332 int32_t right = index;
333 while ((right < static_cast<int32_t>(size)) && ((params.hashArray)->Get(right).GetInt() == hash)) {
334 if (JSTaggedValue::SameValue((params.keyArray)->Get(right), *(params.key))) {
335 return right;
336 }
337 right++;
338 }
339 int32_t left = index - 1;
340 while ((left >= 0) && ((params.hashArray)->Get(left).GetInt() == hash)) {
341 if (JSTaggedValue::SameValue((params.keyArray)->Get(left), *(params.key))) {
342 return left;
343 }
344 left--;
345 }
346
347 int32_t res = (-right) ^ HASH_REBELLION;
348 return res;
349 }
350
GetIteratorObj(JSThread * thread,const JSHandle<JSAPILightWeightMap> & obj,IterationKind type)351 JSTaggedValue JSAPILightWeightMap::GetIteratorObj(JSThread *thread, const JSHandle<JSAPILightWeightMap> &obj,
352 IterationKind type)
353 {
354 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
355 JSHandle<JSAPILightWeightMapIterator> iter(factory->NewJSAPILightWeightMapIterator(obj, type));
356
357 return iter.GetTaggedValue();
358 }
359
ToString(JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap)360 JSTaggedValue JSAPILightWeightMap::ToString(JSThread *thread, const JSHandle<JSAPILightWeightMap> &lightWeightMap)
361 {
362 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
363 std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
364 std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
365 uint32_t length = lightWeightMap->GetLength();
366 std::u16string concatStr;
367 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
368 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
369
370 for (uint32_t k = 0; k < length; k++) {
371 std::u16string valueStr;
372 valueHandle.Update(lightWeightMap->GetValueAt(thread, lightWeightMap, k));
373 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374 if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
375 JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
376 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
377 valueStr = EcmaStringAccessor(valueStringHandle).ToU16String();
378 }
379
380 std::u16string nextStr;
381 keyHandle.Update(lightWeightMap->GetKeyAt(thread, lightWeightMap, k));
382 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
383 if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
384 JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
385 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
386 nextStr = EcmaStringAccessor(keyStringHandle).ToU16String();
387 }
388
389 nextStr.append(colonStr);
390 nextStr.append(valueStr);
391
392 if (k > 0) {
393 concatStr.append(sepStr);
394 concatStr.append(nextStr);
395 continue;
396 }
397 concatStr.append(nextStr);
398 }
399
400 char16_t *char16tData = concatStr.data();
401 auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
402 uint32_t u16strSize = concatStr.size();
403 return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
404 }
405
GrowCapacity(const JSThread * thread,JSHandle<TaggedArray> & oldArray,uint32_t needCapacity)406 JSHandle<TaggedArray> JSAPILightWeightMap::GrowCapacity(const JSThread *thread, JSHandle<TaggedArray> &oldArray,
407 uint32_t needCapacity)
408 {
409 uint32_t oldLength = oldArray->GetLength();
410 if (needCapacity <= oldLength) {
411 return oldArray;
412 }
413 uint32_t newCapacity = ComputeCapacity(needCapacity);
414 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
415 JSHandle<TaggedArray> newArray = factory->CopyArray(oldArray, oldLength, newCapacity);
416 return newArray;
417 }
418
SetArrayByKind(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,const JSHandle<TaggedArray> & array,AccossorsKind kind)419 void JSAPILightWeightMap::SetArrayByKind(const JSThread *thread,
420 const JSHandle<JSAPILightWeightMap> &lightWeightMap,
421 const JSHandle<TaggedArray> &array,
422 AccossorsKind kind)
423 {
424 switch (kind) {
425 case AccossorsKind::HASH:
426 lightWeightMap->SetHashes(thread, array);
427 break;
428 case AccossorsKind::KEY:
429 lightWeightMap->SetKeys(thread, array);
430 break;
431 case AccossorsKind::VALUE:
432 lightWeightMap->SetValues(thread, array);
433 break;
434 default:
435 LOG_ECMA(FATAL) << "this branch is unreachable";
436 UNREACHABLE();
437 }
438 }
439
GetArrayByKind(const JSThread * thread,const JSHandle<JSAPILightWeightMap> & lightWeightMap,AccossorsKind kind)440 JSHandle<TaggedArray> JSAPILightWeightMap::GetArrayByKind(const JSThread *thread,
441 const JSHandle<JSAPILightWeightMap> &lightWeightMap,
442 AccossorsKind kind)
443 {
444 JSHandle<TaggedArray> array;
445 switch (kind) {
446 case AccossorsKind::HASH:
447 array = JSHandle<TaggedArray>(thread, lightWeightMap->GetHashes());
448 break;
449 case AccossorsKind::KEY:
450 array = JSHandle<TaggedArray>(thread, lightWeightMap->GetKeys());
451 break;
452 case AccossorsKind::VALUE:
453 array = JSHandle<TaggedArray>(thread, lightWeightMap->GetValues());
454 break;
455 default:
456 LOG_ECMA(FATAL) << "this branch is unreachable";
457 UNREACHABLE();
458 }
459 return array;
460 }
461
Hash(const JSThread * thread,JSTaggedValue key)462 int32_t JSAPILightWeightMap::Hash(const JSThread *thread, JSTaggedValue key)
463 {
464 if (key.IsDouble() && key.GetDouble() == 0.0) {
465 key = JSTaggedValue(0);
466 }
467 if (key.IsSymbol()) {
468 auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
469 return symbolString->GetHashField();
470 }
471 if (key.IsString()) {
472 auto keyString = EcmaString::Cast(key.GetTaggedObject());
473 return EcmaStringAccessor(keyString).GetHashcode();
474 }
475 if (key.IsECMAObject()) {
476 uint32_t hash = static_cast<uint32_t>(ECMAObject::Cast(key.GetTaggedObject())->GetHash());
477 if (hash == 0) {
478 hash = base::RandomGenerator::GenerateIdentityHash();
479 JSHandle<ECMAObject> ecmaObj(thread, key);
480 ECMAObject::SetHash(thread, hash, ecmaObj);
481 }
482 return hash;
483 }
484 if (key.IsInt()) {
485 int32_t hash = key.GetInt();
486 return hash;
487 }
488 if (key.IsBigInt()) {
489 uint32_t keyValue = BigInt::Cast(key.GetTaggedObject())->GetDigit(0);
490 return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
491 }
492 uint64_t keyValue = key.GetRawData();
493 return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
494 }
495
BinarySearchHashes(JSHandle<TaggedArray> & array,int32_t hash,int32_t size)496 int32_t JSAPILightWeightMap::BinarySearchHashes(JSHandle<TaggedArray> &array, int32_t hash, int32_t size)
497 {
498 int32_t low = 0;
499 int32_t high = size - 1;
500 while (low <= high) {
501 uint32_t mid = static_cast<uint32_t>(low + high) >> 1U;
502 int32_t midHash = array->Get(mid).GetInt();
503 if (midHash < hash) {
504 low = static_cast<int32_t>(mid) + 1;
505 } else {
506 if (midHash == hash) {
507 return mid;
508 }
509 high = static_cast<int32_t>(mid) - 1;
510 }
511 }
512 return -(low + 1);
513 }
514 } // namespace panda::ecmascript
515