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