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 23namespace panda::ecmascript { 24using ContainerError = containers::ContainerError; 25using ErrorFlag = containers::ErrorFlag; 26JSTaggedValue 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 46void 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 56void 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 64void 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 73void 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 89JSTaggedValue 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 100JSTaggedValue 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 135JSTaggedValue 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 142JSTaggedValue 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 155int32_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 162KeyState 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 191int32_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 205JSTaggedValue 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 224JSTaggedValue 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 243void 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 258JSTaggedValue 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 276JSTaggedValue 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 290JSTaggedValue JSAPILightWeightMap::IsEmpty() 291{ 292 if (GetLength() == 0) { 293 return JSTaggedValue::True(); 294 } else { 295 return JSTaggedValue::False(); 296 } 297} 298 299void 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 311JSTaggedValue 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 330int32_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 351JSTaggedValue 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 360JSTaggedValue 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 406JSHandle<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 419void 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 440JSHandle<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 462int32_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 496int32_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