1/* 2 * Copyright (c) 2021-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/builtins/builtins_array.h" 17 18#include <cmath> 19 20#include "ecmascript/base/typed_array_helper-inl.h" 21#include "ecmascript/interpreter/interpreter.h" 22#include "ecmascript/js_map_iterator.h" 23#include "ecmascript/js_stable_array.h" 24#include "ecmascript/object_fast_operator-inl.h" 25#include "ecmascript/builtins/builtins_string.h" 26 27namespace panda::ecmascript::builtins { 28using ArrayHelper = base::ArrayHelper; 29using TypedArrayHelper = base::TypedArrayHelper; 30const CString STRING_SEPERATOR = ","; 31 32// 22.1.1 33JSTaggedValue BuiltinsArray::ArrayConstructor(EcmaRuntimeCallInfo *argv) 34{ 35 BUILTINS_ENTRY_DEBUG_LOG(); 36 ASSERT(argv); 37 BUILTINS_API_TRACE(argv->GetThread(), Array, Constructor); 38 JSThread *thread = argv->GetThread(); 39 [[maybe_unused]] EcmaHandleScope handleScope(thread); 40 41 // 1. Let numberOfArgs be the number of arguments passed to this function call. 42 uint32_t argc = argv->GetArgsNumber(); 43 44 // 3. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. 45 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 46 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 47 if (newTarget->IsUndefined()) { 48 newTarget = constructor; 49 } 50 51 // 4. Let proto be GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%"). 52 // In NewJSObjectByConstructor(), will get prototype. 53 // 5. ReturnIfAbrupt(proto). 54 55 // 22.1.1.1 Array ( ) 56 if (argc == 0) { 57 // 6. Return ArrayCreate(0, proto). 58 return JSArray::ArrayCreate(thread, JSTaggedNumber(0), newTarget).GetTaggedValue(); 59 } 60 61 // 22.1.1.2 Array(len) 62 if (argc == 1) { 63 // 6. Let array be ArrayCreate(0, proto). 64 JSHandle<JSObject> newArrayHandle(JSArray::ArrayCreate(thread, JSTaggedNumber(0), newTarget)); 65 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 66 JSHandle<JSTaggedValue> len = GetCallArg(argv, 0); 67 // 7. If Type(len) is not Number, then 68 // a. Let defineStatus be CreateDataProperty(array, "0", len). 69 // b. Assert: defineStatus is true. 70 // c. Let intLen be 1. 71 // 8. Else, 72 // a. Let intLen be ToUint32(len). 73 // b. If intLen ≠ len, throw a RangeError exception. 74 // 9. Let setStatus be Set(array, "length", intLen, true). 75 // 10. Assert: setStatus is not an abrupt completion. 76 uint32_t newLen = 0; 77 if (!len->IsNumber()) { 78 JSHandle<JSTaggedValue> key0 = thread->GlobalConstants()->GetHandledZeroString(); 79 JSObject::CreateDataProperty(thread, newArrayHandle, key0, len); 80 newLen = 1; 81 } else { 82 newLen = JSTaggedValue::ToUint32(thread, len); 83 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 84 if (JSTaggedNumber(len.GetTaggedValue()).GetNumber() != newLen) { 85 THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid array length", JSTaggedValue::Exception()); 86 } 87 } 88 JSArray::SetCapacity(thread, newArrayHandle, 0, newLen, true); 89 90 // 11. Return array. 91 return newArrayHandle.GetTaggedValue(); 92 } 93 94 // not dictionary elements, fast create array from argv elements 95 if (argc < JSObject::MAX_GAP) { 96 // 6. Create array elements from 'argv'. 97#if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 98 ElementsKind newKind = ElementsKind::GENERIC; 99#else 100 auto arrayFunc = thread->GetEcmaVM()->GetGlobalEnv()->GetArrayFunction(); 101 ElementsKind newKind = newTarget.GetTaggedValue() == arrayFunc.GetTaggedValue() ? 102 ElementsKind::HOLE : ElementsKind::NONE; 103#endif 104 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 105 auto elements = factory->NewTaggedArray(argc, JSTaggedValue::Undefined()); 106 for (uint32_t k = 0; k < argc; k++) { 107 auto value = GetCallArg(argv, k); 108 newKind = Elements::ToElementsKind(value.GetTaggedValue(), newKind); 109 if (value->IsHole()) { 110 continue; 111 } 112 elements->Set(thread, k, value); 113 } 114 // 7. create array from elements 115 auto newArray = JSArray::CreateArrayFromList(thread, newTarget, elements); 116 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 117 if (thread->GetEcmaVM()->IsEnableElementsKind()) { 118 JSHClass::TransitToElementsKind(thread, newArray, newKind); 119 } 120 // 8. Return array. 121 return newArray.GetTaggedValue(); 122 } 123 124 // 22.1.1.3 Array(...items ) 125 JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(argc), newTarget).GetTaggedValue(); 126 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 127 if (!newArray.IsArray(thread)) { 128 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create array.", JSTaggedValue::Exception()); 129 } 130 JSHandle<JSObject> newArrayHandle(thread, newArray); 131 // 8. Let k be 0. 132 // 9. Let items be a zero-origined List containing the argument items in order. 133 // 10. Repeat, while k < numberOfArgs 134 // a. Let Pk be ToString(k). 135 // b. Let itemK be items[k]. 136 // c. Let defineStatus be CreateDataProperty(array, Pk, itemK). 137 // d. Assert: defineStatus is true. 138 // e. Increase k by 1. 139 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 140 JSMutableHandle<JSTaggedValue> itemK(thread, JSTaggedValue::Undefined()); 141 for (uint32_t k = 0; k < argc; k++) { 142 key.Update(JSTaggedValue(k)); 143 itemK.Update(GetCallArg(argv, k)); 144 if (itemK.GetTaggedValue().IsHole()) { 145 itemK.Update(JSTaggedValue::Undefined()); 146 } 147 JSObject::CreateDataProperty(thread, newArrayHandle, key, itemK); 148 } 149 // 11. Assert: the value of array’s length property is numberOfArgs. 150 // 12. Return array. 151 JSArray::Cast(*newArrayHandle)->SetArrayLength(thread, argc); 152 return newArrayHandle.GetTaggedValue(); 153} 154 155// 22.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] ) 156// NOLINTNEXTLINE(readability-function-size) 157JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) 158{ 159 ASSERT(argv); 160 BUILTINS_API_TRACE(argv->GetThread(), Array, From); 161 JSThread *thread = argv->GetThread(); 162 [[maybe_unused]] EcmaHandleScope handleScope(thread); 163 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 164 // 1. Let C be the this value. 165 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 166 // 2. If mapfn is undefined, let mapping be false. 167 bool mapping = false; 168 // 3. else 169 // a. If IsCallable(mapfn) is false, throw a TypeError exception. 170 // b. If thisArg was supplied, let T be thisArg; else let T be undefined. 171 // c. Let mapping be true 172 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, INDEX_TWO); 173 JSHandle<JSTaggedValue> mapfn = GetCallArg(argv, 1); 174 if (!mapfn->IsUndefined()) { 175 if (!mapfn->IsCallable()) { 176 THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception()); 177 } 178 mapping = true; 179 } 180 // 4. Let usingIterator be GetMethod(items, @@iterator). 181 JSHandle<JSTaggedValue> items = GetCallArg(argv, 0); 182 if (items->IsNull()) { 183 THROW_TYPE_ERROR_AND_RETURN(thread, "The items is null.", JSTaggedValue::Exception()); 184 } 185 if (!mapping && items->IsString()) { 186 JSHandle<EcmaString> strItems(items); 187 return BuiltinsString::StringToList(thread, strItems); 188 } 189 // Fast path for TypedArray 190 if (!mapping && items->IsTypedArray()) { 191 JSHandle<JSTypedArray> arrayItems(items); 192 return BuiltinsArrayBuffer::TypedArrayToList(thread, arrayItems); 193 } 194 195 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 196 JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol(); 197 JSHandle<JSTaggedValue> usingIterator = JSObject::GetMethod(thread, items, iteratorSymbol); 198 // 5. ReturnIfAbrupt(usingIterator). 199 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 200 // 6. If usingIterator is not undefined, then 201 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 202 if (!usingIterator->IsUndefined()) { 203 // Fast path for MapIterator 204 JSHandle<JSTaggedValue> iterator(thread, JSTaggedValue::Hole()); 205 if (!mapping && items->IsJSMapIterator()) { 206 iterator = JSIterator::GetIterator(thread, items, usingIterator); 207 if (iterator->IsJSMapIterator()) { 208 return JSMapIterator::MapIteratorToList(thread, iterator); 209 } 210 } 211 212 // a. If IsConstructor(C) is true, then 213 // i. Let A be Construct(C). 214 // b. Else, 215 // i. Let A be ArrayCreate(0). 216 // c. ReturnIfAbrupt(A). 217 JSTaggedValue newArray; 218 if (thisHandle->IsConstructor()) { 219 EcmaRuntimeCallInfo *info = 220 EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 0); 221 newArray = JSFunction::Construct(info); 222 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 223 } else { 224 newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); 225 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 226 } 227 if (!newArray.IsECMAObject()) { 228 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception()); 229 } 230 JSHandle<JSObject> newArrayHandle(thread, newArray); 231 // d. Let iterator be GetIterator(items, usingIterator). 232 if (iterator->IsHole()) { 233 iterator = JSIterator::GetIterator(thread, items, usingIterator); 234 // e. ReturnIfAbrupt(iterator). 235 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 236 } 237 // f. Let k be 0. 238 int k = 0; 239 // g. Repeat 240 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 241 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined()); 242 // fastpath for jsarray 243 if (newArrayHandle->IsJSArray() && items->IsJSArray() && iterator->IsJSArrayIterator()) { 244 JSHandle<JSObject> arrayLikeObj = JSTaggedValue::ToObject(thread, items); 245 JSHandle<JSTaggedValue> arrayLike(arrayLikeObj) ; 246 int64_t len = ArrayHelper::GetArrayLength(thread, arrayLike); 247 while (k < len) { 248 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, arrayLike, k); 249 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 250 if (mapping) { 251 key.Update(JSTaggedValue(k)); 252 const uint32_t argsLength = 2; // 2: «kValue, k» 253 EcmaRuntimeCallInfo *info = 254 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); 255 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 256 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue()); 257 JSTaggedValue callResult = JSFunction::Call(info); 258 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 259 mapValue.Update(callResult); 260 } else { 261 mapValue.Update(kValue.GetTaggedValue()); 262 } 263 JSArray::TryFastCreateDataProperty(thread, newArrayHandle, k, mapValue); 264 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 265 k++; 266 len = ArrayHelper::GetArrayLength(thread, arrayLike); 267 thread->CheckSafepointIfSuspended(); 268 } 269 return newArrayHandle.GetTaggedValue(); 270 } 271 while (true) { 272 key.Update(JSTaggedValue(k)); 273 // i. Let Pk be ToString(k). 274 // ii. Let next be IteratorStep(iterator). 275 JSHandle<JSTaggedValue> next = JSIterator::IteratorStep(thread, iterator); 276 // iii. ReturnIfAbrupt(next). 277 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 278 // iv. If next is false, then 279 // 1. Let setStatus be Set(A, "length", k, true). 280 // 2. ReturnIfAbrupt(setStatus). 281 // 3. Return A. 282 if (next->IsFalse()) { 283 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, key, true); 284 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 285 return newArrayHandle.GetTaggedValue(); 286 } 287 // v. Let nextValue be IteratorValue(next). 288 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next); 289 // vi. ReturnIfAbrupt(nextValue). 290 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 291 // vii. If mapping is true, then 292 // 1. Let mappedValue be Call(mapfn, T, «nextValue, k»). 293 // 2. If mappedValue is an abrupt completion, return IteratorClose(iterator, mappedValue). 294 // 3. Let mappedValue be mappedValue.[[value]]. 295 // viii. Else, let mappedValue be nextValue. 296 if (mapping) { 297 const uint32_t argsLength = 2; // 2: «nextValue, k» 298 EcmaRuntimeCallInfo *info = 299 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); 300 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 301 info->SetCallArg(nextValue.GetTaggedValue(), key.GetTaggedValue()); 302 JSTaggedValue callResult = JSFunction::Call(info); 303 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 304 JSIterator::IteratorClose(thread, iterator, mapValue).GetTaggedValue()); 305 mapValue.Update(callResult); 306 } else { 307 mapValue.Update(nextValue.GetTaggedValue()); 308 } 309 // ix. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue). 310 // x. If defineStatus is an abrupt completion, return IteratorClose(iterator, defineStatus). 311 // xi. Increase k by 1. 312 bool createRes = newArrayHandle->IsJSArray() ? 313 JSArray::TryFastCreateDataProperty(thread, newArrayHandle, k, mapValue) : 314 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, key, mapValue); 315 316 JSHandle<JSTaggedValue> defineStatus(thread, JSTaggedValue(createRes)); 317 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 318 JSIterator::IteratorClose(thread, iterator, defineStatus).GetTaggedValue()); 319 k++; 320 } 321 } 322 // 7. Assert: items is not an Iterable so assume it is an array-like object. 323 // 8. Let arrayLike be ToObject(items). 324 JSHandle<JSObject> arrayLikeObj = JSTaggedValue::ToObject(thread, items); 325 // 9. ReturnIfAbrupt(arrayLike). 326 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 327 JSHandle<JSTaggedValue> arrayLike(arrayLikeObj); 328 // 10. Let len be ToLength(Get(arrayLike, "length")). 329 int64_t len = ArrayHelper::GetArrayLength(thread, arrayLike); 330 // 11. ReturnIfAbrupt(len). 331 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 332 // 12. If IsConstructor(C) is true, then 333 // a. Let A be Construct(C, «len»). 334 // 13. Else, 335 // a. Let A be ArrayCreate(len). 336 // 14. ReturnIfAbrupt(A). 337 JSTaggedValue newArray; 338 if (thisHandle->IsConstructor()) { 339 EcmaRuntimeCallInfo *info = 340 EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 1); 341 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 342 info->SetCallArg(JSTaggedValue(len)); 343 newArray = JSFunction::Construct(info); 344 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 345 } else { 346 newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue(); 347 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 348 } 349 if (!newArray.IsECMAObject()) { 350 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception()); 351 } 352 JSHandle<JSObject> newArrayHandle(thread, newArray); 353 // 15. Let k be 0. 354 // 16. Repeat, while k < len 355 // a. Let Pk be ToString(k). 356 // b. Let kValue be Get(arrayLike, Pk). 357 // d. If mapping is true, then 358 // i. Let mappedValue be Call(mapfn, T, «kValue, k»). 359 // e. Else, let mappedValue be kValue. 360 // f. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue). 361 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 362 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined()); 363 int64_t k = 0; 364 while (k < len) { 365 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, arrayLike, k); 366 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 367 if (mapping) { 368 key.Update(JSTaggedValue(k)); 369 const uint32_t argsLength = 2; // 2: «kValue, k» 370 EcmaRuntimeCallInfo *info = 371 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); 372 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 373 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue()); 374 JSTaggedValue callResult = JSFunction::Call(info); 375 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 376 mapValue.Update(callResult); 377 } else { 378 mapValue.Update(kValue.GetTaggedValue()); 379 } 380 JSArray::TryFastCreateDataProperty(thread, newArrayHandle, k, mapValue); 381 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 382 k++; 383 thread->CheckSafepointIfSuspended(); 384 } 385 // 17. Let setStatus be Set(A, "length", len, true). 386 JSHandle<JSTaggedValue> lenHandle(thread, JSTaggedValue(len)); 387 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, lenHandle, true); 388 // 18. ReturnIfAbrupt(setStatus). 389 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 390 // 19. Return A. 391 return newArrayHandle.GetTaggedValue(); 392} 393 394// 22.1.2.2 Array.isArray ( arg ) 395JSTaggedValue BuiltinsArray::IsArray(EcmaRuntimeCallInfo *argv) 396{ 397 ASSERT(argv); 398 BUILTINS_API_TRACE(argv->GetThread(), Array, IsArray); 399 // 1. Return IsArray(arg). 400 if (GetCallArg(argv, 0)->IsArray(argv->GetThread())) { 401 return GetTaggedBoolean(true); 402 } 403 return GetTaggedBoolean(false); 404} 405 406// 22.1.2.3 Array.of ( ...items ) 407JSTaggedValue BuiltinsArray::Of(EcmaRuntimeCallInfo *argv) 408{ 409 ASSERT(argv); 410 BUILTINS_API_TRACE(argv->GetThread(), Array, Of); 411 JSThread *thread = argv->GetThread(); 412 [[maybe_unused]] EcmaHandleScope handleScope(thread); 413 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 414 JSHandle<JSTaggedValue> lengthKey = globalConst->GetHandledLengthString(); 415 416 // 1. Let len be the actual number of arguments passed to this function. 417 uint32_t argc = argv->GetArgsNumber(); 418 419 // 3. Let C be the this value. 420 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 421 // 4. If IsConstructor(C) is true, then 422 // a. Let A be Construct(C, «len»). 423 // 5. Else, 424 // a. Let A be ArrayCreate(len). 425 // 6. ReturnIfAbrupt(A). 426 JSHandle<JSTaggedValue> newArray; 427 if (thisHandle->IsConstructor()) { 428 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 429 EcmaRuntimeCallInfo *info = 430 EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 1); 431 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 432 info->SetCallArg(JSTaggedValue(argc)); 433 JSTaggedValue taggedArray = JSFunction::Construct(info); 434 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 435 newArray = JSHandle<JSTaggedValue>(thread, taggedArray); 436 } else { 437 newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(argc)); 438 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 439 } 440 if (!newArray->IsECMAObject()) { 441 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception()); 442 } 443 JSHandle<JSObject> newArrayHandle(newArray); 444 445 // 7. Let k be 0. 446 // 8. Repeat, while k < len 447 // a. Let kValue be items[k]. 448 // b. Let Pk be ToString(k). 449 // c. Let defineStatus be CreateDataPropertyOrThrow(A,Pk, kValue). 450 // d. ReturnIfAbrupt(defineStatus). 451 // e. Increase k by 1. 452 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 453 for (uint32_t k = 0; k < argc; k++) { 454 key.Update(JSTaggedValue(k)); 455 JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k); 456 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, key, kValue); 457 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 458 } 459 // 9. Let setStatus be Set(A, "length", len, true). 460 JSHandle<JSTaggedValue> lenHandle(thread, JSTaggedValue(argc)); 461 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, lenHandle, true); 462 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 463 // 11. Return A. 464 return newArrayHandle.GetTaggedValue(); 465} 466 467// 22.1.2.5 get Array [ @@species ] 468JSTaggedValue BuiltinsArray::Species(EcmaRuntimeCallInfo *argv) 469{ 470 ASSERT(argv); 471 BUILTINS_API_TRACE(argv->GetThread(), Array, Species); 472 // 1. Return the this value. 473 return GetThis(argv).GetTaggedValue(); 474} 475 476// 22.1.3.1 Array.prototype.concat ( ...arguments ) 477JSTaggedValue BuiltinsArray::Concat(EcmaRuntimeCallInfo *argv) 478{ 479 ASSERT(argv); 480 BUILTINS_API_TRACE(argv->GetThread(), Array, Concat); 481 JSThread *thread = argv->GetThread(); 482 [[maybe_unused]] EcmaHandleScope handleScope(thread); 483 int argc = static_cast<int>(argv->GetArgsNumber()); 484 485 // 1. Let O be ToObject(this value). 486 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 487 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 488 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 489 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 490 491 // 2. Let A be ArraySpeciesCreate(O, 0). 492 uint32_t arrayLen = 0; 493 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); 494 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 495 if (!(newArray.IsECMAObject() || newArray.IsUndefined())) { 496 THROW_TYPE_ERROR_AND_RETURN(thread, "array must be object or undefined.", JSTaggedValue::Exception()); 497 } 498 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 499 JSHandle<JSObject> newArrayHandle(thread, newArray); 500 501 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 502 503 // 3. Let n be 0. 504 int64_t n = 0; 505 JSMutableHandle<JSTaggedValue> ele(thread, JSTaggedValue::Undefined()); 506 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 507 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 508 // 4. Prepend O to items. 509 // 5. For each element E of items, do 510 for (int i = -1; i < argc; i++) { 511 if (i < 0) { 512 ele.Update(thisObjHandle.GetTaggedValue()); 513 } else { 514 ele.Update(GetCallArg(argv, i)); 515 } 516 // a. Let spreadable be ? IsConcatSpreadable(E). 517 bool isSpreadable = ArrayHelper::IsConcatSpreadable(thread, ele); 518 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 519 // b. If spreadable is true, then 520 if (isSpreadable) { 521 // i. Let k be 0. 522 // ii. Let len be ? LengthOfArrayLike(E). 523 // iii. If n + len > 253 - 1, throw a TypeError exception. 524 int64_t len = ArrayHelper::GetArrayLength(thread, ele); 525 int64_t k = 0; 526 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 527 if (n + len > base::MAX_SAFE_INTEGER) { 528 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 529 } 530 531 if (ele->IsStableJSArray(thread)) { 532 JSStableArray::Concat(thread, newArrayHandle, JSHandle<JSObject>::Cast(ele), k, n); 533 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 534 } 535 // iv. Repeat, while k < len, 536 while (k < len) { 537 // 1. Let P be ToString(k). 538 // 2. Let exists be HasProperty(E, P). 539 // 3. If exists is true, then 540 fromKey.Update(JSTaggedValue::ToString(thread, JSTaggedValue(k))); 541 toKey.Update(JSTaggedValue(n)); 542 bool exists = JSTaggedValue::HasProperty(thread, ele, fromKey); 543 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 544 if (exists) { 545 // a. Let subElement be Get(E, P). 546 JSHandle<JSTaggedValue> fromValHandle = 547 JSArray::FastGetPropertyByValue(thread, ele, fromKey); 548 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 549 // b. Perform ? CreateDataPropertyOrThrow(A, ! ToString((n)), subElement). 550 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValHandle); 551 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 552 } 553 // 4. Set n to n + 1. 554 // 5. Set k to k + 1. 555 n++; 556 k++; 557 thread->CheckSafepointIfSuspended(); 558 } 559 //c. Else 560 } else { 561 // ii. If n ≥ 253 - 1, throw a TypeError exception. 562 if (n >= base::MAX_SAFE_INTEGER) { 563 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 564 } 565 // iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString((n)), E). 566 // iv. Set n to n + 1. 567 toKey.Update(JSTaggedValue(n)); 568 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, ele); 569 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 570 n++; 571 } 572 } 573 // 6. Perform ? Set(A, "length", (n), true). 574 JSHandle<JSTaggedValue> lenHandle(thread, JSTaggedValue(n)); 575 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, lenHandle, true); 576 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 577 578 // 7. Return A. 579 return newArrayHandle.GetTaggedValue(); 580} 581 582// 22.1.3.3 Array.prototype.copyWithin (target, start [ , end ] ) 583JSTaggedValue BuiltinsArray::CopyWithin(EcmaRuntimeCallInfo *argv) 584{ 585 ASSERT(argv); 586 BUILTINS_API_TRACE(argv->GetThread(), Array, CopyWithin); 587 JSThread *thread = argv->GetThread(); 588 [[maybe_unused]] EcmaHandleScope handleScope(thread); 589 590 // 1. Let O be ToObject(this value). 591 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, GetThis(argv)); 592 // 2. ReturnIfAbrupt(O). 593 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 594 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 595 596 // 3. Let len be ToLength(Get(O, "length")). 597 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 598 // 4. ReturnIfAbrupt(len). 599 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 600 601 int64_t copyTo = 0; 602 int64_t copyFrom = 0; 603 int64_t copyEnd = len; 604 605 // 5. Let relativeTarget be ToInteger(target). 606 JSTaggedNumber targetTemp = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); 607 // 6. ReturnIfAbrupt(relativeTarget). 608 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 609 double target = targetTemp.GetNumber(); 610 // 7. If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to be min(relativeTarget, len). 611 if (target < 0) { 612 copyTo = target + len > 0 ? target + len : 0; 613 } else { 614 copyTo = target < len ? target : len; 615 } 616 617 // 8. Let relativeStart be ToInteger(start). 618 JSTaggedNumber start_t = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 1)); 619 // 9. ReturnIfAbrupt(relativeStart). 620 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 621 double start = start_t.GetNumber(); 622 // 10. If relativeStart < 0, let from be max((len + relativeStart),0); else let from be min(relativeStart, len). 623 if (start < 0) { 624 copyFrom = start + len > 0 ? start + len : 0; 625 } else { 626 copyFrom = start < len ? start : len; 627 } 628 629 // 11. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). 630 double end = len; 631 JSHandle<JSTaggedValue> msg3 = GetCallArg(argv, INDEX_TWO); 632 if (!msg3->IsUndefined()) { 633 JSTaggedNumber temp = JSTaggedValue::ToInteger(thread, msg3); 634 // 12. ReturnIfAbrupt(relativeEnd). 635 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 636 end = temp.GetNumber(); 637 } 638 639 // 13. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). 640 if (end < 0) { 641 copyEnd = end + len > 0 ? end + len : 0; 642 } else { 643 copyEnd = end < len ? end : len; 644 } 645 646 // 14. Let count be min(final-from, len-to). 647 int64_t count = (copyEnd - copyFrom < len - copyTo) ? (copyEnd - copyFrom) : (len - copyTo); 648 649 // 15. If from<to and to<from+count 650 // a. Let direction be -1. 651 // b. Let from be from + count -1. 652 // c. Let to be to + count -1. 653 // 16. Else, 654 // a. Let direction = 1. 655 int64_t direction = 1; 656 if (copyFrom < copyTo && copyTo < copyFrom + count) { 657 direction = -1; 658 copyFrom = copyFrom + count - 1; 659 copyTo = copyTo + count - 1; 660 } 661 662 // 17. Repeat, while count > 0 663 // a. Let fromKey be ToString(from). 664 // b. Let toKey be ToString(to). 665 // c. Let fromPresent be HasProperty(O, fromKey). 666 // d. ReturnIfAbrupt(fromPresent). 667 // e. If fromPresent is true, then 668 // i. Let fromVal be Get(O, fromKey). 669 // ii. ReturnIfAbrupt(fromVal). 670 // iii. Let setStatus be Set(O, toKey, fromVal, true). 671 // iv. ReturnIfAbrupt(setStatus). 672 // f. Else fromPresent is false, 673 // i. Let deleteStatus be DeletePropertyOrThrow(O, toKey). 674 // ii. ReturnIfAbrupt(deleteStatus). 675 // g. Let from be from + direction. 676 // h. Let to be to + direction. 677 // i. Let count be count − 1. 678 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 679 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 680 while (count > 0) { 681 fromKey.Update(JSTaggedValue(copyFrom)); 682 toKey.Update(JSTaggedValue(copyTo)); 683 bool exists = (thisObjVal->IsTypedArray() || thisObjVal->IsSharedTypedArray() || 684 JSTaggedValue::HasProperty(thread, thisObjVal, fromKey)); 685 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 686 if (exists) { 687 JSHandle<JSTaggedValue> fromValHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 688 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 689 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValHandle); 690 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 691 } else { 692 if (thisObjVal->IsJSProxy()) { 693 toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue()); 694 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 695 } 696 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); 697 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 698 } 699 copyFrom = copyFrom + direction; 700 copyTo = copyTo + direction; 701 count--; 702 } 703 704 // 18. Return O. 705 return thisObjHandle.GetTaggedValue(); 706} 707 708// 22.1.3.4 Array.prototype.entries ( ) 709JSTaggedValue BuiltinsArray::Entries(EcmaRuntimeCallInfo *argv) 710{ 711 ASSERT(argv); 712 BUILTINS_API_TRACE(argv->GetThread(), Array, Entries); 713 JSThread *thread = argv->GetThread(); 714 [[maybe_unused]] EcmaHandleScope handleScope(thread); 715 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 716 // 1. Let O be ToObject(this value). 717 // 2. ReturnIfAbrupt(O). 718 JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv)); 719 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 720 // 3. Return CreateArrayIterator(O, "key+value"). 721 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::KEY_AND_VALUE)); 722 return iter.GetTaggedValue(); 723} 724 725// 22.1.3.5 Array.prototype.every ( callbackfn [ , thisArg] ) 726JSTaggedValue BuiltinsArray::Every(EcmaRuntimeCallInfo *argv) 727{ 728 ASSERT(argv); 729 JSThread *thread = argv->GetThread(); 730 BUILTINS_API_TRACE(thread, Array, Every); 731 [[maybe_unused]] EcmaHandleScope handleScope(thread); 732 733 // 1. Let O be ToObject(this value). 734 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 735 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 736 // 2. ReturnIfAbrupt(O). 737 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 738 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 739 740 // 3. Let len be ToLength(Get(O, "length")). 741 uint64_t len = static_cast<uint64_t>(ArrayHelper::GetArrayLength(thread, thisObjVal)); 742 // 4. ReturnIfAbrupt(len). 743 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 744 745 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 746 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 747 if (!callbackFnHandle->IsCallable()) { 748 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 749 } 750 751 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 752 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 753 754 // 7. Let k be 0. 755 // 8. Repeat, while k < len 756 // a. Let Pk be ToString(k). 757 // b. Let kPresent be HasProperty(O, Pk). 758 // c. ReturnIfAbrupt(kPresent). 759 // d. If kPresent is true, then 760 // i. Let kValue be Get(O, Pk). 761 // ii. ReturnIfAbrupt(kValue). 762 // iii. Let testResult be ToBoolean(Call(callbackfn, T, «kValue, k, O»)). 763 // iv. ReturnIfAbrupt(testResult). 764 // v. If testResult is false, return false. 765 // e. Increase k by 1. 766 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 767 uint32_t k = 0; 768 JSTaggedValue callResult = GetTaggedBoolean(true); 769 if (thisObjVal->IsStableJSArray(thread)) { 770 callResult = JSStableArray::HandleEveryOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); 771 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 772 if (!callResult.ToBoolean()) { 773 return GetTaggedBoolean(false); 774 } 775 } 776 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 777 const uint32_t argsLength = 3; // 3: «kValue, k, O» 778 while (k < len) { 779 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); 780 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 781 if (exists) { 782 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 783 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 784 key.Update(JSTaggedValue(k)); 785 EcmaRuntimeCallInfo *info = 786 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 787 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 788 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 789 callResult = JSFunction::Call(info); 790 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 791 if (!callResult.ToBoolean()) { 792 return GetTaggedBoolean(false); 793 } 794 } 795 k++; 796 thread->CheckSafepointIfSuspended(); 797 } 798 799 // 9. Return true. 800 return GetTaggedBoolean(true); 801} 802 803// 22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] ) 804JSTaggedValue BuiltinsArray::Fill(EcmaRuntimeCallInfo *argv) 805{ 806 ASSERT(argv); 807 BUILTINS_API_TRACE(argv->GetThread(), Array, Fill); 808 JSThread *thread = argv->GetThread(); 809 [[maybe_unused]] EcmaHandleScope handleScope(thread); 810 811 // 1. Let O be ToObject(this value). 812 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 813 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 814 // 2. ReturnIfAbrupt(O). 815 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 816 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 817 818 if (thisObjVal->IsJSArray()) { 819 bool isDictionary = thisObjHandle->GetJSHClass()->IsDictionaryElement(); 820 if (isDictionary) { 821 uint32_t length = JSArray::Cast(*thisObjHandle)->GetLength(); 822 uint32_t size = thisObjHandle->GetNumberOfElements(); 823 if (length - size > JSObject::MAX_GAP) { 824 JSObject::TryOptimizeAsFastElements(thread, thisObjHandle); 825 } 826 } 827 } 828 829 // 2. ReturnIfAbrupt(O). 830 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 831 832 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 833 834 // 3. Let len be ToLength(Get(O, "length")). 835 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 836 // 4. ReturnIfAbrupt(len). 837 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 838 839 // 5. Let relativeStart be ToInteger(start). 840 JSHandle<JSTaggedValue> startArg = GetCallArg(argv, 1); 841 JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, startArg); 842 // 6. ReturnIfAbrupt(relativeStart). 843 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 844 double argStart = argStartTemp.GetNumber(); 845 // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len). 846 int64_t start = 0; 847 if (argStart < 0) { 848 double tempStart = argStart + len; 849 start = tempStart > 0 ? tempStart : 0; 850 } else { 851 start = argStart < len ? argStart : len; 852 } 853 854 // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). 855 double argEnd = len; 856 JSHandle<JSTaggedValue> endArg = GetCallArg(argv, INDEX_TWO); 857 if (!endArg->IsUndefined()) { 858 JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, endArg); 859 // 9. ReturnIfAbrupt(relativeEnd). 860 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 861 argEnd = argEndTemp.GetNumber(); 862 } 863 864 // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). 865 int64_t end = len; 866 if (argEnd < 0) { 867 double tempEnd = argEnd + len; 868 end = tempEnd > 0 ? tempEnd : 0; 869 } else { 870 end = argEnd < len ? argEnd : len; 871 } 872 // 11. Repeat, while k < final 873 // a. Let Pk be ToString(k). 874 // b. Let setStatus be Set(O, Pk, value, true). 875 // c. ReturnIfAbrupt(setStatus). 876 // d. Increase k by 1. 877 878 if (thisObjVal->IsStableJSArray(thread) && !startArg->IsJSObject() && !endArg->IsJSObject()) { 879 return JSStableArray::Fill(thread, thisObjHandle, value, start, end, len); 880 } 881 882 int64_t k = start; 883 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 884 while (k < end) { 885 key.Update(JSTaggedValue(k)); 886 JSArray::FastSetPropertyByValue(thread, thisObjVal, key, value); 887 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 888 k++; 889 } 890 891 // 12. Return O. 892 return thisObjHandle.GetTaggedValue(); 893} 894 895JSTaggedValue BuiltinsArray::FilterUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisArgHandle, 896 JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, uint32_t toIndex, JSHandle<JSObject> newArrayHandle, 897 JSHandle<JSTaggedValue> &callbackFnHandle) 898{ 899 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 900 const uint32_t argsLength = 3; // 3: «kValue, k, O» 901 JSTaggedValue callResult = GetTaggedBoolean(true); 902 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 903 JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined()); 904 while (k < len) { 905 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); 906 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 907 if (exists) { 908 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 909 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 910 key.Update(JSTaggedValue(k)); 911 EcmaRuntimeCallInfo *info = 912 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 913 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 914 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 915 callResult = JSFunction::Call(info); 916 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 917 if (callResult.ToBoolean()) { 918 toIndexHandle.Update(JSTaggedValue(toIndex)); 919 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toIndexHandle, kValue); 920 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 921 toIndex++; 922 } 923 } 924 k++; 925 thread->CheckSafepointIfSuspended(); 926 } 927 return newArrayHandle.GetTaggedValue(); 928} 929 930// 22.1.3.7 Array.prototype.filter ( callbackfn [ , thisArg ] ) 931JSTaggedValue BuiltinsArray::Filter(EcmaRuntimeCallInfo *argv) 932{ 933 ASSERT(argv); 934 JSThread *thread = argv->GetThread(); 935 BUILTINS_API_TRACE(thread, Array, Filter); 936 [[maybe_unused]] EcmaHandleScope handleScope(thread); 937 938 // 1. Let O be ToObject(this value). 939 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 940 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 941 // 2. ReturnIfAbrupt(O). 942 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 943 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 944 945 // 3. Let len be ToLength(Get(O, "length")). 946 uint64_t len = static_cast<uint64_t>(ArrayHelper::GetArrayLength(thread, thisObjVal)); 947 // 4. ReturnIfAbrupt(len). 948 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 949 950 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 951 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 952 if (!callbackFnHandle->IsCallable()) { 953 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 954 } 955 956 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 957 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 958 959 // 7. Let A be ArraySpeciesCreate(O, 0). 960 int32_t arrayLen = 0; 961 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); 962 // 8. ReturnIfAbrupt(A). 963 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 964 JSHandle<JSObject> newArrayHandle(thread, newArray); 965 966 // 9. Let k be 0. 967 // 10. Let to be 0. 968 // 11. Repeat, while k < len 969 // a. Let Pk be ToString(k). 970 // b. Let kPresent be HasProperty(O, Pk). 971 // c. ReturnIfAbrupt(kPresent). 972 // d. If kPresent is true, then 973 // i. Let kValue be Get(O, Pk). 974 // ii. ReturnIfAbrupt(kValue). 975 // iii. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)). 976 // iv. ReturnIfAbrupt(selected). 977 // v. If selected is true, then 978 // 1. Let status be CreateDataPropertyOrThrow (A, ToString(to), kValue). 979 // 2. ReturnIfAbrupt(status). 980 // 3. Increase to by 1. 981 // e. Increase k by 1. 982 uint32_t toIndex = 0; 983 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 984 JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined()); 985 uint32_t k = 0; 986 if (thisObjVal->IsStableJSArray(thread)) { 987 JSStableArray::Filter(newArrayHandle, thisObjHandle, argv, k, toIndex); 988 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 989 } 990 return FilterUnStableJSArray(thread, thisArgHandle, thisObjVal, k, len, toIndex, newArrayHandle, callbackFnHandle); 991} 992 993// 22.1.3.8 Array.prototype.find ( predicate [ , thisArg ] ) 994JSTaggedValue BuiltinsArray::Find(EcmaRuntimeCallInfo *argv) 995{ 996 ASSERT(argv); 997 BUILTINS_API_TRACE(argv->GetThread(), Array, Find); 998 JSThread *thread = argv->GetThread(); 999 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1000 1001 // 1. Let O be ToObject(this value). 1002 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1003 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1004 // 2. ReturnIfAbrupt(O). 1005 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1006 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1007 1008 // 3. Let len be ToLength(Get(O, "length")). 1009 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 1010 // 4. ReturnIfAbrupt(len). 1011 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1012 1013 // 5. If IsCallable(predicate) is false, throw a TypeError exception. 1014 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1015 if (!callbackFnHandle->IsCallable()) { 1016 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); 1017 } 1018 1019 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 1020 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 1021 1022 // 7. Let k be 0. 1023 // 8. Repeat, while k < len 1024 // a. Let Pk be ToString(k). 1025 // b. Let kValue be Get(O, Pk). 1026 // c. ReturnIfAbrupt(kValue). 1027 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). 1028 // e. ReturnIfAbrupt(testResult). 1029 // f. If testResult is true, return kValue. 1030 // g. Increase k by 1. 1031 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1032 int64_t k = 0; 1033 while (k < len) { 1034 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1035 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1036 key.Update(JSTaggedValue(k)); 1037 const uint32_t argsLength = 3; // 3: «kValue, k, O» 1038 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 1039 EcmaRuntimeCallInfo *info = 1040 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1041 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1042 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 1043 JSTaggedValue callResult = JSFunction::Call(info); 1044 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1045 if (callResult.ToBoolean()) { 1046 return kValue.GetTaggedValue(); 1047 } 1048 k++; 1049 } 1050 1051 // 9. Return undefined. 1052 return JSTaggedValue::Undefined(); 1053} 1054 1055// 22.1.3.9 Array.prototype.findIndex ( predicate [ , thisArg ] ) 1056JSTaggedValue BuiltinsArray::FindIndex(EcmaRuntimeCallInfo *argv) 1057{ 1058 ASSERT(argv); 1059 BUILTINS_API_TRACE(argv->GetThread(), Array, FindIndex); 1060 JSThread *thread = argv->GetThread(); 1061 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1062 1063 // 1. Let O be ToObject(this value). 1064 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1065 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1066 // 2. ReturnIfAbrupt(O). 1067 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1068 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1069 1070 // 3. Let len be ToLength(Get(O, "length")). 1071 uint64_t len = static_cast<uint64_t>(ArrayHelper::GetLength(thread, thisObjVal)); 1072 // 4. ReturnIfAbrupt(len). 1073 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1074 1075 // 5. If IsCallable(predicate) is false, throw a TypeError exception. 1076 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1077 if (!callbackFnHandle->IsCallable()) { 1078 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); 1079 } 1080 1081 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 1082 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 1083 1084 // 7. Let k be 0. 1085 // 8. Repeat, while k < len 1086 // a. Let Pk be ToString(k). 1087 // b. Let kValue be Get(O, Pk). 1088 // c. ReturnIfAbrupt(kValue). 1089 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). 1090 // e. ReturnIfAbrupt(testResult). 1091 // f. If testResult is true, return k. 1092 // g. Increase k by 1. 1093 uint32_t k = 0; 1094 JSTaggedValue callResult = GetTaggedBoolean(true); 1095 if (thisObjVal->IsStableJSArray(thread)) { 1096 callResult = JSStableArray::HandleFindIndexOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); 1097 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1098 if (callResult.ToBoolean()) { 1099 return GetTaggedDouble(k); 1100 } 1101 } 1102 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1103 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 1104 const uint32_t argsLength = 3; // 3: «kValue, k, O» 1105 while (k < len) { 1106 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1107 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1108 key.Update(JSTaggedValue(k)); 1109 EcmaRuntimeCallInfo *info = 1110 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1111 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1112 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 1113 callResult = JSFunction::Call(info); 1114 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1115 if (callResult.ToBoolean()) { 1116 return GetTaggedDouble(k); 1117 } 1118 k++; 1119 thread->CheckSafepointIfSuspended(); 1120 } 1121 1122 // 9. Return -1. 1123 return GetTaggedDouble(-1); 1124} 1125 1126// 22.1.3.10 Array.prototype.forEach ( callbackfn [ , thisArg ] ) 1127JSTaggedValue BuiltinsArray::ForEach(EcmaRuntimeCallInfo *argv) 1128{ 1129 ASSERT(argv); 1130 JSThread *thread = argv->GetThread(); 1131 BUILTINS_API_TRACE(thread, Array, ForEach); 1132 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1133 1134 // 1. Let O be ToObject(this value). 1135 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1136 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1137 // 2. ReturnIfAbrupt(O). 1138 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1139 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1140 1141 // 3. Let len be ToLength(Get(O, "length")). 1142 uint64_t len = static_cast<uint64_t>(ArrayHelper::GetArrayLength(thread, thisObjVal)); 1143 // 4. ReturnIfAbrupt(len). 1144 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1145 1146 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 1147 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1148 if (!callbackFnHandle->IsCallable()) { 1149 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 1150 } 1151 1152 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 1153 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 1154 1155 // 7. Let k be 0. 1156 // 8. Repeat, while k < len 1157 // a. Let Pk be ToString(k). 1158 // b. Let kPresent be HasProperty(O, Pk). 1159 // c. ReturnIfAbrupt(kPresent). 1160 // d. If kPresent is true, then 1161 // i. Let kValue be Get(O, Pk). 1162 // ii. ReturnIfAbrupt(kValue). 1163 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). 1164 // iv. ReturnIfAbrupt(funcResult). 1165 // e. Increase k by 1. 1166 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1167 uint32_t k = 0; 1168 if (thisObjVal->IsStableJSArray(thread)) { 1169 JSStableArray::HandleforEachOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, len, k); 1170 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1171 } 1172 const uint32_t argsLength = 3; // 3: «kValue, k, O» 1173 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 1174 while (k < len) { 1175 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); 1176 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1177 if (exists) { 1178 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1179 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1180 key.Update(JSTaggedValue(k)); 1181 EcmaRuntimeCallInfo *info = 1182 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1183 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1184 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 1185 JSTaggedValue funcResult = JSFunction::Call(info); 1186 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); 1187 } 1188 k++; 1189 thread->CheckSafepointIfSuspended(); 1190 } 1191 1192 // 9. Return undefined. 1193 return JSTaggedValue::Undefined(); 1194} 1195 1196JSTaggedValue BuiltinsArray::IndexOfStable( 1197 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle) 1198{ 1199 int64_t length = JSHandle<JSArray>::Cast(thisHandle)->GetArrayLength(); 1200 if (length == 0) { 1201 return JSTaggedValue(-1); 1202 } 1203 int64_t fromIndex = 0; 1204 uint32_t argc = argv->GetArgsNumber(); 1205 // 2: [target, fromIndex]. Note that fromIndex is missing in most usage cases. 1206 if (UNLIKELY(argc >= 2)) { 1207 JSHandle<JSTaggedValue> fromIndexHandle = argv->GetCallArg(1); 1208 fromIndex = ArrayHelper::GetStartIndex(thread, fromIndexHandle, length); 1209 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1210 // Slow path when fromIndex is obtained from an ECMAObject 1211 // due to potential side effects in its 'toString' and 'valueOf' methods which modify the array object. 1212 if (UNLIKELY(fromIndexHandle->IsECMAObject())) { 1213 return IndexOfSlowPath(argv, thread, thisHandle, length, fromIndex); 1214 } 1215 } 1216 if (fromIndex >= length) { 1217 return JSTaggedValue(-1); 1218 } 1219 if (UNLIKELY(!thisHandle->IsECMAObject())) { 1220 return IndexOfSlowPath(argv, thread, thisHandle, length, fromIndex); 1221 } 1222 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 1223 return JSStableArray::IndexOf( 1224 thread, thisHandle, target, static_cast<uint32_t>(fromIndex), static_cast<uint32_t>(length)); 1225} 1226 1227JSTaggedValue BuiltinsArray::IndexOfSlowPath( 1228 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle) 1229{ 1230 // 1. Let O be ToObject(this value). 1231 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1232 // 2. ReturnIfAbrupt(O). 1233 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1234 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1235 // 3. Let len be ToLength(Get(O, "length")). 1236 int64_t length = ArrayHelper::GetLength(thread, thisObjVal); 1237 // 4. ReturnIfAbrupt(len). 1238 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1239 // 5. If len is 0, return −1. 1240 if (length == 0) { 1241 return JSTaggedValue(-1); 1242 } 1243 // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0. 1244 int64_t fromIndex = ArrayHelper::GetStartIndexFromArgs(thread, argv, 1, length); 1245 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1246 return IndexOfSlowPath(argv, thread, thisObjVal, length, fromIndex); 1247} 1248 1249JSTaggedValue BuiltinsArray::IndexOfSlowPath( 1250 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal, 1251 int64_t length, int64_t fromIndex) 1252{ 1253 if (fromIndex >= length) { 1254 return JSTaggedValue(-1); 1255 } 1256 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined()); 1257 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 1258 // 11. Repeat, while k < len 1259 for (int64_t curIndex = fromIndex; curIndex < length; ++curIndex) { 1260 keyHandle.Update(JSTaggedValue(curIndex)); 1261 bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target); 1262 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1263 if (UNLIKELY(found)) { 1264 return JSTaggedValue(curIndex); 1265 } 1266 thread->CheckSafepointIfSuspended(); 1267 } 1268 // 12. Return -1. 1269 return JSTaggedValue(-1); 1270} 1271 1272// 22.1.3.11 Array.prototype.indexOf ( searchElement [ , fromIndex ] ) 1273JSTaggedValue BuiltinsArray::IndexOf(EcmaRuntimeCallInfo *argv) 1274{ 1275 ASSERT(argv); 1276 JSThread *thread = argv->GetThread(); 1277 BUILTINS_API_TRACE(thread, Array, IndexOf); 1278 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1279 1280 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1281 if (thisHandle->IsStableJSArray(thread)) { 1282 return IndexOfStable(argv, thread, thisHandle); 1283 } 1284 return IndexOfSlowPath(argv, thread, thisHandle); 1285} 1286 1287// 22.1.3.12 Array.prototype.join (separator) 1288JSTaggedValue BuiltinsArray::Join(EcmaRuntimeCallInfo *argv) 1289{ 1290 ASSERT(argv); 1291 BUILTINS_API_TRACE(argv->GetThread(), Array, Join); 1292 JSThread *thread = argv->GetThread(); 1293 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1294 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1295 auto factory = thread->GetEcmaVM()->GetFactory(); 1296 auto context = thread->GetCurrentEcmaContext(); 1297 bool noCircular = context->JoinStackPushFastPath(thisHandle); 1298 if (!noCircular) { 1299 return factory->GetEmptyString().GetTaggedValue(); 1300 } 1301 if (thisHandle->IsStableJSArray(thread)) { 1302 return JSStableArray::Join(JSHandle<JSArray>::Cast(thisHandle), argv); 1303 } 1304 1305 // 1. Let O be ToObject(this value). 1306 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1307 // 2. ReturnIfAbrupt(O). 1308 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 1309 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1310 1311 // 3. Let len be ToLength(Get(O, "length")). 1312 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 1313 if (len > UINT32_MAX) { 1314 THROW_TYPE_ERROR_AND_RETURN(thread, "Invalid array length", JSTaggedValue::Exception()); 1315 } 1316 // 4. ReturnIfAbrupt(len). 1317 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 1318 1319 // 5. If separator is undefined, let separator be the single-element String ",". 1320 // 6. Let sep be ToString(separator). 1321 JSHandle<JSTaggedValue> sepHandle; 1322 if ((GetCallArg(argv, 0)->IsUndefined())) { 1323 sepHandle = thread->GlobalConstants()->GetHandledCommaString(); 1324 } else { 1325 sepHandle = GetCallArg(argv, 0); 1326 } 1327 1328 JSHandle<EcmaString> sepStringHandle = JSTaggedValue::ToString(thread, sepHandle); 1329 uint32_t allocateLength = 0; 1330 uint32_t sepLength = EcmaStringAccessor(sepStringHandle).GetLength(); 1331 1332 if (len > 0) { 1333 allocateLength = sepLength * (len - 1) + len; 1334 } 1335 if (allocateLength > EcmaString::MAX_STRING_LENGTH) { 1336 context->JoinStackPopFastPath(thisHandle); 1337 THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); 1338 } 1339 // 7. ReturnIfAbrupt(sep). 1340 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 1341 std::u16string sepStr = EcmaStringAccessor(sepStringHandle).ToU16String(); 1342 1343 // 8. If len is zero, return the empty String. 1344 if (len == 0) { 1345 context->JoinStackPopFastPath(thisHandle); 1346 return GetTaggedString(thread, ""); 1347 } 1348 1349 // 9. Let element0 be Get(O, "0"). 1350 // 10. If element0 is undefined or null, let R be the empty String; otherwise, let R be ToString(element0). 1351 // 11. ReturnIfAbrupt(R). 1352 // 12. Let k be 1. 1353 // 13. Repeat, while k < len 1354 // a. Let S be the String value produced by concatenating R and sep. 1355 // b. Let element be Get(O, ToString(k)). 1356 // c. If element is undefined or null, let next be the empty String; otherwise, let next be ToString(element). 1357 // d. ReturnIfAbrupt(next). 1358 // e. Let R be a String value produced by concatenating S and next. 1359 // f. Increase k by 1. 1360 std::u16string concatStr; 1361 for (int64_t k = 0; k < len; k++) { 1362 std::u16string nextStr; 1363 JSHandle<JSTaggedValue> element = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1364 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 1365 if (!element->IsUndefined() && !element->IsNull()) { 1366 JSHandle<EcmaString> nextStringHandle = JSTaggedValue::ToString(thread, element); 1367 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 1368 nextStr = EcmaStringAccessor(nextStringHandle).ToU16String(); 1369 } 1370 if (k > 0) { 1371 concatStr.append(sepStr); 1372 } 1373 concatStr.append(nextStr); 1374 if (concatStr.size() > EcmaString::MAX_STRING_LENGTH) { 1375 context->JoinStackPopFastPath(thisHandle); 1376 THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); 1377 } 1378 thread->CheckSafepointIfSuspended(); 1379 } 1380 1381 // 14. Return R. 1382 const char16_t *constChar16tData = concatStr.data(); 1383 auto *char16tData = const_cast<char16_t *>(constChar16tData); 1384 auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 1385 uint32_t u16strSize = concatStr.size(); 1386 context->JoinStackPopFastPath(thisHandle); 1387 return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue(); 1388} 1389 1390// 22.1.3.13 Array.prototype.keys ( ) 1391JSTaggedValue BuiltinsArray::Keys(EcmaRuntimeCallInfo *argv) 1392{ 1393 ASSERT(argv); 1394 BUILTINS_API_TRACE(argv->GetThread(), Array, Keys); 1395 JSThread *thread = argv->GetThread(); 1396 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1397 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1398 // 1. Let O be ToObject(this value). 1399 // 2. ReturnIfAbrupt(O). 1400 JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv)); 1401 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1402 // 3. Return CreateArrayIterator(O, "key"). 1403 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::KEY)); 1404 return iter.GetTaggedValue(); 1405} 1406 1407JSTaggedValue BuiltinsArray::LastIndexOfStable( 1408 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle) 1409{ 1410 int64_t length = JSHandle<JSArray>::Cast(thisHandle)->GetArrayLength(); 1411 if (length == 0) { 1412 return JSTaggedValue(-1); 1413 } 1414 int64_t fromIndex = length - 1; 1415 uint32_t argc = argv->GetArgsNumber(); 1416 // 2: [target, fromIndex]. Note that fromIndex is missing in most usage cases. 1417 if (UNLIKELY(argc >= 2)) { 1418 JSHandle<JSTaggedValue> fromIndexHandle = argv->GetCallArg(1); 1419 fromIndex = ArrayHelper::GetLastStartIndex(thread, fromIndexHandle, length); 1420 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1421 // Slow path when fromIndex is obtained from an ECMAObject 1422 // due to potential side effects in its 'toString' and 'valueOf' methods which modify the array object. 1423 if (UNLIKELY(fromIndexHandle->IsECMAObject())) { 1424 return LastIndexOfSlowPath(argv, thread, thisHandle, fromIndex); 1425 } 1426 } 1427 if (fromIndex < 0) { 1428 return JSTaggedValue(-1); 1429 } 1430 JSHandle<JSTaggedValue> target = GetCallArg(argv, 0); 1431 return JSStableArray::LastIndexOf( 1432 thread, thisHandle, target, static_cast<uint32_t>(fromIndex), static_cast<uint32_t>(length)); 1433} 1434 1435JSTaggedValue BuiltinsArray::LastIndexOfSlowPath( 1436 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle) 1437{ 1438 // 1. Let O be ToObject(this value). 1439 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1440 // 2. ReturnIfAbrupt(O). 1441 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1442 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1443 // 3. Let len be ToLength(Get(O, "length")). 1444 int64_t length = ArrayHelper::GetLength(thread, thisObjVal); 1445 // 4. ReturnIfAbrupt(len). 1446 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1447 // 5. If len is 0, return −1. 1448 if (length == 0) { 1449 return JSTaggedValue(-1); 1450 } 1451 // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0. 1452 int64_t fromIndex = ArrayHelper::GetLastStartIndexFromArgs(thread, argv, 1, length); 1453 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1454 return LastIndexOfSlowPath(argv, thread, thisObjVal, fromIndex); 1455} 1456 1457JSTaggedValue BuiltinsArray::LastIndexOfSlowPath( 1458 EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal, int64_t fromIndex) 1459{ 1460 if (fromIndex < 0) { 1461 return JSTaggedValue(-1); 1462 } 1463 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined()); 1464 JSHandle<JSTaggedValue> target = base::BuiltinsBase::GetCallArg(argv, 0); 1465 // 11. Repeat, while k < len 1466 for (int64_t curIndex = fromIndex; curIndex >= 0; --curIndex) { 1467 keyHandle.Update(JSTaggedValue(curIndex)); 1468 bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target); 1469 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1470 if (UNLIKELY(found)) { 1471 return JSTaggedValue(curIndex); 1472 } 1473 } 1474 // 12. Return -1. 1475 return JSTaggedValue(-1); 1476} 1477 1478// 22.1.3.14 Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) 1479JSTaggedValue BuiltinsArray::LastIndexOf(EcmaRuntimeCallInfo *argv) 1480{ 1481 ASSERT(argv); 1482 BUILTINS_API_TRACE(argv->GetThread(), Array, IndexOf); 1483 JSThread *thread = argv->GetThread(); 1484 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1485 1486 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1487 if (thisHandle->IsStableJSArray(thread)) { 1488 return LastIndexOfStable(argv, thread, thisHandle); 1489 } 1490 return LastIndexOfSlowPath(argv, thread, thisHandle); 1491} 1492 1493// 22.1.3.15 Array.prototype.map ( callbackfn [ , thisArg ] ) 1494JSTaggedValue BuiltinsArray::Map(EcmaRuntimeCallInfo *argv) 1495{ 1496 ASSERT(argv); 1497 BUILTINS_API_TRACE(argv->GetThread(), Array, Map); 1498 JSThread *thread = argv->GetThread(); 1499 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1500 1501 // 1. Let O be ToObject(this value). 1502 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1503 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1504 // 2. ReturnIfAbrupt(O). 1505 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1506 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1507 1508 // 3. Let len be ToLength(Get(O, "length")). 1509 int64_t rawLen = ArrayHelper::GetArrayLength(thread, thisObjVal); 1510 // 4. ReturnIfAbrupt(len). 1511 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1512 1513 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 1514 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1515 if (!callbackFnHandle->IsCallable()) { 1516 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 1517 } 1518 1519 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 1520 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 1521 1522 // 7. Let A be ArraySpeciesCreate(O, len). 1523 JSTaggedValue newArray = 1524 JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(rawLen))); 1525 // 8. ReturnIfAbrupt(A). 1526 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1527 if (!newArray.IsECMAObject()) { 1528 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception()); 1529 } 1530 JSHandle<JSObject> newArrayHandle(thread, newArray); 1531 1532 // 9. Let k be 0. 1533 // 10. Repeat, while k < len 1534 // a. Let Pk be ToString(k). 1535 // b. Let kPresent be HasProperty(O, Pk). 1536 // c. ReturnIfAbrupt(kPresent). 1537 // d. If kPresent is true, then 1538 // i. Let kValue be Get(O, Pk). 1539 // ii. ReturnIfAbrupt(kValue). 1540 // iii. Let mappedValue be Call(callbackfn, T, «kValue, k, O»). 1541 // iv. ReturnIfAbrupt(mappedValue). 1542 // v. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue). 1543 // vi. ReturnIfAbrupt(status). 1544 // e. Increase k by 1. 1545 uint32_t k = 0; 1546 uint32_t len = static_cast<uint32_t>(rawLen); 1547 if (thisObjVal->IsStableJSArray(thread)) { 1548 JSStableArray::Map(newArrayHandle, thisObjHandle, argv, k, len); 1549 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1550 } 1551 return MapUnStableJSArray(thread, thisArgHandle, thisObjVal, k, len, newArrayHandle, callbackFnHandle); 1552} 1553 1554JSTaggedValue BuiltinsArray::MapUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisArgHandle, 1555 JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSHandle<JSObject> newArrayHandle, 1556 JSHandle<JSTaggedValue> &callbackFnHandle) 1557{ 1558 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1559 JSMutableHandle<JSTaggedValue> mapResultHandle(thread, JSTaggedValue::Undefined()); 1560 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 1561 const uint32_t argsLength = 3; // 3: «kValue, k, O» 1562 while (k < len) { 1563 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); 1564 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1565 if (exists) { 1566 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1567 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1568 key.Update(JSTaggedValue(k)); 1569 EcmaRuntimeCallInfo *info = 1570 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1571 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1572 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 1573 JSTaggedValue mapResult = JSFunction::Call(info); 1574 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1575 mapResultHandle.Update(mapResult); 1576 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle); 1577 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1578 } 1579 k++; 1580 thread->CheckSafepointIfSuspended(); 1581 } 1582 1583 // 11. Return A. 1584 return newArrayHandle.GetTaggedValue(); 1585} 1586 1587// 22.1.3.16 Array.prototype.pop ( ) 1588JSTaggedValue BuiltinsArray::Pop(EcmaRuntimeCallInfo *argv) 1589{ 1590 ASSERT(argv); 1591 BUILTINS_API_TRACE(argv->GetThread(), Array, Pop); 1592 JSThread *thread = argv->GetThread(); 1593 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1594 1595 // 1. Let O be ToObject(this value). 1596 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1597 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1598 if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { 1599 return JSStableArray::Pop(JSHandle<JSArray>::Cast(thisHandle), argv); 1600 } 1601 1602 // 2. ReturnIfAbrupt(O). 1603 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1604 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1605 1606 // 3. Let len be ToLength(Get(O, "length")). 1607 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 1608 // 4. ReturnIfAbrupt(len). 1609 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1610 // 5. If len is zero, 1611 // a. Let setStatus be Set(O, "length", 0, true). 1612 // b. ReturnIfAbrupt(setStatus). 1613 // c. Return undefined. 1614 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 1615 if (len == 0) { 1616 JSHandle<JSTaggedValue> lengthValue(thread, JSTaggedValue(0)); 1617 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, lengthValue, true); 1618 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1619 return JSTaggedValue::Undefined(); 1620 } 1621 1622 // 6. Else len > 0, 1623 // a. Let newLen be len–1. 1624 // b. Let indx be ToString(newLen). 1625 // c. Let element be Get(O, indx). 1626 // d. ReturnIfAbrupt(element). 1627 // e. Let deleteStatus be DeletePropertyOrThrow(O, indx). 1628 // f. ReturnIfAbrupt(deleteStatus). 1629 // g. Let setStatus be Set(O, "length", newLen, true). 1630 // h. ReturnIfAbrupt(setStatus). 1631 // i. Return element. 1632 int64_t newLen = len - 1; 1633 JSHandle<JSTaggedValue> indexHandle(thread, JSTaggedValue(newLen)); 1634 JSHandle<JSTaggedValue> element = JSTaggedValue::GetProperty(thread, thisObjVal, indexHandle).GetValue(); 1635 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1636 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, indexHandle); 1637 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1638 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, indexHandle, true); 1639 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1640 1641 return element.GetTaggedValue(); 1642} 1643 1644// 22.1.3.17 Array.prototype.push ( ...items ) 1645JSTaggedValue BuiltinsArray::Push(EcmaRuntimeCallInfo *argv) 1646{ 1647 ASSERT(argv); 1648 BUILTINS_API_TRACE(argv->GetThread(), Array, Push); 1649 JSThread *thread = argv->GetThread(); 1650 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1651 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1652 // 1. Let O be ToObject(this value). 1653 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1654 if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { 1655 return JSStableArray::Push(JSHandle<JSArray>::Cast(thisHandle), argv); 1656 } 1657 // 6. Let argCount be the number of elements in items. 1658 uint32_t argc = argv->GetArgsNumber(); 1659 1660 // 2. ReturnIfAbrupt(O). 1661 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1662 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1663 1664 // 3. Let len be ToLength(Get(O, "length")). 1665 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 1666 // 4. ReturnIfAbrupt(len). 1667 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1668 // 7. If len + argCount > 253-1, throw a TypeError exception. 1669 if ((len + static_cast<int64_t>(argc)) > base::MAX_SAFE_INTEGER) { 1670 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 1671 } 1672 1673 // 8. Repeat, while items is not empty 1674 // a. Remove the first element from items and let E be the value of the element. 1675 // b. Let setStatus be Set(O, ToString(len), E, true). 1676 // c. ReturnIfAbrupt(setStatus). 1677 // d. Let len be len+1. 1678 uint32_t k = 0; 1679 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1680 while (k < argc) { 1681 key.Update(JSTaggedValue(len)); 1682 JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k); 1683 JSArray::FastSetPropertyByValue(thread, thisObjVal, key, kValue); 1684 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1685 k++; 1686 len++; 1687 } 1688 1689 // 9. Let setStatus be Set(O, "length", len, true). 1690 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 1691 key.Update(JSTaggedValue(len)); 1692 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, key, true); 1693 // 10. ReturnIfAbrupt(setStatus). 1694 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1695 1696 // 11. Return len. 1697 return GetTaggedDouble(len); 1698} 1699 1700JSTaggedValue BuiltinsArray::ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle, 1701 JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator, 1702 JSHandle<JSTaggedValue> &callbackFnHandle) 1703{ 1704 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 1705 JSTaggedValue callResult = JSTaggedValue::Undefined(); 1706 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1707 while (k < len) { 1708 bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); 1709 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1710 if (exists) { 1711 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 1712 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1713 key.Update(JSTaggedValue(k)); 1714 JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined(); 1715 const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O» 1716 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 1717 EcmaRuntimeCallInfo *info = 1718 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1719 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1720 info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(), 1721 thisObjVal.GetTaggedValue()); 1722 callResult = JSFunction::Call(info); 1723 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1724 accumulator.Update(callResult); 1725 } 1726 k++; 1727 thread->CheckSafepointIfSuspended(); 1728 } 1729 return accumulator.GetTaggedValue(); 1730} 1731 1732// 22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] ) 1733JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv) 1734{ 1735 ASSERT(argv); 1736 BUILTINS_API_TRACE(argv->GetThread(), Array, Reduce); 1737 JSThread *thread = argv->GetThread(); 1738 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1739 1740 // 1. Let O be ToObject(this value). 1741 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1742 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1743 // 2. ReturnIfAbrupt(O). 1744 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1745 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1746 1747 // 3. Let len be ToLength(Get(O, "length")). 1748 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 1749 // 4. ReturnIfAbrupt(len). 1750 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1751 return ReduceInner(argv, len); 1752} 1753 1754JSTaggedValue BuiltinsArray::ReduceInner(EcmaRuntimeCallInfo *argv, int64_t len) 1755{ 1756 ASSERT(argv); 1757 JSThread *thread = argv->GetThread(); 1758 uint32_t argc = argv->GetArgsNumber(); 1759 // 1. Let O be ToObject(this value). 1760 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1761 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1762 // 2. ReturnIfAbrupt(O). 1763 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1764 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1765 1766 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 1767 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1768 if (!callbackFnHandle->IsCallable()) { 1769 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 1770 } 1771 1772 // 6. If len is 0 and initialValue is not present, throw a TypeError exception. 1773 if (len == 0 && argc < 2) { // 2:2 means the number of parameters 1774 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 1775 } 1776 1777 // 7. Let k be 0. 1778 // 8. If initialValue is present, then 1779 // a. Set accumulator to initialValue. 1780 // 9. Else initialValue is not present, 1781 // a. Let kPresent be false. 1782 // b. Repeat, while kPresent is false and k < len 1783 // i. Let Pk be ToString(k). 1784 // ii. Let kPresent be HasProperty(O, Pk). 1785 // iii. ReturnIfAbrupt(kPresent). 1786 // iv. If kPresent is true, then 1787 // 1. Let accumulator be Get(O, Pk). 1788 // 2. ReturnIfAbrupt(accumulator). 1789 // v. Increase k by 1. 1790 // c. If kPresent is false, throw a TypeError exception. 1791 int64_t k = 0; 1792 JSMutableHandle<JSTaggedValue> accumulator(thread, JSTaggedValue::Undefined()); 1793 if (argc >= 2) { // 2:2 means the number of parameters 1794 accumulator.Update(GetCallArg(argv, 1).GetTaggedValue()); 1795 } else { 1796 bool kPresent = false; 1797 while (!kPresent && k < len) { 1798 kPresent = (thisHandle->IsTypedArray() || thisHandle->IsSharedTypedArray() || 1799 JSTaggedValue::HasProperty(thread, thisObjVal, k)); 1800 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1801 if (kPresent) { 1802 accumulator.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue()); 1803 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1804 } 1805 k++; 1806 } 1807 if (!kPresent) { 1808 THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception()); 1809 } 1810 } 1811 1812 if (thisObjVal->IsStableJSArray(thread)) { 1813 JSStableArray::Reduce(thread, thisObjHandle, callbackFnHandle, accumulator, k, len); 1814 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1815 } 1816 return ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len, accumulator, callbackFnHandle); 1817} 1818 1819// 22.1.3.19 Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) 1820JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) 1821{ 1822 ASSERT(argv); 1823 BUILTINS_API_TRACE(argv->GetThread(), Array, ReduceRight); 1824 JSThread *thread = argv->GetThread(); 1825 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1826 1827 // 1. Let O be ToObject(this value). 1828 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1829 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1830 // 2. ReturnIfAbrupt(O). 1831 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1832 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1833 1834 // 3. Let len be ToLength(Get(O, "length")). 1835 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 1836 // 4. ReturnIfAbrupt(len). 1837 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1838 return ReduceRightInner(argv, len); 1839} 1840 1841JSTaggedValue BuiltinsArray::ReduceRightInner(EcmaRuntimeCallInfo *argv, int64_t len) 1842{ 1843 ASSERT(argv); 1844 JSThread *thread = argv->GetThread(); 1845 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 1846 1847 uint32_t argc = argv->GetArgsNumber(); 1848 1849 // 1. Let O be ToObject(this value). 1850 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1851 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1852 // 2. ReturnIfAbrupt(O). 1853 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1854 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1855 1856 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 1857 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1858 if (!callbackFnHandle->IsCallable()) { 1859 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 1860 } 1861 1862 // 6. If len is 0 and initialValue is not present, throw a TypeError exception. 1863 if (len == 0 && argc < 2) { // 2:2 means the number of parameters 1864 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 1865 } 1866 1867 // 7. Let k be len-1. 1868 int64_t k = len - 1; 1869 // 8. If initialValue is present, then 1870 // a. Set accumulator to initialValue. 1871 // 9. Else initialValue is not present, 1872 // a. Let kPresent be false. 1873 // b. Repeat, while kPresent is false and k ≥ 0 1874 // i. Let Pk be ToString(k). 1875 // ii. Let kPresent be HasProperty(O, Pk). 1876 // iii. ReturnIfAbrupt(kPresent). 1877 // iv. If kPresent is true, then 1878 // 1. Let accumulator be Get(O, Pk). 1879 // 2. ReturnIfAbrupt(accumulator). 1880 // v. Decrease k by 1. 1881 // c. If kPresent is false, throw a TypeError exception. 1882 JSMutableHandle<JSTaggedValue> accumulator(thread, JSTaggedValue::Undefined()); 1883 if (argc >= 2) { // 2:2 means the number of parameters 1884 accumulator.Update(GetCallArg(argv, 1).GetTaggedValue()); 1885 } else { 1886 bool kPresent = false; 1887 while (!kPresent && k >= 0) { 1888 kPresent = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); 1889 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1890 if (kPresent) { 1891 accumulator.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue()); 1892 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1893 } 1894 k--; 1895 } 1896 if (!kPresent) { 1897 THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception()); 1898 } 1899 } 1900 1901 // 10. Repeat, while k ≥ 0 1902 // a. Let Pk be ToString(k). 1903 // b. Let kPresent be HasProperty(O, Pk). 1904 // c. ReturnIfAbrupt(kPresent). 1905 // d. If kPresent is true, then 1906 // i. Let kValue be Get(O, Pk). 1907 // ii. ReturnIfAbrupt(kValue). 1908 // iii. Let accumulator be Call(callbackfn, undefined, «accumulator, kValue, k, O»). 1909 // iv. ReturnIfAbrupt(accumulator). 1910 // e. Decrease k by 1. 1911 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 1912 JSTaggedValue callResult = JSTaggedValue::Undefined(); 1913 1914 JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined(); 1915 if (thisObjVal->IsStableJSArray(thread)) { 1916 JSTaggedValue ret = JSStableArray::HandleReduceRightOfStable(thread, thisObjHandle, 1917 callbackFnHandle, accumulator, thisArgHandle, k); 1918 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1919 if (ret.ToBoolean()) { 1920 return accumulator.GetTaggedValue(); 1921 } 1922 } 1923 1924 while (k >= 0) { 1925 key.Update(JSTaggedValue(k)); 1926 bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, key)); 1927 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1928 if (exists) { 1929 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); 1930 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1931 const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O» 1932 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 1933 EcmaRuntimeCallInfo *info = 1934 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 1935 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1936 info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(), 1937 thisObjVal.GetTaggedValue()); 1938 callResult = JSFunction::Call(info); 1939 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1940 accumulator.Update(callResult); 1941 } 1942 k--; 1943 } 1944 1945 // 11. Return accumulator. 1946 return accumulator.GetTaggedValue(); 1947} 1948 1949// 22.1.3.20 Array.prototype.reverse ( ) 1950JSTaggedValue BuiltinsArray::Reverse(EcmaRuntimeCallInfo *argv) 1951{ 1952 ASSERT(argv); 1953 BUILTINS_API_TRACE(argv->GetThread(), Array, Reverse); 1954 JSThread *thread = argv->GetThread(); 1955 [[maybe_unused]] EcmaHandleScope handleScope(thread); 1956 1957 // 1. Let O be ToObject(this value). 1958 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1959 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 1960 // 2. ReturnIfAbrupt(O). 1961 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1962 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 1963 1964 // 3. Let len be ToLength(Get(O, "length")). 1965 int64_t len = 0; 1966 if (thisHandle->IsJSArray()) { 1967 len = JSArray::Cast(thisHandle->GetTaggedObject())->GetArrayLength(); 1968 } else { 1969 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 1970 JSHandle<JSTaggedValue> lenResult = JSTaggedValue::GetProperty(thread, thisHandle, lengthKey).GetValue(); 1971 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); 1972 JSTaggedNumber lenNumber = JSTaggedValue::ToLength(thread, lenResult); 1973 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); 1974 len = lenNumber.GetNumber(); 1975 } 1976 // 4. ReturnIfAbrupt(len). 1977 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1978 1979 // 5. Let middle be floor(len/2). 1980 int64_t middle = std::floor(len / 2); 1981 1982 // 6. Let lower be 0. 1983 int64_t lower = 0; 1984 1985 // 7. Repeat, while lower != middle 1986 // a. Let upper be len-lower-1. 1987 // b. Let upperP be ToString(upper). 1988 // c. Let lowerP be ToString(lower). 1989 // d. Let lowerExists be HasProperty(O, lowerP). 1990 // e. ReturnIfAbrupt(lowerExists). 1991 // f. If lowerExists is true, then 1992 // i. Let lowerValue be Get(O, lowerP). 1993 // ii. ReturnIfAbrupt(lowerValue). 1994 // g. Let upperExists be HasProperty(O, upperP). 1995 // h. ReturnIfAbrupt(upperExists). 1996 // i. If upperExists is true, then 1997 // i. Let upperValue be Get(O, upperP). 1998 // ii. ReturnIfAbrupt(upperValue). 1999 // j. If lowerExists is true and upperExists is true, then 2000 // i. Let setStatus be Set(O, lowerP, upperValue, true). 2001 // ii. ReturnIfAbrupt(setStatus). 2002 // iii. Let setStatus be Set(O, upperP, lowerValue, true). 2003 // iv. ReturnIfAbrupt(setStatus). 2004 // k. Else if lowerExists is false and upperExists is true, then 2005 // i. Let setStatus be Set(O, lowerP, upperValue, true). 2006 // ii. ReturnIfAbrupt(setStatus). 2007 // iii. Let deleteStatus be DeletePropertyOrThrow (O, upperP). 2008 // iv. ReturnIfAbrupt(deleteStatus). 2009 // l. Else if lowerExists is true and upperExists is false, then 2010 // i. Let deleteStatus be DeletePropertyOrThrow (O, lowerP). 2011 // ii. ReturnIfAbrupt(deleteStatus). 2012 // iii. Let setStatus be Set(O, upperP, lowerValue, true). 2013 // iv. ReturnIfAbrupt(setStatus). 2014 // m. Else both lowerExists and upperExists are false, 2015 // i. No action is required. 2016 // n. Increase lower by 1. 2017 JSMutableHandle<JSTaggedValue> lowerP(thread, JSTaggedValue::Undefined()); 2018 JSMutableHandle<JSTaggedValue> upperP(thread, JSTaggedValue::Undefined()); 2019 JSHandle<JSTaggedValue> lowerValueHandle(thread, JSTaggedValue::Undefined()); 2020 JSHandle<JSTaggedValue> upperValueHandle(thread, JSTaggedValue::Undefined()); 2021 2022 if (thisObjVal->IsStableJSArray(thread)) { 2023 JSStableArray::Reverse(thread, thisObjHandle, lower, len); 2024 } 2025 while (lower != middle) { 2026 int64_t upper = len - lower - 1; 2027 lowerP.Update(JSTaggedValue(lower)); 2028 upperP.Update(JSTaggedValue(upper)); 2029 bool lowerExists = (JSTaggedValue::HasProperty(thread, thisObjVal, lowerP)); 2030 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2031 if (lowerExists) { 2032 lowerValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, lowerP); 2033 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2034 } 2035 bool upperExists = (JSTaggedValue::HasProperty(thread, thisObjVal, upperP)); 2036 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2037 if (upperExists) { 2038 upperValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, upperP); 2039 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2040 } 2041 if (lowerExists && upperExists) { 2042 JSArray::FastSetPropertyByValue(thread, thisObjVal, lowerP, upperValueHandle); 2043 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2044 JSArray::FastSetPropertyByValue(thread, thisObjVal, upperP, lowerValueHandle); 2045 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2046 } else if (upperExists) { 2047 JSArray::FastSetPropertyByValue(thread, thisObjVal, lowerP, upperValueHandle); 2048 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2049 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, upperP); 2050 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2051 } else if (lowerExists) { 2052 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, lowerP); 2053 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2054 JSArray::FastSetPropertyByValue(thread, thisObjVal, upperP, lowerValueHandle); 2055 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2056 } else { 2057 } 2058 lower++; 2059 } 2060 2061 // 8. Return O . 2062 return thisObjHandle.GetTaggedValue(); 2063} 2064 2065// 22.1.3.21 Array.prototype.shift ( ) 2066JSTaggedValue BuiltinsArray::Shift(EcmaRuntimeCallInfo *argv) 2067{ 2068 ASSERT(argv); 2069 BUILTINS_API_TRACE(argv->GetThread(), Array, Shift); 2070 JSThread *thread = argv->GetThread(); 2071 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2072 2073 // 1. Let O be ToObject(this value). 2074 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2075 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2076 // 2. ReturnIfAbrupt(O). 2077 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2078 if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { 2079 return JSStableArray::Shift(JSHandle<JSArray>::Cast(thisHandle), argv); 2080 } 2081 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2082 2083 // 3. Let len be ToLength(Get(O, "length")). 2084 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 2085 // 4. ReturnIfAbrupt(len). 2086 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2087 // 5. If len is zero, then 2088 // a. Let setStatus be Set(O, "length", 0, true). 2089 // b. ReturnIfAbrupt(setStatus). 2090 // c. Return undefined. 2091 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 2092 if (len == 0) { 2093 JSHandle<JSTaggedValue> zeroLenHandle(thread, JSTaggedValue(len)); 2094 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, zeroLenHandle, true); 2095 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2096 return JSTaggedValue::Undefined(); 2097 } 2098 2099 // 6. Let first be Get(O, "0"). 2100 JSHandle<JSTaggedValue> firstKey(thread, JSTaggedValue(0)); 2101 JSHandle<JSTaggedValue> firstValue = JSTaggedValue::GetProperty(thread, thisObjVal, firstKey).GetValue(); 2102 // 7. ReturnIfAbrupt(first). 2103 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2104 2105 // 8. Let k be 1. 2106 // 9. Repeat, while k < len 2107 // a. Let from be ToString(k). 2108 // b. Let to be ToString(k–1). 2109 // c. Let fromPresent be HasProperty(O, from). 2110 // d. ReturnIfAbrupt(fromPresent). 2111 // e. If fromPresent is true, then 2112 // i. Let fromVal be Get(O, from). 2113 // ii. ReturnIfAbrupt(fromVal). 2114 // iii. Let setStatus be Set(O, to, fromVal, true). 2115 // iv. ReturnIfAbrupt(setStatus). 2116 // f. Else fromPresent is false, 2117 // i. Let deleteStatus be DeletePropertyOrThrow(O, to). 2118 // ii. ReturnIfAbrupt(deleteStatus). 2119 // g. Increase k by 1. 2120 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 2121 int64_t k = 1; 2122 while (k < len) { 2123 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); 2124 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2125 if (exists) { 2126 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 2127 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2128 JSArray::FastSetPropertyByValue(thread, thisObjVal, k - 1, fromValue); 2129 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2130 } else { 2131 toKey.Update(JSTaggedValue(k - 1)); 2132 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); 2133 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2134 } 2135 k++; 2136 thread->CheckSafepointIfSuspended(); 2137 } 2138 // 10. Let deleteStatus be DeletePropertyOrThrow(O, ToString(len–1)). 2139 JSHandle<JSTaggedValue> deleteKey(thread, JSTaggedValue(len - 1)); 2140 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey); 2141 // 11. ReturnIfAbrupt(deleteStatus). 2142 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2143 2144 // 12. Let setStatus be Set(O, "length", len–1, true). 2145 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(len - 1)); 2146 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true); 2147 // 13. ReturnIfAbrupt(setStatus). 2148 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2149 2150 // 14. Return first. 2151 return firstValue.GetTaggedValue(); 2152} 2153 2154// 22.1.3.22 Array.prototype.slice (start, end) 2155JSTaggedValue BuiltinsArray::Slice(EcmaRuntimeCallInfo *argv) 2156{ 2157 BUILTINS_API_TRACE(argv->GetThread(), Array, Slice); 2158 ASSERT(argv); 2159 JSThread *thread = argv->GetThread(); 2160 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2161 2162 // 1. Let O be ToObject(this value). 2163 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2164 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2165 // 2. ReturnIfAbrupt(O). 2166 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2167 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2168 2169 // 3. Let len be ToLength(Get(O, "length")). 2170 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 2171 // 4. ReturnIfAbrupt(len). 2172 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2173 2174 JSHandle<JSTaggedValue> msg0 = GetCallArg(argv, 0); 2175 double argStart; 2176 if (msg0->IsInt()) { 2177 argStart = msg0->GetInt(); 2178 } else { 2179 // 5. Let relativeStart be ToInteger(start). 2180 JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0); 2181 // 6. ReturnIfAbrupt(relativeStart). 2182 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2183 argStart = argStartTemp.GetNumber(); 2184 } 2185 2186 // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len). 2187 int64_t k = 0; 2188 if (argStart < 0) { 2189 double tempStart = len + argStart; 2190 k = tempStart > 0 ? tempStart : 0; 2191 } else { 2192 k = argStart < len ? argStart : len; 2193 } 2194 2195 // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). 2196 // 9. ReturnIfAbrupt(relativeEnd). 2197 // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). 2198 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1); 2199 double argEnd = len; 2200 if (!msg1->IsUndefined()) { 2201 if (msg1->IsInt()) { 2202 argEnd = msg1->GetInt(); 2203 } else { 2204 JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, msg1); 2205 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2206 argEnd = argEndTemp.GetNumber(); 2207 } 2208 } 2209 int64_t final = 0; 2210 if (argEnd < 0) { 2211 double tempFinal = len + argEnd; 2212 final = tempFinal > 0 ? tempFinal : 0; 2213 } else { 2214 final = argEnd < len ? argEnd : len; 2215 } 2216 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2217 2218 // 11. Let count be max(final – k, 0). 2219 int64_t count = final > k ? (final - k) : 0; 2220 2221 if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor() 2222 && JSObject::GetPrototype(thisObjHandle).IsJSArray()) { 2223 return JSStableArray::Slice(thread, thisObjHandle, k, count); 2224 } 2225 2226 // 12. Let A be ArraySpeciesCreate(O, count). 2227 JSTaggedValue newArray = 2228 JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(count))); 2229 // 13. ReturnIfAbrupt(A). 2230 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2231 if (count == 0) { 2232 return newArray; 2233 } 2234 JSHandle<JSObject> newArrayHandle(thread, newArray); 2235 2236 // 14. Let n be 0. 2237 // 15. Repeat, while k < final 2238 // a. Let Pk be ToString(k). 2239 // b. Let kPresent be HasProperty(O, Pk). 2240 // c. ReturnIfAbrupt(kPresent). 2241 // d. If kPresent is true, then 2242 // i. Let kValue be Get(O, Pk). 2243 // ii. ReturnIfAbrupt(kValue). 2244 // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue ). 2245 // iv. ReturnIfAbrupt(status). 2246 // e. Increase k by 1. 2247 // f. Increase n by 1. 2248 int64_t n = 0; 2249 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 2250 JSMutableHandle<JSTaggedValue> nKey(thread, JSTaggedValue::Undefined()); 2251 while (k < final) { 2252 key.Update(JSTaggedValue(k)); 2253 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, key); 2254 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2255 if (exists) { 2256 nKey.Update(JSTaggedValue(n)); 2257 JSHandle<JSTaggedValue> kValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); 2258 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2259 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, nKey, kValueHandle); 2260 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2261 } 2262 k++; 2263 n++; 2264 } 2265 2266 // 16. Let setStatus be Set(A, "length", n, true). 2267 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 2268 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(n)); 2269 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, newLenHandle, true); 2270 // 17. ReturnIfAbrupt(setStatus). 2271 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2272 2273 // 18. Return A. 2274 return newArrayHandle.GetTaggedValue(); 2275} 2276 2277// 22.1.3.23 Array.prototype.some ( callbackfn [ , thisArg ] ) 2278JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) 2279{ 2280 ASSERT(argv); 2281 BUILTINS_API_TRACE(argv->GetThread(), Array, Some); 2282 JSThread *thread = argv->GetThread(); 2283 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2284 2285 // 1. Let O be ToObject(this value). 2286 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2287 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2288 // 2. ReturnIfAbrupt(O). 2289 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2290 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2291 2292 // 3. Let len be ToLength(Get(O, "length")). 2293 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 2294 // 4. ReturnIfAbrupt(len). 2295 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2296 2297 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. 2298 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 2299 if (!callbackFnHandle->IsCallable()) { 2300 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); 2301 } 2302 2303 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 2304 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 2305 2306 // 7. Let k be 0. 2307 // 8. Repeat, while k < len 2308 // a. Let Pk be ToString(k). 2309 // b. Let kPresent be HasProperty(O, Pk). 2310 // c. ReturnIfAbrupt(kPresent). 2311 // d. If kPresent is true, then 2312 // i. Let kValue be Get(O, Pk). 2313 // ii. ReturnIfAbrupt(kValue). 2314 // iii. Let testResult be ToBoolean(Call(callbackfn, T, «kValue, k, and O»)). 2315 // iv. ReturnIfAbrupt(testResult). 2316 // v. If testResult is true, return true. 2317 // e. Increase k by 1. 2318 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 2319 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined()); 2320 uint32_t k = 0; 2321 JSTaggedValue callResult = GetTaggedBoolean(false); 2322 if (thisObjVal->IsStableJSArray(thread)) { 2323 callResult = JSStableArray::HandleSomeOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); 2324 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2325 if (callResult.ToBoolean()) { 2326 return GetTaggedBoolean(true); 2327 } 2328 } 2329 while (k < len) { 2330 bool exists = (thisHandle->IsTypedArray() || thisHandle->IsSharedTypedArray() || 2331 JSTaggedValue::HasProperty(thread, thisObjVal, k)); 2332 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2333 if (exists) { 2334 key.Update(JSTaggedValue(k)); 2335 kValue.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, key)); 2336 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2337 const uint32_t argsLength = 3; // 3: «kValue, k, O» 2338 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 2339 EcmaRuntimeCallInfo *info = 2340 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 2341 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2342 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 2343 callResult = JSFunction::Call(info); 2344 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2345 if (callResult.ToBoolean()) { 2346 return GetTaggedBoolean(true); 2347 } 2348 } 2349 k++; 2350 thread->CheckSafepointIfSuspended(); 2351 } 2352 2353 // 9. Return false. 2354 return GetTaggedBoolean(false); 2355} 2356 2357// 22.1.3.24 Array.prototype.sort (comparefn) 2358JSTaggedValue BuiltinsArray::Sort(EcmaRuntimeCallInfo *argv) 2359{ 2360 ASSERT(argv); 2361 JSThread *thread = argv->GetThread(); 2362 BUILTINS_API_TRACE(thread, Array, Sort); 2363 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2364 2365 // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception. 2366 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 2367 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { 2368 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); 2369 } 2370 2371 // 2. Let obj be ToObject(this value). 2372 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2373 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2374 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2375 2376 // Array sort 2377 if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) { 2378 JSStableArray::Sort(thread, thisObjHandle, callbackFnHandle); 2379 } else { 2380 JSArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle); 2381 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2382 } 2383 return thisObjHandle.GetTaggedValue(); 2384} 2385 2386// 22.1.3.25 Array.prototype.splice (start, deleteCount , ...items ) 2387// NOLINTNEXTLINE(readability-function-size) 2388JSTaggedValue BuiltinsArray::Splice(EcmaRuntimeCallInfo *argv) 2389{ 2390 ASSERT(argv); 2391 BUILTINS_API_TRACE(argv->GetThread(), Array, Splice); 2392 JSThread *thread = argv->GetThread(); 2393 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2394 uint32_t argc = argv->GetArgsNumber(); 2395 // 1. Let O be ToObject(this value). 2396 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2397 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2398 // 2. ReturnIfAbrupt(O). 2399 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2400 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2401 // 3. Let len be ToLength(Get(O, "length")). 2402 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 2403 // 4. ReturnIfAbrupt(len). 2404 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2405 // 5. Let relativeStart be ToInteger(start). 2406 int64_t start = 0; 2407 int64_t insertCount = 0; 2408 int64_t actualDeleteCount = 0; 2409 int64_t end = len; 2410 double argStart = 0; 2411 if (argc > 0) { 2412 JSHandle<JSTaggedValue> msg0 = GetCallArg(argv, 0); 2413 JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0); 2414 // 6. ReturnIfAbrupt(relativeStart). 2415 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2416 argStart = argStartTemp.GetNumber(); 2417 // 7. If relativeStart < 0, let actualStart be max((len + relativeStart),0); else let actualStart be 2418 // min(relativeStart, len). 2419 if (argStart < 0) { 2420 double tempStart = argStart + len; 2421 start = tempStart > 0 ? tempStart : 0; 2422 } else { 2423 start = argStart < end ? argStart : end; 2424 } 2425 actualDeleteCount = len - start; 2426 } 2427 // 8. If the number of actual arguments is 0, then 2428 // a. Let insertCount be 0. 2429 // b. Let actualDeleteCount be 0. 2430 // 9. Else if the number of actual arguments is 1, then 2431 // a. Let insertCount be 0. 2432 // b. Let actualDeleteCount be len – actualStart. 2433 // 10. Else, 2434 // a. Let insertCount be the number of actual arguments minus 2. 2435 // b. Let dc be ToInteger(deleteCount). 2436 // c. ReturnIfAbrupt(dc). 2437 // d. Let actualDeleteCount be min(max(dc,0), len – actualStart). 2438 if (argc > 1) { 2439 insertCount = argc - 2; // 2:2 means there are two arguments before the insert items. 2440 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1); 2441 JSTaggedNumber argDeleteCount = JSTaggedValue::ToInteger(thread, msg1); 2442 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2443 double deleteCount = argDeleteCount.GetNumber(); 2444 deleteCount = deleteCount > 0 ? deleteCount : 0; 2445 actualDeleteCount = deleteCount < (len - start) ? deleteCount : len - start; 2446 } 2447 // 11. If len+insertCount−actualDeleteCount > 253-1, throw a TypeError exception. 2448 if (len + insertCount - actualDeleteCount > base::MAX_SAFE_INTEGER) { 2449 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 2450 } 2451 // 12. Let A be ArraySpeciesCreate(O, actualDeleteCount). 2452 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, 2453 JSTaggedNumber(static_cast<double>(actualDeleteCount))); 2454 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2455 JSHandle<JSObject> newArrayHandle(thread, newArray); 2456 if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { 2457 return JSStableArray::Splice(JSHandle<JSArray>::Cast(thisHandle), argv, start, insertCount, 2458 actualDeleteCount, newArrayHandle, len); 2459 } 2460 // 14. Let k be 0. 2461 // 15. Repeat, while k < actualDeleteCount 2462 // a. Let from be ToString(actualStart+k). 2463 // b. Let fromPresent be HasProperty(O, from). 2464 // d. If fromPresent is true, then 2465 // i. Let fromValue be Get(O, from). 2466 // iii. Let status be CreateDataPropertyOrThrow(A, ToString(k), fromValue). 2467 // e. Increase k by 1. 2468 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 2469 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 2470 int64_t k = 0; 2471 while (k < actualDeleteCount) { 2472 int64_t from = start + k; 2473 fromKey.Update(JSTaggedValue(from)); 2474 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey); 2475 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2476 if (exists) { 2477 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 2478 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2479 toKey.Update(JSTaggedValue(k)); 2480 if (newArrayHandle->IsJSProxy()) { 2481 toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue()); 2482 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2483 } 2484 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue); 2485 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2486 } 2487 k++; 2488 } 2489 // 16. Let setStatus be Set(A, "length", actualDeleteCount, true). 2490 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 2491 JSHandle<JSTaggedValue> deleteCountHandle(thread, JSTaggedValue(actualDeleteCount)); 2492 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, deleteCountHandle, 2493 true); 2494 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2495 // 19. Let itemCount be the number of elements in items. 2496 // 20. If itemCount < actualDeleteCount, then 2497 // a. Let k be actualStart. 2498 // b. Repeat, while k < (len – actualDeleteCount) 2499 // i. Let from be ToString(k+actualDeleteCount). 2500 // ii. Let to be ToString(k+itemCount). 2501 // iii. Let fromPresent be HasProperty(O, from). 2502 // v. If fromPresent is true, then 2503 // 1. Let fromValue be Get(O, from). 2504 // 3. Let setStatus be Set(O, to, fromValue, true). 2505 // vi. Else fromPresent is false, 2506 // 1. Let deleteStatus be DeletePropertyOrThrow(O, to). 2507 // vii. Increase k by 1. 2508 // c. Let k be len. 2509 // d. Repeat, while k > (len – actualDeleteCount + itemCount) 2510 // i. Let deleteStatus be DeletePropertyOrThrow(O, ToString(k–1)). 2511 // iii. Decrease k by 1. 2512 if (insertCount < actualDeleteCount) { 2513 k = start; 2514 while (k < len - actualDeleteCount) { 2515 fromKey.Update(JSTaggedValue(k + actualDeleteCount)); 2516 toKey.Update(JSTaggedValue(k + insertCount)); 2517 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey); 2518 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2519 if (exists) { 2520 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 2521 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2522 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue); 2523 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2524 } else { 2525 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); 2526 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2527 } 2528 k++; 2529 } 2530 k = len; 2531 JSMutableHandle<JSTaggedValue> deleteKey(thread, JSTaggedValue::Undefined()); 2532 while (k > len - actualDeleteCount + insertCount) { 2533 deleteKey.Update(JSTaggedValue(k - 1)); 2534 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey); 2535 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2536 k--; 2537 } 2538 } else if (insertCount > actualDeleteCount) { 2539 // 21. Else if itemCount > actualDeleteCount, then 2540 // a. Let k be (len – actualDeleteCount). 2541 // b. Repeat, while k > actualStart 2542 // i. Let from be ToString(k + actualDeleteCount – 1). 2543 // ii. Let to be ToString(k + itemCount – 1) 2544 // iii. Let fromPresent be HasProperty(O, from). 2545 // iv. ReturnIfAbrupt(fromPresent). 2546 // v. If fromPresent is true, then 2547 // 1. Let fromValue be Get(O, from). 2548 // 2. ReturnIfAbrupt(fromValue). 2549 // 3. Let setStatus be Set(O, to, fromValue, true). 2550 // 4. ReturnIfAbrupt(setStatus). 2551 // vi. Else fromPresent is false, 2552 // 1. Let deleteStatus be DeletePropertyOrThrow(O, to). 2553 // 2. ReturnIfAbrupt(deleteStatus). 2554 // vii. Decrease k by 1. 2555 k = len - actualDeleteCount; 2556 while (k > start) { 2557 fromKey.Update(JSTaggedValue(k + actualDeleteCount - 1)); 2558 toKey.Update(JSTaggedValue(k + insertCount - 1)); 2559 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey); 2560 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2561 if (exists) { 2562 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 2563 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2564 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue); 2565 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2566 } else { 2567 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); 2568 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2569 } 2570 k--; 2571 } 2572 } 2573 // 22. Let k be actualStart. 2574 k = start; 2575 // 23. Repeat, while items is not empty 2576 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 2577 for (uint32_t i = 2; i < argc; i++) { 2578 JSHandle<JSTaggedValue> itemValue = GetCallArg(argv, i); 2579 key.Update(JSTaggedValue(k)); 2580 JSArray::FastSetPropertyByValue(thread, thisObjVal, key, itemValue); 2581 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2582 k++; 2583 } 2584 // 24. Let setStatus be Set(O, "length", len – actualDeleteCount + itemCount, true). 2585 int64_t newLen = len - actualDeleteCount + insertCount; 2586 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen)); 2587 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true); 2588 // 25. ReturnIfAbrupt(setStatus). 2589 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2590 // 26. Return A. 2591 return newArrayHandle.GetTaggedValue(); 2592} 2593 2594// 22.1.3.26 Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) 2595JSTaggedValue BuiltinsArray::ToLocaleString(EcmaRuntimeCallInfo *argv) 2596{ 2597 ASSERT(argv); 2598 BUILTINS_API_TRACE(argv->GetThread(), Array, ToLocaleString); 2599 JSThread *thread = argv->GetThread(); 2600 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2601 auto ecmaVm = thread->GetEcmaVM(); 2602 ObjectFactory *factory = ecmaVm->GetFactory(); 2603 2604 // 1. Let O be ToObject(this value). 2605 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2606 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2607 // add this to join stack to avoid circular call 2608 auto context = thread->GetCurrentEcmaContext(); 2609 bool noCircular = context->JoinStackPushFastPath(thisHandle); 2610 if (!noCircular) { 2611 return factory->GetEmptyString().GetTaggedValue(); 2612 } 2613 // 2. ReturnIfAbrupt(O). 2614 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2615 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2616 2617 // 3. Let len be ToLength(Get(O, "length")). 2618 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 2619 // 4. ReturnIfAbrupt(len). 2620 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2621 2622 // 6. If len is zero, return the empty String. 2623 if (len == 0) { 2624 // pop this from join stack 2625 context->JoinStackPopFastPath(thisHandle); 2626 return GetTaggedString(thread, ""); 2627 } 2628 2629 // Inject locales and options argument into a taggedArray 2630 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 2631 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 2632 2633 CString concatStr; 2634 // 7. Let firstElement be Get(array, "0"). 2635 // 8. ReturnIfAbrupt(firstElement). 2636 // 9. If firstElement is undefined or null, then 2637 // a. Let R be the empty String. 2638 // 10. Else 2639 // a. Let R be ToString(Invoke(firstElement, "toLocaleString")). 2640 // b. ReturnIfAbrupt(R). 2641 // 11. Let k be 1. 2642 // 12. Repeat, while k < len 2643 // a. Let S be a String value produced by concatenating R and separator. 2644 // b. Let nextElement be Get(array, ToString(k)). 2645 // c. ReturnIfAbrupt(nextElement). 2646 // d. If nextElement is undefined or null, then 2647 // i. Let R be the empty String. 2648 // e. Else 2649 // i. Let R be ToString(Invoke(nextElement, "toLocaleString")). 2650 // ii. ReturnIfAbrupt(R). 2651 // f. Let R be a String value produced by concatenating S and R. 2652 // g. Increase k by 1. 2653 auto globalConst = thread->GlobalConstants(); 2654 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 2655 for (int64_t k = 0; k < len; k++) { 2656 thread->CheckSafepointIfSuspended(); 2657 JSTaggedValue next = globalConst->GetEmptyString(); 2658 JSHandle<JSTaggedValue> nextElement = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 2659 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2660 if (!nextElement->IsUndefined() && !nextElement->IsNull()) { 2661 JSHandle<JSTaggedValue> nextValueHandle = nextElement; 2662 JSHandle<JSTaggedValue> key = globalConst->GetHandledToLocaleStringString(); 2663 EcmaRuntimeCallInfo *info = 2664 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextValueHandle, undefined, 2); // 2: two args 2665 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2666 info->SetCallArg(locales.GetTaggedValue(), options.GetTaggedValue()); 2667 JSTaggedValue callResult = JSFunction::Invoke(info, key); 2668 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2669 next = callResult; 2670 } 2671 JSHandle<JSTaggedValue> nextHandle(thread, next); 2672 JSHandle<EcmaString> nextStringHandle = JSTaggedValue::ToString(thread, nextHandle); 2673 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); 2674 CString nextString = ConvertToString(*nextStringHandle); 2675 if (k > 0) { 2676 concatStr += STRING_SEPERATOR; 2677 concatStr += nextString; 2678 continue; 2679 } 2680 concatStr += nextString; 2681 } 2682 2683 // pop this from join stack 2684 context->JoinStackPopFastPath(thisHandle); 2685 // 13. Return R. 2686 return factory->NewFromUtf8(concatStr).GetTaggedValue(); 2687} 2688 2689// 22.1.3.27 Array.prototype.toString ( ) 2690JSTaggedValue BuiltinsArray::ToString(EcmaRuntimeCallInfo *argv) 2691{ 2692 ASSERT(argv); 2693 BUILTINS_API_TRACE(argv->GetThread(), Array, ToString); 2694 JSThread *thread = argv->GetThread(); 2695 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2696 auto ecmaVm = thread->GetEcmaVM(); 2697 2698 // 1. Let array be ToObject(this value). 2699 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2700 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2701 // 2. ReturnIfAbrupt(array). 2702 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2703 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2704 2705 // 3. Let func be Get(array, "join"). 2706 JSHandle<JSTaggedValue> joinKey = thread->GlobalConstants()->GetHandledJoinString(); 2707 JSHandle<JSTaggedValue> callbackFnHandle = JSTaggedValue::GetProperty(thread, thisObjVal, joinKey).GetValue(); 2708 2709 // 4. ReturnIfAbrupt(func). 2710 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2711 2712 // 5. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString% (19.1.3.6). 2713 if (!callbackFnHandle->IsCallable()) { 2714 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 2715 JSHandle<JSTaggedValue> objectPrototype = env->GetObjectFunctionPrototype(); 2716 JSHandle<JSTaggedValue> toStringKey = thread->GlobalConstants()->GetHandledToStringString(); 2717 callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue(); 2718 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2719 } 2720 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 2721 EcmaRuntimeCallInfo *info = 2722 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, 0); 2723 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2724 return JSFunction::Call(info); 2725} 2726 2727// 22.1.3.28 Array.prototype.unshift ( ...items ) 2728JSTaggedValue BuiltinsArray::Unshift(EcmaRuntimeCallInfo *argv) 2729{ 2730 ASSERT(argv); 2731 BUILTINS_API_TRACE(argv->GetThread(), Array, Unshift); 2732 JSThread *thread = argv->GetThread(); 2733 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2734 2735 // 5. Let argCount be the number of actual arguments. 2736 int64_t argc = argv->GetArgsNumber(); 2737 2738 // 1. Let O be ToObject(this value). 2739 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2740 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2741 // 2. ReturnIfAbrupt(O). 2742 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2743 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2744 2745 // 3. Let len be ToLength(Get(O, "length")). 2746 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 2747 // 4. ReturnIfAbrupt(len). 2748 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2749 2750 // 6. If argCount > 0, then 2751 // a. If len+ argCount > 253-1, throw a TypeError exception. 2752 // b. Let k be len. 2753 // c. Repeat, while k > 0, 2754 // i. Let from be ToString(k–1). 2755 // ii. Let to be ToString(k+argCount –1). 2756 // iii. Let fromPresent be HasProperty(O, from). 2757 // iv. ReturnIfAbrupt(fromPresent). 2758 // v. If fromPresent is true, then 2759 // 1. Let fromValue be Get(O, from). 2760 // 2. ReturnIfAbrupt(fromValue). 2761 // 3. Let setStatus be Set(O, to, fromValue, true). 2762 // 4. ReturnIfAbrupt(setStatus). 2763 // vi. Else fromPresent is false, 2764 // 1. Let deleteStatus be DeletePropertyOrThrow(O, to). 2765 // 2. ReturnIfAbrupt(deleteStatus). 2766 // vii. Decrease k by 1. 2767 if (argc > 0) { 2768 if (len + argc > base::MAX_SAFE_INTEGER) { 2769 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 2770 } 2771 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 2772 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 2773 int64_t k = len; 2774 while (k > 0) { 2775 fromKey.Update(JSTaggedValue(k - 1)); 2776 toKey.Update(JSTaggedValue(k + argc - 1)); 2777 bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey); 2778 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2779 if (exists) { 2780 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 2781 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2782 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue); 2783 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2784 } else { 2785 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); 2786 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2787 } 2788 k--; 2789 } 2790 // d. Let j be 0. 2791 // e. Let items be a List whose elements are, in left to right order, the arguments that were passed to this 2792 // function invocation. 2793 // f. Repeat, while items is not empty 2794 // i. Remove the first element from items and let E be the value of that element. 2795 // ii. Let setStatus be Set(O, ToString(j), E, true). 2796 // iii. ReturnIfAbrupt(setStatus). 2797 // iv. Increase j by 1. 2798 int64_t j = 0; 2799 while (j < argc) { 2800 toKey.Update(JSTaggedValue(j)); 2801 JSHandle<JSTaggedValue> toValue = GetCallArg(argv, j); 2802 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, toValue); 2803 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2804 j++; 2805 } 2806 } 2807 2808 // 7. Let setStatus be Set(O, "length", len+argCount, true). 2809 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 2810 int64_t newLen = len + argc; 2811 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen)); 2812 JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true); 2813 // 8. ReturnIfAbrupt(setStatus). 2814 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2815 2816 // 9. Return len+argCount. 2817 return GetTaggedDouble(newLen); 2818} 2819 2820// 22.1.3.29 Array.prototype.values ( ) 2821JSTaggedValue BuiltinsArray::Values(EcmaRuntimeCallInfo *argv) 2822{ 2823 ASSERT(argv); 2824 BUILTINS_API_TRACE(argv->GetThread(), Array, Values); 2825 JSThread *thread = argv->GetThread(); 2826 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2827 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2828 // 1. Let O be ToObject(this value). 2829 // 2. ReturnIfAbrupt(O). 2830 JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv)); 2831 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2832 // 3. Return CreateArrayIterator(O, "value"). 2833 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::VALUE)); 2834 return iter.GetTaggedValue(); 2835} 2836 2837// es12 23.1.3.10 2838JSTaggedValue BuiltinsArray::Flat(EcmaRuntimeCallInfo *argv) 2839{ 2840 ASSERT(argv); 2841 BUILTINS_API_TRACE(argv->GetThread(), Array, Flat); 2842 JSThread *thread = argv->GetThread(); 2843 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2844 2845 // 1. Let O be ? ToObject(this value). 2846 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2847 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2848 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2849 2850 uint32_t argc = argv->GetArgsNumber(); 2851 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2852 2853 // 2. Let sourceLen be ? LengthOfArrayLike(O). 2854 int64_t sourceLen = ArrayHelper::GetLength(thread, thisObjVal); 2855 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2856 2857 // 3. Let depthNum be 1. 2858 double depthNum = 1; 2859 2860 // 4. If depth is not undefined, then 2861 // a. Set depthNum to ? ToIntegerOrInfinity(depth). 2862 // b. If depthNum < 0, set depthNum to 0. 2863 if (argc > 0) { 2864 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 0); 2865 if (!msg1->IsUndefined()) { 2866 JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1); 2867 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2868 depthNum = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber()); 2869 depthNum = depthNum < 0 ? 0 : depthNum; 2870 } 2871 } 2872 // 5. Let A be ? ArraySpeciesCreate(O, 0). 2873 uint32_t arrayLen = 0; 2874 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); 2875 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2876 2877 base::FlattenArgs args = { sourceLen, 0, depthNum }; 2878 JSHandle<JSObject> newArrayHandle(thread, newArray); 2879 // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum). 2880 ArrayHelper::FlattenIntoArray(thread, newArrayHandle, thisObjVal, args, 2881 thread->GlobalConstants()->GetHandledUndefined(), 2882 thread->GlobalConstants()->GetHandledUndefined()); 2883 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2884 2885 // 7. Return A. 2886 return newArrayHandle.GetTaggedValue(); 2887} 2888 2889// es12 23.1.3.11 2890JSTaggedValue BuiltinsArray::FlatMap(EcmaRuntimeCallInfo *argv) 2891{ 2892 ASSERT(argv); 2893 BUILTINS_API_TRACE(argv->GetThread(), Array, FlatMap); 2894 JSThread *thread = argv->GetThread(); 2895 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2896 2897 // 1. Let O be ? ToObject(this value). 2898 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2899 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2900 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2901 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2902 2903 // 2. Let sourceLen be ? LengthOfArrayLike(O). 2904 int64_t sourceLen = ArrayHelper::GetLength(thread, thisObjVal); 2905 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2906 2907 // 3. If ! IsCallable(mapperFunction) is false, throw a TypeError exception. 2908 JSHandle<JSTaggedValue> mapperFunctionHandle = GetCallArg(argv, 0); 2909 if (!mapperFunctionHandle->IsCallable()) { 2910 THROW_TYPE_ERROR_AND_RETURN(thread, "the mapperFunction is not callable.", JSTaggedValue::Exception()); 2911 } 2912 // 4. Let A be ? ArraySpeciesCreate(O, 0). 2913 uint32_t arrayLen = 0; 2914 JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); 2915 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2916 2917 base::FlattenArgs args = { sourceLen, 0, 1 }; 2918 JSHandle<JSObject> newArrayHandle(thread, newArray); 2919 // 5. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, thisArg). 2920 ArrayHelper::FlattenIntoArray(thread, newArrayHandle, thisObjVal, args, 2921 mapperFunctionHandle, GetCallArg(argv, 1)); 2922 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2923 // 6. Return A. 2924 return newArrayHandle.GetTaggedValue(); 2925} 2926 2927// 23.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] ) 2928JSTaggedValue BuiltinsArray::Includes(EcmaRuntimeCallInfo *argv) 2929{ 2930 ASSERT(argv); 2931 BUILTINS_API_TRACE(argv->GetThread(), Array, Includes); 2932 JSThread *thread = argv->GetThread(); 2933 [[maybe_unused]] EcmaHandleScope handleScope(thread); 2934 // 1. Let O be ? ToObject(this value). 2935 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 2936 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 2937 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2938 2939 uint32_t argc = argv->GetArgsNumber(); 2940 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 2941 JSHandle<JSTaggedValue> searchElement = GetCallArg(argv, 0); 2942 2943 // 2. Let len be ? LengthOfArrayLike(O). 2944 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 2945 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2946 // 3. If len is 0, return false. 2947 if (len == 0) { 2948 return GetTaggedBoolean(false); 2949 } 2950 // 4. Let n be ? ToIntegerOrInfinity(fromIndex). 2951 // 5. Assert: If fromIndex is undefined, then n is 0. 2952 double fromIndex = 0; 2953 if (argc > 1) { 2954 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1); 2955 JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1); 2956 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2957 fromIndex = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber()); 2958 } 2959 2960 // 6. If n is +∞, return false. 2961 // 7. Else if n is -∞, set n to 0. 2962 if (fromIndex >= len) { 2963 return GetTaggedBoolean(false); 2964 } else if (fromIndex < -len) { 2965 fromIndex = 0; 2966 } 2967 // 8. If n ≥ 0, then 2968 // a. Let k be n. 2969 // 9. Else, 2970 // a. Let k be len + n. 2971 // b. If k < 0, let k be 0. 2972 int64_t from = (fromIndex >= 0) ? fromIndex : ((len + fromIndex) >= 0 ? len + fromIndex : 0); 2973 2974 // 10. Repeat, while k < len, 2975 // a. Let elementK be ? Get(O, ! ToString(!(k))). 2976 // b. If SameValueZero(searchElement, elementK) is true, return true. 2977 // c. Set k to k + 1. 2978 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 2979 JSMutableHandle<JSTaggedValue> kValueHandle(thread, JSTaggedValue::Undefined()); 2980 JSHandle<EcmaString> fromStr; 2981 while (from < len) { 2982 JSHandle<JSTaggedValue> handledFrom(thread, JSTaggedValue(from)); 2983 fromStr = JSTaggedValue::ToString(thread, handledFrom); 2984 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2985 key.Update(fromStr.GetTaggedValue()); 2986 kValueHandle.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, key).GetTaggedValue()); 2987 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2988 if (JSTaggedValue::SameValueZero(searchElement.GetTaggedValue(), kValueHandle.GetTaggedValue())) { 2989 return GetTaggedBoolean(true); 2990 } 2991 from++; 2992 } 2993 // 11. Return false. 2994 return GetTaggedBoolean(false); 2995} 2996 2997// 23.1.3.1 Array.prototype.at ( index ) 2998JSTaggedValue BuiltinsArray::At(EcmaRuntimeCallInfo *argv) 2999{ 3000 ASSERT(argv); 3001 BUILTINS_API_TRACE(argv->GetThread(), Array, At); 3002 JSThread *thread = argv->GetThread(); 3003 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3004 3005 // 1. Let O be ToObject(this value). 3006 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3007 if (thisHandle->IsStableJSArray(thread)) { 3008 return JSStableArray::At(JSHandle<JSArray>::Cast(thisHandle), argv); 3009 } 3010 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3011 // ReturnIfAbrupt(O). 3012 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3013 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3014 3015 // 2. Let len be ? LengthOfArrayLike(O). 3016 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 3017 // ReturnIfAbrupt(len). 3018 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3019 3020 // 3. Let index be ? ToIntegerOrInfinity(index). 3021 JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); 3022 // ReturnIfAbrupt(index). 3023 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3024 3025 // 4. If relativeIndex ≥ 0, then 3026 // a. Let k be relativeIndex. 3027 // 5. Else, 3028 // a. Let k be len + relativeIndex. 3029 int64_t relativeIndex = index.GetNumber(); 3030 int64_t k = 0; 3031 if (relativeIndex >= 0) { 3032 k = relativeIndex; 3033 } else { 3034 k = len + relativeIndex; 3035 } 3036 3037 // 6. If k < 0 or k ≥ len, return undefined. 3038 if (k < 0 || k >= len) { 3039 // Return undefined. 3040 return JSTaggedValue::Undefined(); 3041 } 3042 // 7. Return ? Get(O, ! ToString((k))). 3043 JSHandle<JSTaggedValue> element = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 3044 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3045 return element.GetTaggedValue(); 3046} 3047 3048// 23.1.3.39 Array.prototype.with ( index, value ) 3049// NOLINTNEXTLINE(readability-function-size) 3050JSTaggedValue BuiltinsArray::With(EcmaRuntimeCallInfo *argv) 3051{ 3052 ASSERT(argv); 3053 JSThread *thread = argv->GetThread(); 3054 BUILTINS_API_TRACE(thread, Array, With); 3055 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3056 3057 // 1. Let O be ToObject(this value). 3058 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3059 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3060 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3061 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3062 // 2. Let len be ? LengthOfArrayLike(O). 3063 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 3064 // ReturnIfAbrupt(len). 3065 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3066 // 3. Let relativeIndex be ? ToIntegerOrInfinity(relativeIndex). 3067 JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); 3068 // ReturnIfAbrupt(index). 3069 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3070 int64_t relativeIndex = index.GetNumber(); 3071 int64_t actualIndex = 0; 3072 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); 3073 // 4. If relativeIndex ≥ 0, let actualIndex be relativeIndex. 3074 // 5. Else, let actualIndex be len + relativeIndex. 3075 // 6. If actualIndex ≥ len or actualIndex < 0, throw a RangeError exception. 3076 if (relativeIndex >= 0) { 3077 actualIndex = relativeIndex; 3078 } else { 3079 actualIndex = len + relativeIndex; 3080 } 3081 if (actualIndex >= len || actualIndex < 0) { 3082 THROW_RANGE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 3083 } 3084 // 7. Let A be ? ArrayCreate(len). 3085 JSTaggedValue newArray = 3086 JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue(); 3087 // ReturnIfAbrupt(A). 3088 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3089 JSHandle<JSObject> newArrayHandle(thread, newArray); 3090 if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) { 3091 return JSStableArray::With(thread, JSHandle<JSArray>::Cast(thisHandle), len, actualIndex, value); 3092 } 3093 // 8. Let k be 0. 3094 int64_t k = 0; 3095 // 9. Repeat, while k < len, 3096 // a. Let Pk be ! ToString((k)). 3097 // b. If k is actualIndex, let fromValue be value. 3098 // c. Else, let fromValue be ? Get(O, Pk). 3099 // d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue). 3100 // e. Set k to k + 1. 3101 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 3102 JSHandle<JSTaggedValue> fromValue; 3103 while (k < len) { 3104 fromKey.Update(JSTaggedValue(k)); 3105 if (k == actualIndex) { 3106 fromValue = value; 3107 } else { 3108 fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 3109 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3110 } 3111 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, fromKey, fromValue); 3112 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3113 ++k; 3114 thread->CheckSafepointIfSuspended(); 3115 } 3116 // 10. Return A. 3117 return newArrayHandle.GetTaggedValue(); 3118} 3119 3120// 23.1.3.34 Array.prototype.toSorted ( comparefn ) 3121JSTaggedValue BuiltinsArray::ToSorted(EcmaRuntimeCallInfo *argv) 3122{ 3123 ASSERT(argv); 3124 JSThread *thread = argv->GetThread(); 3125 BUILTINS_API_TRACE(thread, Array, ToSorted); 3126 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3127 3128 // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception. 3129 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 3130 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { 3131 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); 3132 } 3133 3134 // 2. Let obj be ToObject(this value). 3135 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3136 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3137 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3138 3139 // 3. Let len be ToLength(Get(obj, "length")). 3140 int64_t len = ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(thisObjHandle)); 3141 // ReturnIfAbrupt(len). 3142 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3143 3144 // 4. Let A be ? ArrayCreate(len). 3145 JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue(); 3146 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3147 JSHandle<JSObject> newArrayHandle(thread, newArray); 3148 3149 // 5. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs 3150 // the following steps when called: 3151 // a. Return ? CompareArrayElements(x, y, comparefn). 3152 // 6. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes). 3153 JSHandle<TaggedArray> sortedList = 3154 ArrayHelper::SortIndexedProperties(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), len, callbackFnHandle, 3155 base::HolesType::READ_THROUGH_HOLES); 3156 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3157 3158 //7. Let j be 0. 3159 int64_t j = 0; 3160 // 8. Repeat, while j < len, 3161 // a. Perform ! CreateDataPropertyOrThrow(A, ! ToString((j)), sortedList[j]). 3162 // b. Set j to j + 1. 3163 JSMutableHandle<JSTaggedValue> itemValue(thread, JSTaggedValue::Undefined()); 3164 while (j < len) { 3165 itemValue.Update(sortedList->Get(j)); 3166 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, itemValue); 3167 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3168 ++j; 3169 } 3170 // 9. Return A. 3171 return newArrayHandle.GetTaggedValue(); 3172} 3173 3174// 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items ) 3175JSTaggedValue BuiltinsArray::ToSpliced(EcmaRuntimeCallInfo *argv) 3176{ 3177 ASSERT(argv); 3178 JSThread *thread = argv->GetThread(); 3179 BUILTINS_API_TRACE(thread, Array, ToSpliced); 3180 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3181 uint32_t argc = argv->GetArgsNumber(); 3182 // 1. Let O be ? ToObject(this value). 3183 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3184 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3185 // ReturnIfAbrupt(O). 3186 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3187 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3188 // 2. Let len be ? LengthOfArrayLike(O). 3189 int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); 3190 // ReturnIfAbrupt(len). 3191 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3192 int64_t actualStart = 0; 3193 int64_t actualSkipCount = 0; 3194 int64_t newLen = 0; 3195 int64_t insertCount = 0; 3196 // 3. Let relativeStart be ? ToIntegerOrInfinity(start). 3197 if (argc > 0) { 3198 JSTaggedNumber argStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); 3199 // ReturnIfAbrupt(relativeStart). 3200 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3201 double relativeStart = argStart.GetNumber(); 3202 // 4. If relativeStart = -∞, let k be 0. 3203 // 5. Else if relativeStart < 0, let k be max(len + relativeStart, 0). 3204 // 6. Else, let k be min(relativeStart, len). 3205 if (relativeStart < 0) { 3206 double tempStart = relativeStart + len; 3207 actualStart = tempStart > 0 ? tempStart : 0; 3208 } else { 3209 actualStart = relativeStart < len ? relativeStart : len; 3210 } 3211 actualSkipCount = len - actualStart; 3212 } 3213 // 7. Let insertCount be the number of elements in items. 3214 // 8. If start is not present, then 3215 // a. Let actualSkipCount be 0. 3216 // 9. Else if skipCount is not present, then 3217 // a. Let actualSkipCount be len - actualStart. 3218 // 10. Else, 3219 // a. Let sc be ? ToIntegerOrInfinity(skipCount). 3220 // b. Let actualSkipCount be the result of clamping sc between 0 and len - actualStart. 3221 if (argc > 1) { 3222 insertCount = argc - 2; // 2:2 means there two arguments before the insert items. 3223 JSTaggedNumber argSkipCount = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 1)); 3224 // ReturnIfAbrupt(argSkipCount). 3225 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3226 double skipCount = argSkipCount.GetNumber(); 3227 skipCount = skipCount > 0 ? skipCount : 0; 3228 actualSkipCount = skipCount < (len - actualStart) ? skipCount : len - actualStart; 3229 } 3230 // 11. Let newLen be len + insertCount - actualSkipCount. 3231 newLen = len + insertCount - actualSkipCount; 3232 // 12. If newLen > 2^53 - 1, throw a TypeError exception. 3233 if (newLen > base::MAX_SAFE_INTEGER) { 3234 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); 3235 } 3236 if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) { 3237 return JSStableArray::ToSpliced(JSHandle<JSArray>::Cast(thisHandle), argv, argc, actualStart, 3238 actualSkipCount, newLen); 3239 } 3240 // 13. Let A be ? ArrayCreate(newLen). 3241 JSHandle<JSTaggedValue> newJsTaggedArray = 3242 JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(newLen))); 3243 // ReturnIfAbrupt(newArray). 3244 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3245 JSHandle<JSObject> newArrayHandle(thread, newJsTaggedArray.GetTaggedValue()); 3246 // 14. Let i be 0. 3247 int64_t i = 0; 3248 // 15. Let r be actualStart + actualSkipCount. 3249 int64_t r = actualStart + actualSkipCount; 3250 // 16. Repeat, while i < actualStart, 3251 // a. Let Pi be ! ToString((i)). 3252 // b. Let iValue be ? Get(O, Pi). 3253 // c. Perform ! CreateDataPropertyOrThrow(A, Pi, iValue). 3254 // d. Set i to i + 1. 3255 while (i < actualStart) { 3256 JSHandle<JSTaggedValue> iValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, i); 3257 // ReturnIfAbrupt(iValue). 3258 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3259 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, i, iValue); 3260 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3261 ++i; 3262 } 3263 // 17. For each element E of items, do 3264 // a. Let Pi be ! ToString((i)). 3265 // b. Perform ! CreateDataPropertyOrThrow(A, Pi, E). 3266 // c. Set i to i + 1. 3267 JSMutableHandle<JSTaggedValue> pi(thread, JSTaggedValue::Undefined()); 3268 for (int64_t pos = 2; pos < argc; ++pos) { // 2:2 means there two arguments before the insert items. 3269 pi.Update(JSTaggedValue(i)); 3270 JSHandle<JSTaggedValue> element = GetCallArg(argv, pos); 3271 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, pi, element); 3272 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3273 ++i; 3274 } 3275 // 18. Repeat, while i < newLen, 3276 // a. Let Pi be ! ToString((i)). 3277 // b. Let from be ! ToString((r)). 3278 // c. Let fromValue be ? Get(O, from). 3279 // d. Perform ! CreateDataPropertyOrThrow(A, Pi, fromValue). 3280 // e. Set i to i + 1. 3281 // f. Set r to r + 1. 3282 JSMutableHandle<JSTaggedValue> from(thread, JSTaggedValue::Undefined()); 3283 while (i < newLen) { 3284 pi.Update(JSTaggedValue(i)); 3285 from.Update(JSTaggedValue(r)); 3286 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, from); 3287 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3288 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, pi, fromValue); 3289 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3290 ++i; 3291 ++r; 3292 } 3293 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 3294 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen)); 3295 JSTaggedValue::SetProperty(thread, newJsTaggedArray, lengthKey, newLenHandle, true); 3296 // ReturnIfAbrupt(setStatus). 3297 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3298 // 19. Return A. 3299 return newArrayHandle.GetTaggedValue(); 3300} 3301 3302// 23.1.3.11 Array.prototype.findLast ( predicate [ , thisArg ] ) 3303JSTaggedValue BuiltinsArray::FindLast(EcmaRuntimeCallInfo *argv) 3304{ 3305 ASSERT(argv); 3306 JSThread *thread = argv->GetThread(); 3307 BUILTINS_API_TRACE(thread, Array, FindLast); 3308 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3309 3310 // 1. Let O be ToObject(this value). 3311 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3312 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3313 // 2. ReturnIfAbrupt(O). 3314 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3315 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3316 3317 // 3. Let len be ToLength(Get(O, "length")). 3318 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 3319 // 4. ReturnIfAbrupt(len). 3320 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3321 3322 // 5. If IsCallable(predicate) is false, throw a TypeError exception. 3323 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 3324 if (!callbackFnHandle->IsCallable()) { 3325 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); 3326 } 3327 3328 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 3329 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 3330 3331 // 7. Let k be (len - 1). 3332 // 8. Repeat, while k >= 0 3333 // a. Let Pk be ToString(k). 3334 // b. Let kValue be Get(O, Pk). 3335 // c. ReturnIfAbrupt(kValue). 3336 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). 3337 // e. ReturnIfAbrupt(testResult). 3338 // f. If testResult is true, return kValue. 3339 // g. Decrease k by 1. 3340 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 3341 int64_t k = len - 1; 3342 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 3343 const uint32_t argsLength = 3; // 3: «kValue, k, O» 3344 JSTaggedValue callResult = GetTaggedBoolean(false); 3345 if (thisObjVal->IsStableJSArray(thread)) { 3346 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined()); 3347 callResult = JSStableArray::HandleFindLastOfStable(thread, thisObjHandle, 3348 callbackFnHandle, thisArgHandle, kValue, k); 3349 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3350 if (callResult.ToBoolean()) { 3351 return kValue.GetTaggedValue(); 3352 } 3353 } 3354 3355 while (k >= 0) { 3356 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 3357 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3358 key.Update(JSTaggedValue(k)); 3359 EcmaRuntimeCallInfo *info = 3360 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 3361 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3362 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 3363 callResult = JSFunction::Call(info); 3364 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3365 if (callResult.ToBoolean()) { 3366 return kValue.GetTaggedValue(); 3367 } 3368 k--; 3369 } 3370 3371 // 9. Return undefined. 3372 return JSTaggedValue::Undefined(); 3373} 3374 3375// 23.1.3.12 Array.prototype.findLastIndex ( predicate [ , thisArg ] ) 3376JSTaggedValue BuiltinsArray::FindLastIndex(EcmaRuntimeCallInfo *argv) 3377{ 3378 ASSERT(argv); 3379 JSThread *thread = argv->GetThread(); 3380 BUILTINS_API_TRACE(thread, Array, FindLastIndex); 3381 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3382 3383 // 1. Let O be ToObject(this value). 3384 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3385 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3386 // 2. ReturnIfAbrupt(O). 3387 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3388 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3389 3390 // 3. Let len be ToLength(Get(O, "length")). 3391 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 3392 // 4. ReturnIfAbrupt(len). 3393 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3394 3395 // 5. If IsCallable(predicate) is false, throw a TypeError exception. 3396 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 3397 if (!callbackFnHandle->IsCallable()) { 3398 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); 3399 } 3400 3401 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. 3402 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 3403 3404 // 7. Let k be (len - 1). 3405 // 8. Repeat, while k >=0 3406 // a. Let Pk be ToString(k). 3407 // b. Let kValue be Get(O, Pk). 3408 // c. ReturnIfAbrupt(kValue). 3409 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). 3410 // e. ReturnIfAbrupt(testResult). 3411 // f. If testResult is true, return k. 3412 // g. Decrease k by 1. 3413 int64_t k = len - 1; 3414 JSTaggedValue callResult = GetTaggedBoolean(true); 3415 if (thisObjVal->IsStableJSArray(thread)) { 3416 callResult = 3417 JSStableArray::HandleFindLastIndexOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); 3418 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3419 if (callResult.ToBoolean()) { 3420 return GetTaggedDouble(k); 3421 } 3422 } 3423 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 3424 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 3425 const uint32_t argsLength = 3; // 3: «kValue, k, O» 3426 while (k >= 0) { 3427 JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); 3428 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3429 key.Update(JSTaggedValue(k)); 3430 EcmaRuntimeCallInfo *info = 3431 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 3432 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3433 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); 3434 callResult = JSFunction::Call(info); 3435 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3436 if (callResult.ToBoolean()) { 3437 return GetTaggedDouble(k); 3438 } 3439 k--; 3440 } 3441 3442 // 9. Return -1. 3443 return GetTaggedDouble(-1); 3444} 3445 3446// 23.1.3.33 Array.prototype.toReversed ( ) 3447JSTaggedValue BuiltinsArray::ToReversed(EcmaRuntimeCallInfo *argv) 3448{ 3449 ASSERT(argv); 3450 JSThread *thread = argv->GetThread(); 3451 BUILTINS_API_TRACE(thread, Array, ToReversed); 3452 [[maybe_unused]] EcmaHandleScope handleScope(thread); 3453 3454 // 1. Let O be ToObject(this value). 3455 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 3456 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); 3457 // ReturnIfAbrupt(O). 3458 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3459 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle); 3460 3461 // 2. Let len be ? LengthOfArrayLike(O). 3462 int64_t len = ArrayHelper::GetLength(thread, thisObjVal); 3463 // ReturnIfAbrupt(len). 3464 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3465 if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) { 3466 return JSStableArray::ToReversed(thread, JSHandle<JSArray>::Cast(thisHandle), len); 3467 } 3468 // 3. Let A be ? ArrayCreate(len). 3469 JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue(); 3470 // ReturnIfAbrupt(len). 3471 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3472 JSHandle<JSObject> newArrayHandle(thread, newArray); 3473 3474 // 4. Let k be 0. 3475 // 5. Repeat, while k < len, 3476 // a. Let from be ! ToString((len - k - 1)). 3477 // b. Let Pk be ! ToString((k)). 3478 // c. Let fromValue be ? Get(O, from). 3479 // d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue). 3480 // e. Set k to k + 1. 3481 JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined()); 3482 JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined()); 3483 int64_t k = 0; 3484 while (k < len) { 3485 int64_t from = len - k - 1; 3486 fromKey.Update(JSTaggedValue(from)); 3487 toKey.Update(JSTaggedValue(k)); 3488 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); 3489 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3490 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue); 3491 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3492 k++; 3493 thread->CheckSafepointIfSuspended(); 3494 } 3495 // 6. Return A. 3496 return newArrayHandle.GetTaggedValue(); 3497} 3498} // namespace panda::ecmascript::builtins 3499