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