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