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_plain_array.h" 17 18#include "ecmascript/containers/containers_errors.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/js_function.h" 21#include <codecvt> 22 23namespace panda::ecmascript { 24using ContainerError = containers::ContainerError; 25using ErrorFlag = containers::ErrorFlag; 26void JSAPIPlainArray::Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key, 27 JSHandle<JSTaggedValue> value) 28{ 29 JSHandle<TaggedArray> keyArray(thread, obj->GetKeys()); 30 JSHandle<TaggedArray> valueArray(thread, obj->GetValues()); 31 uint32_t size = obj->GetLength(); 32 int32_t index = obj->BinarySearch(*keyArray, 0, size, key.GetTaggedValue().GetNumber()); 33 if (index >= 0) { 34 keyArray->Set(thread, index, key); 35 valueArray->Set(thread, index, value); 36 return; 37 } 38 index ^= 0xFFFFFFFF; 39 if (index < static_cast<int32_t>(size)) { 40 obj->AdjustArray(thread, *keyArray, index, size, true); 41 obj->AdjustArray(thread, *valueArray, index, size, true); 42 } 43 uint32_t capacity = valueArray->GetLength(); 44 if (size + 1 >= capacity) { 45 uint32_t newCapacity = capacity << 1U; 46 keyArray = 47 thread->GetEcmaVM()->GetFactory()->CopyArray(keyArray, capacity, newCapacity); 48 valueArray = 49 thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity); 50 obj->SetKeys(thread, keyArray); 51 obj->SetValues(thread, valueArray); 52 } 53 keyArray->Set(thread, index, key); 54 valueArray->Set(thread, index, value); 55 size++; 56 obj->SetLength(size); 57} 58 59JSHandle<TaggedArray> JSAPIPlainArray::CreateSlot(const JSThread *thread, const uint32_t capacity) 60{ 61 ASSERT_PRINT(capacity > 0, "size must be a non-negative integer"); 62 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 63 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity, JSTaggedValue::Hole()); 64 return taggedArray; 65} 66 67bool JSAPIPlainArray::AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize) 68{ 69 uint32_t size = GetLength(); 70 TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject()); 71 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 72 AdjustPrimitiveArray(keys, index + forwardSize, index); 73 AdjustArray(thread, values, index + forwardSize, index, false); 74 size = size - static_cast<uint32_t>(forwardSize); 75 SetLength(size); 76 return true; 77} 78 79void JSAPIPlainArray::AdjustPrimitiveArray(TaggedArray *srcArray, int32_t fromIndex, int32_t toIndex) 80{ 81 uint32_t size = GetLength(); 82 auto srcPtr = reinterpret_cast<JSTaggedType *>( 83 ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize()); 84 auto dstPtr = reinterpret_cast<JSTaggedType *>( 85 ToUintPtr(srcArray->GetData()) + toIndex * JSTaggedValue::TaggedTypeSize()); 86 // move Array element from srcPtr to dstPtr 87 for (uint32_t count = size - fromIndex; count > 0; --count) { 88 *dstPtr = *srcPtr; 89 ++srcPtr; 90 ++dstPtr; 91 } 92 for (uint32_t count = fromIndex - toIndex; count > 0; --count) { 93 *dstPtr = JSTaggedValue::Hole().GetRawData(); 94 ++dstPtr; 95 } 96} 97 98void JSAPIPlainArray::AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex, 99 int32_t toIndex, bool direction) 100{ 101 uint32_t size = GetLength(); 102 ASSERT(size > 0); 103 uint32_t idx = size - 1; 104 if (direction) { 105 while (fromIndex < toIndex) { 106 JSTaggedValue value = srcArray->Get(idx); 107 srcArray->Set(thread, idx + 1, value); 108 idx--; 109 fromIndex++; 110 } 111 } else { 112 if (srcArray->IsGeneralNewAndNotMarking(thread)) { 113 AdjustPrimitiveArray(srcArray, fromIndex, toIndex); 114 } else { 115 auto srcPtr = reinterpret_cast<JSTaggedType *>( 116 ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize()); 117 uint32_t dstIndex = toIndex; 118 for (uint32_t count = size - fromIndex; count > 0; --count) { 119 srcArray->Set(thread, dstIndex, JSTaggedValue(*srcPtr)); 120 ++srcPtr; 121 ++dstIndex; 122 } 123 for (uint32_t count = fromIndex - toIndex; count > 0; --count) { 124 srcArray->Set(thread, dstIndex, JSTaggedValue::Hole()); 125 ++dstIndex; 126 } 127 } 128 } 129} 130 131int32_t JSAPIPlainArray::BinarySearch(TaggedArray *array, int32_t fromIndex, int32_t toIndex, int32_t key) 132{ 133 int32_t low = fromIndex; 134 int32_t high = toIndex - 1; 135 while (low <= high) { 136 int32_t mid = static_cast<int32_t>(static_cast<uint32_t>(low + high) >> 1U); 137 int32_t midVal = static_cast<int32_t>(array->Get(mid).GetNumber()); 138 if (midVal < key) { 139 low = mid + 1; 140 } else { 141 if (midVal <= key) { 142 return mid; 143 } 144 high = mid - 1; 145 } 146 } 147 return -(low + 1); 148} 149 150void JSAPIPlainArray::Clear(JSThread *thread) 151{ 152 TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject()); 153 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 154 uint32_t size = GetLength(); 155 for (uint32_t index = 0; index < size; index++) { 156 keys->Set(thread, index, JSTaggedValue::Hole()); 157 values->Set(thread, index, JSTaggedValue::Hole()); 158 } 159 SetLength(0); 160} 161 162JSTaggedValue JSAPIPlainArray::RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize) 163{ 164 int32_t size = static_cast<int32_t>(GetLength()); 165 if (size <= 0) { 166 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty"); 167 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 168 } 169 if (index < 0 || index >= size) { 170 std::ostringstream oss; 171 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1) 172 << ". Received value is: " << index; 173 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 174 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 175 } 176 if (batchSize < 1) { 177 std::ostringstream oss; 178 oss << "The value of \"size\" is out of range. It must be > 0" << ". Received value is: " << batchSize; 179 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 180 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 181 } 182 int32_t safeSize = (size - (index + batchSize)) < 0 ? size - index : batchSize; 183 AdjustForward(thread, index, safeSize); 184 return JSTaggedValue(safeSize); 185} 186 187JSTaggedValue JSAPIPlainArray::Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, 188 const uint32_t index, JSTaggedValue value) 189{ 190 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index)); 191 JSHandle<JSTaggedValue> valueHandle(thread, value); 192 JSAPIPlainArray::Add(thread, obj, key, valueHandle); 193 return JSTaggedValue::Undefined(); 194} 195 196bool JSAPIPlainArray::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, 197 const JSHandle<JSTaggedValue> &key) 198{ 199 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject()); 200 uint32_t size = obj->GetLength(); 201 if (size == 0) { 202 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty"); 203 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false); 204 } 205 int32_t index = obj->BinarySearch(keyArray, 0, size, key.GetTaggedValue().GetInt()); 206 if (index < 0 || index >= static_cast<int32_t>(size)) { 207 ASSERT(size > 0); 208 std::ostringstream oss; 209 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1) 210 << ". Received value is: " << index; 211 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 212 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false); 213 } 214 215 obj->Get(key.GetTaggedValue()); 216 return true; 217} 218 219OperationResult JSAPIPlainArray::GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, 220 const JSHandle<JSTaggedValue> &key) 221{ 222 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject()); 223 uint32_t size = obj->GetLength(); 224 if (size == 0) { 225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty"); 226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread, 227 JSTaggedValue::Exception(), 228 PropertyMetaData(false))); 229 } 230 JSHandle<JSTaggedValue> indexKey = key; 231 if (indexKey->IsDouble()) { 232 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt 233 // For integer which is greater than INT32_MAX, it will remain TaggedDouble 234 indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble())); 235 } 236 if (!indexKey->IsInt()) { 237 CString errorMsg = "The type of \"index\" must be small integer."; 238 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 239 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, 240 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); 241 } 242 243 int keyVal = indexKey->GetInt(); 244 int32_t index = obj->BinarySearch(keyArray, 0, size, keyVal); 245 if (index < 0 || index >= static_cast<int32_t>(size)) { 246 std::ostringstream oss; 247 ASSERT(size > 0); 248 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1) 249 << ". Received value is: " << index; 250 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 251 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread, 252 JSTaggedValue::Exception(), 253 PropertyMetaData(false))); 254 } 255 256 return OperationResult(thread, obj->Get(JSTaggedValue(index)), PropertyMetaData(false)); 257} 258 259bool JSAPIPlainArray::SetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, 260 const JSHandle<JSTaggedValue> &key, 261 const JSHandle<JSTaggedValue> &value) 262{ 263 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject()); 264 uint32_t size = obj->GetLength(); 265 JSHandle<JSTaggedValue> indexKey = key; 266 if (indexKey->IsDouble()) { 267 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt 268 // For integer which is greater than INT32_MAX, it will remain TaggedDouble 269 indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble())); 270 } 271 if (!indexKey->IsInt()) { 272 return false; 273 } 274 int32_t index = obj->BinarySearch(keyArray, 0, size, indexKey->GetInt()); 275 if (index < 0 || index >= static_cast<int32_t>(size)) { 276 return false; 277 } 278 279 obj->Set(thread, obj, index, value.GetTaggedValue()); 280 return true; 281} 282 283JSHandle<JSAPIPlainArray> JSAPIPlainArray::Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj) 284{ 285 JSHandle<TaggedArray> srckeys(thread, obj->GetKeys()); 286 JSHandle<TaggedArray> srcvalues(thread, obj->GetValues()); 287 auto factory = thread->GetEcmaVM()->GetFactory(); 288 JSHandle<JSAPIPlainArray> newPlainArray = factory->NewJSAPIPlainArray(0); 289 290 uint32_t length = obj->GetLength(); 291 newPlainArray->SetLength(length); 292 JSHandle<TaggedArray> srcKeyArray(thread, obj->GetKeys()); 293 JSHandle<TaggedArray> srcValueArray(thread, obj->GetValues()); 294 295 JSHandle<TaggedArray> dstKeyArray = factory->NewAndCopyTaggedArray(srcKeyArray, length, length); 296 JSHandle<TaggedArray> dstValueArray = factory->NewAndCopyTaggedArray(srcValueArray, length, length); 297 298 newPlainArray->SetKeys(thread, dstKeyArray); 299 newPlainArray->SetValues(thread, dstValueArray); 300 return newPlainArray; 301} 302 303bool JSAPIPlainArray::Has(const int32_t key) 304{ 305 uint32_t size = GetLength(); 306 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject()); 307 int32_t index = BinarySearch(keyArray, 0, size, key); 308 if (index < 0) { 309 return false; 310 } 311 return true; 312} 313 314JSTaggedValue JSAPIPlainArray::Get(const JSTaggedValue key) 315{ 316 uint32_t size = GetLength(); 317 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject()); 318 int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber()); 319 if (index < 0) { 320 return JSTaggedValue::Undefined(); 321 } 322 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 323 return values->Get(index); 324} 325 326JSHandle<JSTaggedValue> JSAPIPlainArray::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, 327 IterationKind kind) 328{ 329 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 330 JSHandle<JSTaggedValue> iter = 331 JSHandle<JSTaggedValue>::Cast(factory->NewJSAPIPlainArrayIterator(obj, kind)); 332 return iter; 333} 334 335JSTaggedValue JSAPIPlainArray::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle, 336 const JSHandle<JSTaggedValue> &callbackFn, 337 const JSHandle<JSTaggedValue> &thisArg) 338{ 339 JSAPIPlainArray *plainarray = JSAPIPlainArray::Cast(thisHandle->GetTaggedObject()); 340 uint32_t length = plainarray->GetLength(); 341 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 342 JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys()); 343 JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues()); 344 for (uint32_t k = 0; k < length; k++) { 345 JSTaggedValue kValue = valueArray->Get(k); 346 JSTaggedValue key = keyArray->Get(k); 347 EcmaRuntimeCallInfo *info = 348 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3: three args 349 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); 350 info->SetCallArg(kValue, key, thisHandle.GetTaggedValue()); 351 JSTaggedValue funcResult = JSFunction::Call(info); 352 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); 353 } 354 return JSTaggedValue::Undefined(); 355} 356 357JSTaggedValue JSAPIPlainArray::ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray) 358{ 359 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 360 std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(","); 361 std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":"); 362 363 uint32_t length = plainarray->GetLength(); 364 std::u16string concatStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(""); 365 std::u16string concatStrNew = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(""); 366 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined()); 367 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined()); 368 for (uint32_t k = 0; k < length; k++) { 369 std::u16string valueStr; 370 valueHandle.Update(plainarray->GetValueAt(thread, k)); 371 if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) { 372 JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle); 373 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 374 valueStr = EcmaStringAccessor(valueStringHandle).ToU16String(); 375 } 376 377 std::u16string nextStr; 378 keyHandle.Update(plainarray->GetKeyAt(k)); 379 if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) { 380 JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle); 381 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 382 nextStr = EcmaStringAccessor(keyStringHandle).ToU16String(); 383 } 384 385 nextStr.append(colonStr); 386 nextStr.append(valueStr); 387 if (k > 0) { 388 concatStr.append(sepStr); 389 concatStr.append(nextStr); 390 continue; 391 } 392 concatStr.append(nextStr); 393 } 394 395 char16_t *char16tData = concatStr.data(); 396 auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 397 uint32_t u16strSize = concatStr.size(); 398 return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue(); 399} 400 401JSTaggedValue JSAPIPlainArray::GetIndexOfKey(int32_t key) 402{ 403 uint32_t size = GetLength(); 404 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject()); 405 int32_t index = BinarySearch(keyArray, 0, size, key); 406 if (index < 0) { 407 return JSTaggedValue(-1); 408 } 409 return JSTaggedValue(index); 410} 411 412JSTaggedValue JSAPIPlainArray::TryFastGetIndexOfValue(TaggedArray *values, JSTaggedValue value) 413{ 414 uint32_t size = GetLength(); 415 for (uint32_t i = 0; i < size; ++i) { 416 JSTaggedValue currVal = values->Get(i); 417 if (currVal.IsInt() && (currVal == value)) { 418 return JSTaggedValue(i); 419 } 420 } 421 return JSTaggedValue(-1); 422} 423 424JSTaggedValue JSAPIPlainArray::GetIndexOfValue(JSTaggedValue value) 425{ 426 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 427 if (value.IsInt()) { 428 return TryFastGetIndexOfValue(values, value); 429 } else { 430 uint32_t size = GetLength(); 431 for (uint32_t i = 0; i < size; ++i) { 432 if (JSTaggedValue::SameValue(values->Get(i), value)) { 433 return JSTaggedValue(i); 434 } 435 } 436 } 437 return JSTaggedValue(-1); 438} 439 440bool JSAPIPlainArray::IsEmpty() 441{ 442 uint32_t length = GetLength(); 443 return length == 0; 444} 445 446JSTaggedValue JSAPIPlainArray::GetKeyAt(int32_t index) 447{ 448 uint32_t size = GetLength(); 449 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject()); 450 if (index < 0 || index >= static_cast<int32_t>(size)) { 451 return JSTaggedValue::Undefined(); 452 } 453 return keyArray->Get(index); 454} 455 456JSTaggedValue JSAPIPlainArray::GetValueAt(JSThread *thread, int32_t index) 457{ 458 uint32_t size = GetLength(); 459 if (size == 0) { 460 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty"); 461 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 462 } 463 if (index < 0 || index >= static_cast<int32_t>(size)) { 464 ASSERT(size > 0); 465 std::ostringstream oss; 466 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1) 467 << ". Received value is: " << index; 468 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 469 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 470 } 471 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 472 return values->Get(index); 473} 474 475JSTaggedValue JSAPIPlainArray::Remove(JSThread *thread, JSTaggedValue key) 476{ 477 uint32_t size = GetLength(); 478 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject()); 479 int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber()); 480 if (index < 0 || index >= static_cast<int32_t>(size)) { 481 return JSTaggedValue::Undefined(); 482 } 483 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 484 JSTaggedValue value = values->Get(index); 485 AdjustForward(thread, index, 1); // 1 means the length of array 486 return value; 487} 488 489JSTaggedValue JSAPIPlainArray::RemoveAt(JSThread *thread, JSTaggedValue index) 490{ 491 uint32_t size = GetLength(); 492 int32_t seat = index.GetNumber(); 493 if (seat < 0 || static_cast<uint32_t>(seat) >= size) { 494 return JSTaggedValue::Undefined(); 495 } 496 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 497 JSTaggedValue value = values->Get(seat); 498 AdjustForward(thread, seat, 1); 499 return value; 500} 501 502bool JSAPIPlainArray::SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value) 503{ 504 uint32_t size = GetLength(); 505 if (size == 0) { 506 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty"); 507 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false); 508 } 509 int32_t seat = index.GetNumber(); 510 if (seat < 0 || static_cast<uint32_t>(seat) >= size) { 511 std::ostringstream oss; 512 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1) 513 << ". Received value is: " << seat; 514 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str()); 515 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false); 516 } 517 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject()); 518 values->Set(thread, seat, value); 519 return true; 520} 521} // namespace panda::ecmascript 522