• 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,
2232             thisObjHandle.GetTaggedValue(), i));
2233         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2234         while (beginIndex < endIndex) {
2235             int middleIndex = (beginIndex + endIndex) / 2; // 2 : half
2236             middleValue.Update(
2237                 ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), middleIndex));
2238             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2239             double compareResult = ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue);
2240             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2241             if (compareResult > 0) {
2242                 endIndex = middleIndex;
2243             } else {
2244                 beginIndex = middleIndex + 1;
2245             }
2246         }
2247 
2248         if (endIndex >= 0 && endIndex < i) {
2249             for (int j = i; j > endIndex; j--) {
2250                 previousValue.Update(
2251                     ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), j - 1));
2252                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2253                 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
2254                                                            previousValue.GetTaggedValue());
2255                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2256             }
2257             ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
2258                                                        presentValue.GetTaggedValue());
2259             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2260         }
2261     }
2262 
2263     return thisObjHandle.GetTaggedValue();
2264 }
2265 
2266 // 22.1.3.25 Array.prototype.splice (start, deleteCount , ...items )
2267 // NOLINTNEXTLINE(readability-function-size)
Splice(EcmaRuntimeCallInfo * argv)2268 JSTaggedValue BuiltinsArray::Splice(EcmaRuntimeCallInfo *argv)
2269 {
2270     ASSERT(argv);
2271     BUILTINS_API_TRACE(argv->GetThread(), Array, Splice);
2272     JSThread *thread = argv->GetThread();
2273     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2274     uint32_t argc = argv->GetArgsNumber();
2275     // 1. Let O be ToObject(this value).
2276     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2277     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2278     // 2. ReturnIfAbrupt(O).
2279     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2280     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2281     // 3. Let len be ToLength(Get(O, "length")).
2282     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
2283     // 4. ReturnIfAbrupt(len).
2284     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2285     // 5. Let relativeStart be ToInteger(start).
2286     int64_t start = 0;
2287     int64_t insertCount = 0;
2288     int64_t actualDeleteCount = 0;
2289     int64_t end = len;
2290     double argStart = 0;
2291     if (argc > 0) {
2292         JSHandle<JSTaggedValue> msg0 = GetCallArg(argv, 0);
2293         JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0);
2294         // 6. ReturnIfAbrupt(relativeStart).
2295         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2296         argStart = argStartTemp.GetNumber();
2297         // 7. If relativeStart < 0, let actualStart be max((len + relativeStart),0); else let actualStart be
2298         // min(relativeStart, len).
2299         if (argStart < 0) {
2300             double tempStart = argStart + len;
2301             start = tempStart > 0 ? tempStart : 0;
2302         } else {
2303             start = argStart < end ? argStart : end;
2304         }
2305         actualDeleteCount = len - start;
2306     }
2307     // 8. If the number of actual arguments is 0, then
2308     //   a. Let insertCount be 0.
2309     //   b. Let actualDeleteCount be 0.
2310     // 9. Else if the number of actual arguments is 1, then
2311     //   a. Let insertCount be 0.
2312     //   b. Let actualDeleteCount be len – actualStart.
2313     // 10. Else,
2314     //   a. Let insertCount be the number of actual arguments minus 2.
2315     //   b. Let dc be ToInteger(deleteCount).
2316     //   c. ReturnIfAbrupt(dc).
2317     //   d. Let actualDeleteCount be min(max(dc,0), len – actualStart).
2318     if (argc > 1) {
2319         insertCount = argc - 2;  // 2:2 means there are two arguments before the insert items.
2320         JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
2321         JSTaggedNumber argDeleteCount = JSTaggedValue::ToInteger(thread, msg1);
2322         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2323         double deleteCount = argDeleteCount.GetNumber();
2324         deleteCount = deleteCount > 0 ? deleteCount : 0;
2325         actualDeleteCount = deleteCount < (len - start) ? deleteCount : len - start;
2326     }
2327     // 11. If len+insertCount−actualDeleteCount > 253-1, throw a TypeError exception.
2328     if (len + insertCount - actualDeleteCount > base::MAX_SAFE_INTEGER) {
2329         THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
2330     }
2331     // 12. Let A be ArraySpeciesCreate(O, actualDeleteCount).
2332     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle,
2333                                                          JSTaggedNumber(static_cast<double>(actualDeleteCount)));
2334     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2335     if (thisHandle->IsStableJSArray(thread)) {
2336         return JSStableArray::Splice(JSHandle<JSArray>::Cast(thisHandle), argv, start, insertCount,
2337             actualDeleteCount, newArray);
2338     }
2339     JSHandle<JSObject> newArrayHandle(thread, newArray);
2340     // 14. Let k be 0.
2341     // 15. Repeat, while k < actualDeleteCount
2342     //   a. Let from be ToString(actualStart+k).
2343     //   b. Let fromPresent be HasProperty(O, from).
2344     //   d. If fromPresent is true, then
2345     //     i. Let fromValue be Get(O, from).
2346     //     iii. Let status be CreateDataPropertyOrThrow(A, ToString(k), fromValue).
2347     //   e. Increase k by 1.
2348     JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
2349     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
2350     int64_t k = 0;
2351     while (k < actualDeleteCount) {
2352         int64_t from = start + k;
2353         fromKey.Update(JSTaggedValue(from));
2354         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
2355         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2356         if (exists) {
2357             JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
2358             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2359             toKey.Update(JSTaggedValue(k));
2360             if (newArrayHandle->IsJSProxy()) {
2361                 toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue());
2362                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2363             }
2364             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue);
2365             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2366         }
2367         k++;
2368     }
2369     // 16. Let setStatus be Set(A, "length", actualDeleteCount, true).
2370     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
2371     JSHandle<JSTaggedValue> deleteCountHandle(thread, JSTaggedValue(actualDeleteCount));
2372     JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newArrayHandle), lengthKey, deleteCountHandle,
2373                                true);
2374     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2375     // 19. Let itemCount be the number of elements in items.
2376     // 20. If itemCount < actualDeleteCount, then
2377     //   a. Let k be actualStart.
2378     //   b. Repeat, while k < (len – actualDeleteCount)
2379     //     i. Let from be ToString(k+actualDeleteCount).
2380     //     ii. Let to be ToString(k+itemCount).
2381     //     iii. Let fromPresent be HasProperty(O, from).
2382     //     v. If fromPresent is true, then
2383     //       1. Let fromValue be Get(O, from).
2384     //       3. Let setStatus be Set(O, to, fromValue, true).
2385     //     vi. Else fromPresent is false,
2386     //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
2387     //     vii. Increase k by 1.
2388     //   c. Let k be len.
2389     //   d. Repeat, while k > (len – actualDeleteCount + itemCount)
2390     //     i. Let deleteStatus be DeletePropertyOrThrow(O, ToString(k–1)).
2391     //     iii. Decrease k by 1.
2392     if (insertCount < actualDeleteCount) {
2393         k = start;
2394         while (k < len - actualDeleteCount) {
2395             fromKey.Update(JSTaggedValue(k + actualDeleteCount));
2396             toKey.Update(JSTaggedValue(k + insertCount));
2397             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
2398             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2399             if (exists) {
2400                 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
2401                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2402                 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
2403                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2404             } else {
2405                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
2406                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2407             }
2408             k++;
2409         }
2410         k = len;
2411         JSMutableHandle<JSTaggedValue> deleteKey(thread, JSTaggedValue::Undefined());
2412         while (k > len - actualDeleteCount + insertCount) {
2413             deleteKey.Update(JSTaggedValue(k - 1));
2414             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey);
2415             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2416             k--;
2417         }
2418     } else if (insertCount > actualDeleteCount) {
2419         // 21. Else if itemCount > actualDeleteCount, then
2420         //   a. Let k be (len – actualDeleteCount).
2421         //   b. Repeat, while k > actualStart
2422         //     i. Let from be ToString(k + actualDeleteCount – 1).
2423         //     ii. Let to be ToString(k + itemCount – 1)
2424         //     iii. Let fromPresent be HasProperty(O, from).
2425         //     iv. ReturnIfAbrupt(fromPresent).
2426         //     v. If fromPresent is true, then
2427         //       1. Let fromValue be Get(O, from).
2428         //       2. ReturnIfAbrupt(fromValue).
2429         //       3. Let setStatus be Set(O, to, fromValue, true).
2430         //       4. ReturnIfAbrupt(setStatus).
2431         //     vi. Else fromPresent is false,
2432         //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
2433         //       2. ReturnIfAbrupt(deleteStatus).
2434         //     vii. Decrease k by 1.
2435         k = len - actualDeleteCount;
2436         while (k > start) {
2437             fromKey.Update(JSTaggedValue(k + actualDeleteCount - 1));
2438             toKey.Update(JSTaggedValue(k + insertCount - 1));
2439             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
2440             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2441             if (exists) {
2442                 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
2443                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2444                 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
2445                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2446             } else {
2447                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
2448                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2449             }
2450             k--;
2451         }
2452     }
2453     // 22. Let k be actualStart.
2454     k = start;
2455     // 23. Repeat, while items is not empty
2456     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2457     for (uint32_t i = 2; i < argc; i++) {
2458         JSHandle<JSTaggedValue> itemValue = GetCallArg(argv, i);
2459         key.Update(JSTaggedValue(k));
2460         JSArray::FastSetPropertyByValue(thread, thisObjVal, key, itemValue);
2461         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2462         k++;
2463     }
2464     // 24. Let setStatus be Set(O, "length", len – actualDeleteCount + itemCount, true).
2465     int64_t newLen = len - actualDeleteCount + insertCount;
2466     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
2467     JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true);
2468     // 25. ReturnIfAbrupt(setStatus).
2469     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2470     // 26. Return A.
2471     return newArrayHandle.GetTaggedValue();
2472 }
2473 
2474 // 22.1.3.26 Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )
ToLocaleString(EcmaRuntimeCallInfo * argv)2475 JSTaggedValue BuiltinsArray::ToLocaleString(EcmaRuntimeCallInfo *argv)
2476 {
2477     ASSERT(argv);
2478     BUILTINS_API_TRACE(argv->GetThread(), Array, ToLocaleString);
2479     JSThread *thread = argv->GetThread();
2480     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2481     auto ecmaVm = thread->GetEcmaVM();
2482     ObjectFactory *factory = ecmaVm->GetFactory();
2483 
2484     // 1. Let O be ToObject(this value).
2485     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2486     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2487     // 2. ReturnIfAbrupt(O).
2488     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2489     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2490 
2491     // 3. Let len be ToLength(Get(O, "length")).
2492     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2493     // 4. ReturnIfAbrupt(len).
2494     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2495 
2496     // 6. If len is zero, return the empty String.
2497     if (len == 0) {
2498         return GetTaggedString(thread, "");
2499     }
2500 
2501     // Inject locales and options argument into a taggedArray
2502     JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
2503     JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
2504 
2505     CString concatStr;
2506     // 7. Let firstElement be Get(array, "0").
2507     // 8. ReturnIfAbrupt(firstElement).
2508     // 9. If firstElement is undefined or null, then
2509     //   a. Let R be the empty String.
2510     // 10. Else
2511     //   a. Let R be ToString(Invoke(firstElement, "toLocaleString")).
2512     //   b. ReturnIfAbrupt(R).
2513     // 11. Let k be 1.
2514     // 12. Repeat, while k < len
2515     //   a. Let S be a String value produced by concatenating R and separator.
2516     //   b. Let nextElement be Get(array, ToString(k)).
2517     //   c. ReturnIfAbrupt(nextElement).
2518     //   d. If nextElement is undefined or null, then
2519     //     i. Let R be the empty String.
2520     //   e. Else
2521     //     i. Let R be ToString(Invoke(nextElement, "toLocaleString")).
2522     //     ii. ReturnIfAbrupt(R).
2523     //   f. Let R be a String value produced by concatenating S and R.
2524     //   g. Increase k by 1.
2525     auto globalConst = thread->GlobalConstants();
2526     JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
2527     for (int64_t k = 0; k < len; k++) {
2528         JSTaggedValue next = globalConst->GetEmptyString();
2529         JSHandle<JSTaggedValue> nextElement = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
2530         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2531         if (!nextElement->IsUndefined() && !nextElement->IsNull()) {
2532             JSHandle<JSTaggedValue> nextValueHandle = nextElement;
2533             JSHandle<JSTaggedValue> key = globalConst->GetHandledToLocaleStringString();
2534             EcmaRuntimeCallInfo *info =
2535                 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextValueHandle, undefined, 2); // 2: two args
2536             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2537             info->SetCallArg(locales.GetTaggedValue(), options.GetTaggedValue());
2538             JSTaggedValue callResult = JSFunction::Invoke(info, key);
2539             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2540             next = callResult;
2541         }
2542         JSHandle<JSTaggedValue> nextHandle(thread, next);
2543         JSHandle<EcmaString> nextStringHandle = JSTaggedValue::ToString(thread, nextHandle);
2544         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2545         CString nextString = ConvertToString(*nextStringHandle);
2546         if (k > 0) {
2547             concatStr += STRING_SEPERATOR;
2548             concatStr += nextString;
2549             continue;
2550         }
2551         concatStr += nextString;
2552     }
2553 
2554     // 13. Return R.
2555     return factory->NewFromUtf8(concatStr).GetTaggedValue();
2556 }
2557 
2558 // 22.1.3.27 Array.prototype.toString ( )
ToString(EcmaRuntimeCallInfo * argv)2559 JSTaggedValue BuiltinsArray::ToString(EcmaRuntimeCallInfo *argv)
2560 {
2561     ASSERT(argv);
2562     BUILTINS_API_TRACE(argv->GetThread(), Array, ToString);
2563     JSThread *thread = argv->GetThread();
2564     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2565     auto ecmaVm = thread->GetEcmaVM();
2566 
2567     // 1. Let array be ToObject(this value).
2568     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2569     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2570     // 2. ReturnIfAbrupt(array).
2571     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2572     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2573 
2574     // 3. Let func be Get(array, "join").
2575     JSHandle<JSTaggedValue> joinKey = thread->GlobalConstants()->GetHandledJoinString();
2576     JSHandle<JSTaggedValue> callbackFnHandle = JSTaggedValue::GetProperty(thread, thisObjVal, joinKey).GetValue();
2577 
2578     // 4. ReturnIfAbrupt(func).
2579     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2580 
2581     // 5. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString% (19.1.3.6).
2582     if (!callbackFnHandle->IsCallable()) {
2583         JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
2584         JSHandle<JSTaggedValue> objectPrototype = env->GetObjectFunctionPrototype();
2585         JSHandle<JSTaggedValue> toStringKey = thread->GlobalConstants()->GetHandledToStringString();
2586         callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue();
2587         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2588     }
2589     const uint32_t argsLength = argv->GetArgsNumber();
2590     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2591     EcmaRuntimeCallInfo *info =
2592         EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength);
2593     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2594     info->SetCallArg(argsLength, 0, argv, 0);
2595     return JSFunction::Call(info);
2596 }
2597 
2598 // 22.1.3.28 Array.prototype.unshift ( ...items )
Unshift(EcmaRuntimeCallInfo * argv)2599 JSTaggedValue BuiltinsArray::Unshift(EcmaRuntimeCallInfo *argv)
2600 {
2601     ASSERT(argv);
2602     BUILTINS_API_TRACE(argv->GetThread(), Array, Unshift);
2603     JSThread *thread = argv->GetThread();
2604     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2605 
2606     // 5. Let argCount be the number of actual arguments.
2607     int64_t argc = argv->GetArgsNumber();
2608 
2609     // 1. Let O be ToObject(this value).
2610     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2611     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2612     // 2. ReturnIfAbrupt(O).
2613     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2614     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2615 
2616     // 3. Let len be ToLength(Get(O, "length")).
2617     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
2618     // 4. ReturnIfAbrupt(len).
2619     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2620 
2621     // 6. If argCount > 0, then
2622     //   a. If len+ argCount > 253-1, throw a TypeError exception.
2623     //   b. Let k be len.
2624     //   c. Repeat, while k > 0,
2625     //     i. Let from be ToString(k–1).
2626     //     ii. Let to be ToString(k+argCount –1).
2627     //     iii. Let fromPresent be HasProperty(O, from).
2628     //     iv. ReturnIfAbrupt(fromPresent).
2629     //     v. If fromPresent is true, then
2630     //       1. Let fromValue be Get(O, from).
2631     //       2. ReturnIfAbrupt(fromValue).
2632     //       3. Let setStatus be Set(O, to, fromValue, true).
2633     //       4. ReturnIfAbrupt(setStatus).
2634     //     vi. Else fromPresent is false,
2635     //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
2636     //       2. ReturnIfAbrupt(deleteStatus).
2637     //     vii. Decrease k by 1.
2638     if (argc > 0) {
2639         if (len + argc > base::MAX_SAFE_INTEGER) {
2640             THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
2641         }
2642         JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
2643         JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
2644         int64_t k = len;
2645         while (k > 0) {
2646             fromKey.Update(JSTaggedValue(k - 1));
2647             toKey.Update(JSTaggedValue(k + argc - 1));
2648             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
2649             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2650             if (exists) {
2651                 JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
2652                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2653                 JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
2654                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2655             } else {
2656                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
2657                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2658             }
2659             k--;
2660         }
2661         //   d. Let j be 0.
2662         //   e. Let items be a List whose elements are, in left to right order, the arguments that were passed to this
2663         //   function invocation.
2664         //   f. Repeat, while items is not empty
2665         //     i. Remove the first element from items and let E be the value of that element.
2666         //     ii. Let setStatus be Set(O, ToString(j), E, true).
2667         //     iii. ReturnIfAbrupt(setStatus).
2668         //     iv. Increase j by 1.
2669         int64_t j = 0;
2670         while (j < argc) {
2671             toKey.Update(JSTaggedValue(j));
2672             JSHandle<JSTaggedValue> toValue = GetCallArg(argv, j);
2673             JSArray::FastSetPropertyByValue(thread, thisObjVal, toKey, toValue);
2674             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2675             j++;
2676         }
2677     }
2678 
2679     // 7. Let setStatus be Set(O, "length", len+argCount, true).
2680     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
2681     int64_t newLen = len + argc;
2682     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
2683     JSTaggedValue::SetProperty(thread, thisObjVal, lengthKey, newLenHandle, true);
2684     // 8. ReturnIfAbrupt(setStatus).
2685     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2686 
2687     // 9. Return len+argCount.
2688     return GetTaggedDouble(newLen);
2689 }
2690 
2691 // 22.1.3.29 Array.prototype.values ( )
Values(EcmaRuntimeCallInfo * argv)2692 JSTaggedValue BuiltinsArray::Values(EcmaRuntimeCallInfo *argv)
2693 {
2694     ASSERT(argv);
2695     BUILTINS_API_TRACE(argv->GetThread(), Array, Values);
2696     JSThread *thread = argv->GetThread();
2697     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2698     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2699     // 1. Let O be ToObject(this value).
2700     // 2. ReturnIfAbrupt(O).
2701     JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv));
2702     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2703     // 3. Return CreateArrayIterator(O, "value").
2704     JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::VALUE));
2705     return iter.GetTaggedValue();
2706 }
2707 // 22.1.3.31 Array.prototype [ @@unscopables ]
Unscopables(EcmaRuntimeCallInfo * argv)2708 JSTaggedValue BuiltinsArray::Unscopables(EcmaRuntimeCallInfo *argv)
2709 {
2710     JSThread *thread = argv->GetThread();
2711     BUILTINS_API_TRACE(thread, Array, Unscopables);
2712     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2713     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2714     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2715 
2716     JSHandle<JSObject> unscopableList = factory->CreateNullJSObject();
2717 
2718     JSHandle<JSTaggedValue> trueVal(thread, JSTaggedValue::True());
2719     JSHandle<JSTaggedValue> copyWithKey = globalConst->GetHandledCopyWithinString();
2720     JSObject::CreateDataProperty(thread, unscopableList, copyWithKey, trueVal);
2721 
2722     JSHandle<JSTaggedValue> entriesKey = globalConst->GetHandledEntriesString();
2723     JSObject::CreateDataProperty(thread, unscopableList, entriesKey, trueVal);
2724 
2725     JSHandle<JSTaggedValue> fillKey = globalConst->GetHandledFillString();
2726     JSObject::CreateDataProperty(thread, unscopableList, fillKey, trueVal);
2727 
2728     JSHandle<JSTaggedValue> findKey = globalConst->GetHandledFindString();
2729     JSObject::CreateDataProperty(thread, unscopableList, findKey, trueVal);
2730 
2731     JSHandle<JSTaggedValue> findIndexKey = globalConst->GetHandledFindIndexString();
2732     JSObject::CreateDataProperty(thread, unscopableList, findIndexKey, trueVal);
2733 
2734     JSHandle<JSTaggedValue> flatKey = globalConst->GetHandledFlatString();
2735     JSObject::CreateDataProperty(thread, unscopableList, flatKey, trueVal);
2736 
2737     JSHandle<JSTaggedValue> flatMapKey = globalConst->GetHandledFlatMapString();
2738     JSObject::CreateDataProperty(thread, unscopableList, flatMapKey, trueVal);
2739 
2740     JSHandle<JSTaggedValue> includesKey = globalConst->GetHandledIncludesString();
2741     JSObject::CreateDataProperty(thread, unscopableList, includesKey, trueVal);
2742 
2743     JSHandle<JSTaggedValue> keysKey = globalConst->GetHandledKeysString();
2744     JSObject::CreateDataProperty(thread, unscopableList, keysKey, trueVal);
2745 
2746     JSHandle<JSTaggedValue> valuesKey = globalConst->GetHandledValuesString();
2747     JSObject::CreateDataProperty(thread, unscopableList, valuesKey, trueVal);
2748 
2749     return unscopableList.GetTaggedValue();
2750 }
2751 
2752 // es12 23.1.3.10
Flat(EcmaRuntimeCallInfo * argv)2753 JSTaggedValue BuiltinsArray::Flat(EcmaRuntimeCallInfo *argv)
2754 {
2755     ASSERT(argv);
2756     BUILTINS_API_TRACE(argv->GetThread(), Array, Flat);
2757     JSThread *thread = argv->GetThread();
2758     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2759 
2760     // 1. Let O be ? ToObject(this value).
2761     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2762     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2763     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2764 
2765     uint32_t argc = argv->GetArgsNumber();
2766     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2767 
2768     // 2. Let sourceLen be ? LengthOfArrayLike(O).
2769     int64_t sourceLen = ArrayHelper::GetLength(thread, thisObjVal);
2770     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2771 
2772     // 3. Let depthNum be 1.
2773     double depthNum = 1;
2774 
2775     // 4. If depth is not undefined, then
2776     // a. Set depthNum to ? ToIntegerOrInfinity(depth).
2777     // b. If depthNum < 0, set depthNum to 0.
2778     if (argc > 0) {
2779         JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 0);
2780         JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1);
2781         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2782         depthNum = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber());
2783         depthNum = depthNum < 0 ? 0 : depthNum;
2784     }
2785 
2786     // 5. Let A be ? ArraySpeciesCreate(O, 0).
2787     uint32_t arrayLen = 0;
2788     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen));
2789     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2790 
2791     base::FlattenArgs args = { sourceLen, 0, depthNum };
2792     JSHandle<JSObject> newArrayHandle(thread, newArray);
2793     // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
2794     ArrayHelper::FlattenIntoArray(thread, newArrayHandle, thisObjVal, args,
2795                                   thread->GlobalConstants()->GetHandledUndefined(),
2796                                   thread->GlobalConstants()->GetHandledUndefined());
2797 
2798     // 7. Return A.
2799     return newArrayHandle.GetTaggedValue();
2800 }
2801 
2802 // es12 23.1.3.11
FlatMap(EcmaRuntimeCallInfo * argv)2803 JSTaggedValue BuiltinsArray::FlatMap(EcmaRuntimeCallInfo *argv)
2804 {
2805     ASSERT(argv);
2806     BUILTINS_API_TRACE(argv->GetThread(), Array, FlatMap);
2807     JSThread *thread = argv->GetThread();
2808     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2809 
2810     // 1. Let O be ? ToObject(this value).
2811     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2812     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2813     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2814     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2815 
2816     // 2. Let sourceLen be ? LengthOfArrayLike(O).
2817     int64_t sourceLen = ArrayHelper::GetLength(thread, thisObjVal);
2818     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2819 
2820     // 3. If ! IsCallable(mapperFunction) is false, throw a TypeError exception.
2821     JSHandle<JSTaggedValue> mapperFunctionHandle = GetCallArg(argv, 0);
2822     if (!mapperFunctionHandle->IsCallable()) {
2823         THROW_TYPE_ERROR_AND_RETURN(thread, "the mapperFunction is not callable.", JSTaggedValue::Exception());
2824     }
2825     // 4. Let A be ? ArraySpeciesCreate(O, 0).
2826     uint32_t arrayLen = 0;
2827     JSTaggedValue newArray = JSArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen));
2828     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2829 
2830     base::FlattenArgs args = { sourceLen, 0, 1 };
2831     JSHandle<JSObject> newArrayHandle(thread, newArray);
2832     // 5. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, thisArg).
2833     ArrayHelper::FlattenIntoArray(thread, newArrayHandle, thisObjVal, args,
2834                                   mapperFunctionHandle, GetCallArg(argv, 1));
2835 
2836     // 6. Return A.
2837     return newArrayHandle.GetTaggedValue();
2838 }
2839 
2840 // 23.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
Includes(EcmaRuntimeCallInfo * argv)2841 JSTaggedValue BuiltinsArray::Includes(EcmaRuntimeCallInfo *argv)
2842 {
2843     ASSERT(argv);
2844     BUILTINS_API_TRACE(argv->GetThread(), Array, Includes);
2845     JSThread *thread = argv->GetThread();
2846     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2847     // 1. Let O be ? ToObject(this value).
2848     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2849     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2850     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2851 
2852     uint32_t argc = argv->GetArgsNumber();
2853     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2854     JSHandle<JSTaggedValue> searchElement = GetCallArg(argv, 0);
2855 
2856     // 2. Let len be ? LengthOfArrayLike(O).
2857     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2858     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2859     // 3. If len is 0, return false.
2860     if (len == 0) {
2861         return GetTaggedBoolean(false);
2862     }
2863     // 4. Let n be ? ToIntegerOrInfinity(fromIndex).
2864     // 5. Assert: If fromIndex is undefined, then n is 0.
2865     double fromIndex = 0;
2866     if (argc > 1) {
2867         JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
2868         JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1);
2869         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2870         fromIndex = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber());
2871     }
2872 
2873     // 6. If n is +∞, return false.
2874     // 7. Else if n is -∞, set n to 0.
2875     if (fromIndex >= len) {
2876         return GetTaggedBoolean(false);
2877     } else if (fromIndex < -len) {
2878         fromIndex = 0;
2879     }
2880     // 8. If n ≥ 0, then
2881     //     a. Let k be n.
2882     // 9. Else,
2883     //     a. Let k be len + n.
2884     //     b. If k < 0, let k be 0.
2885     int64_t from = (fromIndex >= 0) ? fromIndex : ((len + fromIndex) >= 0 ? len + fromIndex : 0);
2886 
2887     // 10. Repeat, while k < len,
2888     //     a. Let elementK be ? Get(O, ! ToString(!(k))).
2889     //     b. If SameValueZero(searchElement, elementK) is true, return true.
2890     //     c. Set k to k + 1.
2891     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2892     JSMutableHandle<JSTaggedValue> kValueHandle(thread, JSTaggedValue::Undefined());
2893     JSHandle<EcmaString> fromStr;
2894     while (from < len) {
2895         JSHandle<JSTaggedValue> handledFrom(thread, JSTaggedValue(from));
2896         fromStr = JSTaggedValue::ToString(thread, handledFrom);
2897         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2898         key.Update(fromStr.GetTaggedValue());
2899         kValueHandle.Update(JSArray::FastGetPropertyByValue(thread, thisObjVal, key).GetTaggedValue());
2900         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2901         if (JSTaggedValue::SameValueZero(searchElement.GetTaggedValue(), kValueHandle.GetTaggedValue())) {
2902             return GetTaggedBoolean(true);
2903         }
2904         from++;
2905     }
2906     // 11. Return false.
2907     return GetTaggedBoolean(false);
2908 }
2909 
2910 // 23.1.3.1 Array.prototype.at ( index )
At(EcmaRuntimeCallInfo * argv)2911 JSTaggedValue BuiltinsArray::At(EcmaRuntimeCallInfo *argv)
2912 {
2913     ASSERT(argv);
2914     BUILTINS_API_TRACE(argv->GetThread(), Array, At);
2915     JSThread *thread = argv->GetThread();
2916     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2917 
2918     // 1. Let O be ToObject(this value).
2919     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2920     if (thisHandle->IsStableJSArray(thread)) {
2921         return JSStableArray::At(JSHandle<JSArray>::Cast(thisHandle), argv);
2922     }
2923     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2924     // ReturnIfAbrupt(O).
2925     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2926     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2927 
2928     // 2. Let len be ? LengthOfArrayLike(O).
2929     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2930     // ReturnIfAbrupt(len).
2931     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2932 
2933     // 3. Let index be ? ToIntegerOrInfinity(index).
2934     JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
2935     // ReturnIfAbrupt(index).
2936     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2937 
2938     // 4. If relativeIndex ≥ 0, then
2939     //     a. Let k be relativeIndex.
2940     // 5. Else,
2941     //     a. Let k be len + relativeIndex.
2942     int64_t relativeIndex = index.GetNumber();
2943     int64_t k = 0;
2944     if (relativeIndex >= 0) {
2945         k = relativeIndex;
2946     } else {
2947         k = len + relativeIndex;
2948     }
2949 
2950     // 6. If k < 0 or k ≥ len, return undefined.
2951     if (k < 0 || k >= len) {
2952         // Return undefined.
2953         return JSTaggedValue::Undefined();
2954     }
2955     // 7. Return ? Get(O, ! ToString(��(k))).
2956     JSHandle<JSTaggedValue> element = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
2957     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2958     return element.GetTaggedValue();
2959 }
2960 
2961 // 23.1.3.39 Array.prototype.with ( index, value )
2962 // NOLINTNEXTLINE(readability-function-size)
With(EcmaRuntimeCallInfo * argv)2963 JSTaggedValue BuiltinsArray::With(EcmaRuntimeCallInfo *argv)
2964 {
2965     ASSERT(argv);
2966     JSThread *thread = argv->GetThread();
2967     BUILTINS_API_TRACE(thread, Array, With);
2968     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2969 
2970     // 1. Let O be ToObject(this value).
2971     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2972     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2973     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2974     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2975     // 2. Let len be ? LengthOfArrayLike(O).
2976     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2977     // ReturnIfAbrupt(len).
2978     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2979     // 3. Let relativeIndex be ? ToIntegerOrInfinity(relativeIndex).
2980     JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
2981     // ReturnIfAbrupt(index).
2982     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2983     int64_t relativeIndex = index.GetNumber();
2984     int64_t actualIndex = 0;
2985     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
2986     // 4. If relativeIndex ≥ 0, let actualIndex be relativeIndex.
2987     // 5. Else, let actualIndex be len + relativeIndex.
2988     // 6. If actualIndex ≥ len or actualIndex < 0, throw a RangeError exception.
2989     if (relativeIndex >= 0) {
2990         actualIndex = relativeIndex;
2991     } else {
2992         actualIndex = len + relativeIndex;
2993     }
2994     if (actualIndex >= len || actualIndex < 0) {
2995         THROW_RANGE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
2996     }
2997     // 7. Let A be ? ArrayCreate(len).
2998     JSTaggedValue newArray =
2999         JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue();
3000     // ReturnIfAbrupt(A).
3001     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3002     JSHandle<JSObject> newArrayHandle(thread, newArray);
3003     if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) {
3004         return JSStableArray::With(thread, JSHandle<JSArray>::Cast(thisHandle), len, actualIndex, value);
3005     }
3006     // 8. Let k be 0.
3007     int64_t k = 0;
3008     // 9. Repeat, while k < len,
3009     //     a. Let Pk be ! ToString(��(k)).
3010     //     b. If k is actualIndex, let fromValue be value.
3011     //     c. Else, let fromValue be ? Get(O, Pk).
3012     //     d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue).
3013     //     e. Set k to k + 1.
3014     JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
3015     JSHandle<JSTaggedValue> fromValue;
3016     while (k < len) {
3017         fromKey.Update(JSTaggedValue(k));
3018         if (k == actualIndex) {
3019             fromValue = value;
3020         } else {
3021             fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
3022             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3023         }
3024         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, fromKey, fromValue);
3025         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3026         ++k;
3027     }
3028     // 10. Return A.
3029     return newArrayHandle.GetTaggedValue();
3030 }
3031 
3032 // 23.1.3.34 Array.prototype.toSorted ( comparefn )
ToSorted(EcmaRuntimeCallInfo * argv)3033 JSTaggedValue BuiltinsArray::ToSorted(EcmaRuntimeCallInfo *argv)
3034 {
3035     ASSERT(argv);
3036     JSThread *thread = argv->GetThread();
3037     BUILTINS_API_TRACE(thread, Array, ToSorted);
3038     [[maybe_unused]] EcmaHandleScope handleScope(thread);
3039 
3040     // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
3041     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
3042     if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
3043         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
3044     }
3045 
3046     // 2. Let obj be ToObject(this value).
3047     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
3048     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
3049     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3050 
3051     // 3. Let len be ToLength(Get(obj, "length")).
3052     int64_t len = ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(thisObjHandle));
3053     // ReturnIfAbrupt(len).
3054     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3055 
3056     // 4. Let A be ? ArrayCreate(len).
3057     JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue();
3058     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3059     JSHandle<JSObject> newArrayHandle(thread, newArray);
3060 
3061     // 5. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs
3062     // the following steps when called:
3063     //    a. Return ? CompareArrayElements(x, y, comparefn).
3064     // 6. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes).
3065     JSTaggedValue sortedList = ArrayHelper::SortIndexedProperties(thread, thisObjHandle, len, callbackFnHandle,
3066                                                                   base::HolesType::READ_THROUGH_HOLES);
3067     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3068     JSHandle<JSTaggedValue> sortedArray(thread, sortedList);
3069 
3070     //7. Let j be 0.
3071     int64_t j = 0;
3072     // 8. Repeat, while j < len,
3073     //     a. Perform ! CreateDataPropertyOrThrow(A, ! ToString(��(j)), sortedList[j]).
3074     //     b. Set j to j + 1.
3075     while (j < len) {
3076         JSHandle<JSTaggedValue> item = JSArray::FastGetPropertyByValue(thread, sortedArray, j);
3077         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3078         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, item);
3079         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3080         ++j;
3081     }
3082     // 9. Return A.
3083     return newArrayHandle.GetTaggedValue();
3084 }
3085 
3086 // 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items )
ToSpliced(EcmaRuntimeCallInfo * argv)3087 JSTaggedValue BuiltinsArray::ToSpliced(EcmaRuntimeCallInfo *argv)
3088 {
3089     ASSERT(argv);
3090     JSThread *thread = argv->GetThread();
3091     BUILTINS_API_TRACE(thread, Array, ToSpliced);
3092     [[maybe_unused]] EcmaHandleScope handleScope(thread);
3093     uint32_t argc = argv->GetArgsNumber();
3094     // 1. Let O be ? ToObject(this value).
3095     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
3096     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
3097     // ReturnIfAbrupt(O).
3098     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3099     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
3100     // 2. Let len be ? LengthOfArrayLike(O).
3101     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
3102     // ReturnIfAbrupt(len).
3103     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3104     int64_t actualStart = 0;
3105     int64_t actualSkipCount = 0;
3106     int64_t newLen = 0;
3107     int64_t insertCount = 0;
3108     // 3. Let relativeStart be ? ToIntegerOrInfinity(start).
3109     if (argc > 0) {
3110         JSTaggedNumber argStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
3111         // ReturnIfAbrupt(relativeStart).
3112         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3113         double relativeStart = argStart.GetNumber();
3114         // 4. If relativeStart = -∞, let k be 0.
3115         // 5. Else if relativeStart < 0, let k be max(len + relativeStart, 0).
3116         // 6. Else, let k be min(relativeStart, len).
3117         if (relativeStart < 0) {
3118             double tempStart = relativeStart + len;
3119             actualStart = tempStart > 0 ? tempStart : 0;
3120         } else {
3121             actualStart = relativeStart < len ? relativeStart : len;
3122         }
3123         actualSkipCount = len - actualStart;
3124     }
3125     // 7. Let insertCount be the number of elements in items.
3126     // 8. If start is not present, then
3127     //     a. Let actualSkipCount be 0.
3128     // 9. Else if skipCount is not present, then
3129     //     a. Let actualSkipCount be len - actualStart.
3130     // 10. Else,
3131     //     a. Let sc be ? ToIntegerOrInfinity(skipCount).
3132     //     b. Let actualSkipCount be the result of clamping sc between 0 and len - actualStart.
3133     if (argc > 1) {
3134         insertCount = argc - 2; // 2:2 means there two arguments before the insert items.
3135         JSTaggedNumber argSkipCount = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 1));
3136         // ReturnIfAbrupt(argSkipCount).
3137         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3138         double skipCount = argSkipCount.GetNumber();
3139         skipCount = skipCount > 0 ? skipCount : 0;
3140         actualSkipCount = skipCount < (len - actualStart) ? skipCount : len - actualStart;
3141     }
3142     // 11. Let newLen be len + insertCount - actualSkipCount.
3143     newLen = len + insertCount - actualSkipCount;
3144     // 12. If newLen > 2^53 - 1, throw a TypeError exception.
3145     if (newLen > base::MAX_SAFE_INTEGER) {
3146         THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
3147     }
3148     if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) {
3149         return JSStableArray::ToSpliced(JSHandle<JSArray>::Cast(thisHandle), argv, argc, actualStart,
3150                                         actualSkipCount, newLen);
3151     }
3152     // 13. Let A be ? ArrayCreate(newLen).
3153     JSHandle<JSTaggedValue> newJsTaggedArray =
3154         JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(newLen)));
3155     // ReturnIfAbrupt(newArray).
3156     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3157     JSHandle<JSObject> newArrayHandle(thread, newJsTaggedArray.GetTaggedValue());
3158     // 14. Let i be 0.
3159     int64_t i = 0;
3160     // 15. Let r be actualStart + actualSkipCount.
3161     int64_t r = actualStart + actualSkipCount;
3162     // 16. Repeat, while i < actualStart,
3163     //     a. Let Pi be ! ToString(��(i)).
3164     //     b. Let iValue be ? Get(O, Pi).
3165     //     c. Perform ! CreateDataPropertyOrThrow(A, Pi, iValue).
3166     //     d. Set i to i + 1.
3167     while (i < actualStart) {
3168         JSHandle<JSTaggedValue> iValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, i);
3169         // ReturnIfAbrupt(iValue).
3170         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3171         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, i, iValue);
3172         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3173         ++i;
3174     }
3175     // 17. For each element E of items, do
3176     //     a. Let Pi be ! ToString(��(i)).
3177     //     b. Perform ! CreateDataPropertyOrThrow(A, Pi, E).
3178     //     c. Set i to i + 1.
3179     JSMutableHandle<JSTaggedValue> pi(thread, JSTaggedValue::Undefined());
3180     for (int64_t pos = 2; pos < argc; ++pos) { // 2:2 means there two arguments before the insert items.
3181         pi.Update(JSTaggedValue(i));
3182         JSHandle<JSTaggedValue> element = GetCallArg(argv, pos);
3183         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, pi, element);
3184         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3185         ++i;
3186     }
3187     // 18. Repeat, while i < newLen,
3188     //     a. Let Pi be ! ToString(��(i)).
3189     //     b. Let from be ! ToString(��(r)).
3190     //     c. Let fromValue be ? Get(O, from).
3191     //     d. Perform ! CreateDataPropertyOrThrow(A, Pi, fromValue).
3192     //     e. Set i to i + 1.
3193     //     f. Set r to r + 1.
3194     JSMutableHandle<JSTaggedValue> from(thread, JSTaggedValue::Undefined());
3195     while (i < newLen) {
3196         pi.Update(JSTaggedValue(i));
3197         from.Update(JSTaggedValue(r));
3198         JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, from);
3199         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3200         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, pi, fromValue);
3201         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3202         ++i;
3203         ++r;
3204     }
3205     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
3206     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
3207     JSTaggedValue::SetProperty(thread, newJsTaggedArray, lengthKey, newLenHandle, true);
3208     // ReturnIfAbrupt(setStatus).
3209     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3210     // 19. Return A.
3211     return newArrayHandle.GetTaggedValue();
3212 }
3213 
3214 // 23.1.3.11 Array.prototype.findLast ( predicate [ , thisArg ] )
FindLast(EcmaRuntimeCallInfo * argv)3215 JSTaggedValue BuiltinsArray::FindLast(EcmaRuntimeCallInfo *argv)
3216 {
3217     ASSERT(argv);
3218     JSThread *thread = argv->GetThread();
3219     BUILTINS_API_TRACE(thread, Array, FindLast);
3220     [[maybe_unused]] EcmaHandleScope handleScope(thread);
3221 
3222     // 1. Let O be ToObject(this value).
3223     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
3224     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
3225     // 2. ReturnIfAbrupt(O).
3226     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3227     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
3228 
3229     // 3. Let len be ToLength(Get(O, "length")).
3230     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
3231     // 4. ReturnIfAbrupt(len).
3232     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3233 
3234     // 5. If IsCallable(predicate) is false, throw a TypeError exception.
3235     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
3236     if (!callbackFnHandle->IsCallable()) {
3237         THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
3238     }
3239 
3240     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
3241     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
3242 
3243     // 7. Let k be (len - 1).
3244     // 8. Repeat, while k >= 0
3245     //   a. Let Pk be ToString(k).
3246     //   b. Let kValue be Get(O, Pk).
3247     //   c. ReturnIfAbrupt(kValue).
3248     //   d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
3249     //   e. ReturnIfAbrupt(testResult).
3250     //   f. If testResult is true, return kValue.
3251     //   g. Decrease k by 1.
3252     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
3253     int64_t k = len - 1;
3254     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
3255     const uint32_t argsLength = 3; // 3: «kValue, k, O»
3256     while (k >= 0) {
3257         JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
3258         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3259         key.Update(JSTaggedValue(k));
3260         EcmaRuntimeCallInfo *info =
3261             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
3262         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3263         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
3264         JSTaggedValue callResult = JSFunction::Call(info);
3265         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3266         if (callResult.ToBoolean()) {
3267             return kValue.GetTaggedValue();
3268         }
3269         k--;
3270     }
3271 
3272     // 9. Return undefined.
3273     return JSTaggedValue::Undefined();
3274 }
3275 
3276 // 23.1.3.12 Array.prototype.findLastIndex ( predicate [ , thisArg ] )
FindLastIndex(EcmaRuntimeCallInfo * argv)3277 JSTaggedValue BuiltinsArray::FindLastIndex(EcmaRuntimeCallInfo *argv)
3278 {
3279     ASSERT(argv);
3280     JSThread *thread = argv->GetThread();
3281     BUILTINS_API_TRACE(thread, Array, FindLastIndex);
3282     [[maybe_unused]] EcmaHandleScope handleScope(thread);
3283 
3284     // 1. Let O be ToObject(this value).
3285     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
3286     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
3287     // 2. ReturnIfAbrupt(O).
3288     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3289     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
3290 
3291     // 3. Let len be ToLength(Get(O, "length")).
3292     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
3293     // 4. ReturnIfAbrupt(len).
3294     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3295 
3296     // 5. If IsCallable(predicate) is false, throw a TypeError exception.
3297     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
3298     if (!callbackFnHandle->IsCallable()) {
3299         THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
3300     }
3301 
3302     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
3303     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
3304 
3305     // 7. Let k be (len - 1).
3306     // 8. Repeat, while k >=0
3307     //   a. Let Pk be ToString(k).
3308     //   b. Let kValue be Get(O, Pk).
3309     //   c. ReturnIfAbrupt(kValue).
3310     //   d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
3311     //   e. ReturnIfAbrupt(testResult).
3312     //   f. If testResult is true, return k.
3313     //   g. Decrease k by 1.
3314     int64_t k = len - 1;
3315     JSTaggedValue callResult = GetTaggedBoolean(true);
3316     if (thisObjVal->IsStableJSArray(thread)) {
3317         callResult =
3318             JSStableArray::HandleFindLastIndexOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k);
3319         if (callResult.ToBoolean()) {
3320             return GetTaggedDouble(k);
3321         }
3322     }
3323     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
3324     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
3325     const uint32_t argsLength = 3; // 3: «kValue, k, O»
3326     while (k >= 0) {
3327         JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
3328         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3329         key.Update(JSTaggedValue(k));
3330         EcmaRuntimeCallInfo *info =
3331             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
3332         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3333         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
3334         callResult = JSFunction::Call(info);
3335         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3336         if (callResult.ToBoolean()) {
3337             return GetTaggedDouble(k);
3338         }
3339         k--;
3340     }
3341 
3342     // 9. Return -1.
3343     return GetTaggedDouble(-1);
3344 }
3345 
3346 // 23.1.3.33 Array.prototype.toReversed ( )
ToReversed(EcmaRuntimeCallInfo * argv)3347 JSTaggedValue BuiltinsArray::ToReversed(EcmaRuntimeCallInfo *argv)
3348 {
3349     ASSERT(argv);
3350     JSThread *thread = argv->GetThread();
3351     BUILTINS_API_TRACE(thread, Array, ToReversed);
3352     [[maybe_unused]] EcmaHandleScope handleScope(thread);
3353 
3354     // 1. Let O be ToObject(this value).
3355     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
3356     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
3357     // ReturnIfAbrupt(O).
3358     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3359     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
3360 
3361     // 2. Let len be ? LengthOfArrayLike(O).
3362     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
3363     // ReturnIfAbrupt(len).
3364     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3365     if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()) {
3366         return JSStableArray::ToReversed(thread, JSHandle<JSArray>::Cast(thisHandle), len);
3367     }
3368     // 3. Let A be ? ArrayCreate(len).
3369     JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue();
3370     // ReturnIfAbrupt(len).
3371     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3372     JSHandle<JSObject> newArrayHandle(thread, newArray);
3373 
3374     // 4. Let k be 0.
3375     // 5. Repeat, while k < len,
3376     //     a. Let from be ! ToString(��(len - k - 1)).
3377     //     b. Let Pk be ! ToString(��(k)).
3378     //     c. Let fromValue be ? Get(O, from).
3379     //     d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue).
3380     //     e. Set k to k + 1.
3381     JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
3382     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
3383     int64_t k = 0;
3384     while (k < len) {
3385         int64_t from = len - k - 1;
3386         fromKey.Update(JSTaggedValue(from));
3387         toKey.Update(JSTaggedValue(k));
3388         JSHandle<JSTaggedValue> fromValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
3389         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3390         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue);
3391         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
3392         k++;
3393     }
3394     // 6. Return A.
3395     return newArrayHandle.GetTaggedValue();
3396 }
3397 }  // namespace panda::ecmascript::builtins
3398