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