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