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