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