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