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