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