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