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