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