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().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().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().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(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(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(thisObjHandle) < len)) {
1078 len = ElementAccessor::GetElementsLength(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 auto factory = thread->GetEcmaVM()->GetFactory();
1281 auto context = thread->GetCurrentEcmaContext();
1282 bool noCircular = context->JoinStackPushFastPath(thisHandle);
1283 if (!noCircular) {
1284 return factory->GetEmptyString().GetTaggedValue();
1285 }
1286
1287 return JSStableArray::Join(thisHandle, argv);
1288 }
1289
1290 // 22.1.3.13 Array.prototype.keys ( )
Keys(EcmaRuntimeCallInfo * argv)1291 JSTaggedValue BuiltinsSharedArray::Keys(EcmaRuntimeCallInfo *argv)
1292 {
1293 ASSERT(argv);
1294 JSThread *thread = argv->GetThread();
1295 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Keys);
1296 // thisHandle variable declare this Macro
1297 ARRAY_CHECK_SHARED_ARRAY("The keys method cannot be bound.")
1298
1299 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1300 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1301 auto opResult = BuiltinsArray::Keys(argv);
1302 return opResult;
1303 }
1304
1305 // 22.1.3.15 Array.prototype.map ( callbackfn [ , thisArg ] )
Map(EcmaRuntimeCallInfo * argv)1306 JSTaggedValue BuiltinsSharedArray::Map(EcmaRuntimeCallInfo *argv)
1307 {
1308 ASSERT(argv);
1309 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Map);
1310 JSThread *thread = argv->GetThread();
1311 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1312
1313 // 1. Let O be ToObject(this value).
1314 // thisHandle variable declare this Macro
1315 ARRAY_CHECK_SHARED_ARRAY("The map method cannot be bound.")
1316
1317 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1318 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1319 // 2. ReturnIfAbrupt(O).
1320 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1321
1322 // 3. Let len be ToLength(Get(O, "length")).
1323 int64_t rawLen = ArrayHelper::GetArrayLength(thread, thisHandle);
1324 // 4. ReturnIfAbrupt(len).
1325 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1326
1327 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
1328 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1329 if (!callbackFnHandle->IsCallable()) {
1330 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
1331 }
1332
1333 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
1334 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
1335
1336 // 7. Let A be ArraySpeciesCreate(O, len).
1337 JSTaggedValue newArray =
1338 JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(rawLen)));
1339 // 8. ReturnIfAbrupt(A).
1340 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1341 if (!newArray.IsECMAObject()) {
1342 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception());
1343 }
1344 JSHandle<JSObject> newArrayHandle(thread, newArray);
1345
1346 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1347 JSHandle<TaggedArray> eleArray = factory->NewTaggedArray(rawLen, JSTaggedValue::Undefined(),
1348 MemSpaceType::SHARED_OLD_SPACE);
1349
1350 // 9. Let k be 0.
1351 // 10. Repeat, while k < len
1352 // a. Let Pk be ToString(k).
1353 // b. Let kPresent be HasProperty(O, Pk).
1354 // c. ReturnIfAbrupt(kPresent).
1355 // d. If kPresent is true, then
1356 // i. Let kValue be Get(O, Pk).
1357 // ii. ReturnIfAbrupt(kValue).
1358 // iii. Let mappedValue be Call(callbackfn, T, «kValue, k, O»).
1359 // iv. ReturnIfAbrupt(mappedValue).
1360 // v. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue).
1361 // vi. ReturnIfAbrupt(status).
1362 // e. Increase k by 1.
1363 uint32_t k = 0;
1364 uint32_t len = static_cast<uint32_t>(rawLen);
1365 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1366 JSMutableHandle<JSTaggedValue> mapResultHandle(thread, JSTaggedValue::Undefined());
1367 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1368 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
1369 const uint32_t argsLength = 3; // 3: «kValue, k, O»
1370 while (k < len) {
1371 kValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
1372 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1373 key.Update(JSTaggedValue(k));
1374 EcmaRuntimeCallInfo *info =
1375 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
1376 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1377 ASSERT(info != nullptr);
1378 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
1379 JSTaggedValue mapResult = JSFunction::Call(info);
1380 if (!mapResult.IsSharedType()) {
1381 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1382 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1383 }
1384 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1385 mapResultHandle.Update(mapResult);
1386 eleArray->Set(thread, k, mapResultHandle);
1387 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1388 k++;
1389 }
1390 newArrayHandle->SetElements(thread, eleArray);
1391
1392 // 11. Return A.
1393 return newArrayHandle.GetTaggedValue();
1394 }
1395
1396 // 22.1.3.16 Array.prototype.pop ( )
Pop(EcmaRuntimeCallInfo * argv)1397 JSTaggedValue BuiltinsSharedArray::Pop(EcmaRuntimeCallInfo *argv)
1398 {
1399 ASSERT(argv);
1400 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Pop);
1401
1402 JSThread *thread = argv->GetThread();
1403 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1404
1405 // 1. Let O be ToObject(this value).
1406 // thisHandle variable declare this Macro
1407 ARRAY_CHECK_SHARED_ARRAY("The pop method cannot be bound.")
1408
1409 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1410 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1411 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1412
1413 JSTaggedValue opResult = PopInner(argv, thisHandle, thisObjHandle);
1414 return opResult;
1415 }
1416
PopInner(EcmaRuntimeCallInfo * argv,JSHandle<JSTaggedValue> & thisHandle,JSHandle<JSObject> & thisObjHandle)1417 JSTaggedValue BuiltinsSharedArray::PopInner(EcmaRuntimeCallInfo *argv, JSHandle<JSTaggedValue> &thisHandle,
1418 JSHandle<JSObject> &thisObjHandle)
1419 {
1420 JSThread *thread = argv->GetThread();
1421 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1422
1423 // 2. ReturnIfAbrupt(O).
1424 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1425
1426 // 3. Let len be ToLength(Get(O, "length")).
1427 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
1428 // 4. ReturnIfAbrupt(len).
1429 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1430 // 5. If len is zero,
1431 // a. Let setStatus be Set(O, "length", 0, true).
1432 // b. ReturnIfAbrupt(setStatus).
1433 // c. Return undefined.
1434 if (len == 0) {
1435 JSHandle<JSTaggedValue> lengthValue(thread, JSTaggedValue(0));
1436 JSSharedArray::LengthSetter(thread, thisObjHandle, lengthValue, true);
1437 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1438 return JSTaggedValue::Undefined();
1439 }
1440
1441 // 6. Else len > 0,
1442 // a. Let newLen be len–1.
1443 // b. Let indx be ToString(newLen).
1444 // c. Let element be Get(O, indx).
1445 // d. ReturnIfAbrupt(element).
1446 // e. Let deleteStatus be DeletePropertyOrThrow(O, indx).
1447 // f. ReturnIfAbrupt(deleteStatus).
1448 // g. Let setStatus be Set(O, "length", newLen, true).
1449 // h. ReturnIfAbrupt(setStatus).
1450 // i. Return element.
1451 int64_t newLen = len - 1;
1452 JSHandle<JSTaggedValue> element(thread, ElementAccessor::Get(thread, thisObjHandle, newLen));
1453 // BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, newLen));
1454 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1455 uint32_t capacity = ElementAccessor::GetElementsLength(thisObjHandle);
1456 if (TaggedArray::ShouldTrim(capacity, newLen)) {
1457 TaggedArray *elements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
1458 elements->Trim(thread, newLen);
1459 }
1460
1461 JSSharedArray::Cast(*thisObjHandle)->SetArrayLength(thread, newLen);
1462 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1463
1464 return element.GetTaggedValue();
1465 }
1466
1467 // 22.1.3.17 Array.prototype.push ( ...items )
Push(EcmaRuntimeCallInfo * argv)1468 JSTaggedValue BuiltinsSharedArray::Push(EcmaRuntimeCallInfo *argv)
1469 {
1470 ASSERT(argv);
1471 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Push);
1472 JSThread *thread = argv->GetThread();
1473 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1474
1475 // thisHandle variable declare this Macro
1476 ARRAY_CHECK_SHARED_ARRAY("The push method cannot be bound.")
1477
1478 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1479 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1480 // 6. Let argCount be the number of elements in items.
1481 uint32_t argc = argv->GetArgsNumber();
1482
1483 // 1. Let O be ToObject(this value).
1484 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1485 // 2. ReturnIfAbrupt(O).
1486 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1487
1488 // 3. Let len be ToLength(Get(O, "length")).
1489 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
1490 // 4. ReturnIfAbrupt(len).
1491 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1492 // 7. If len + argCount > 253-1, throw a TypeError exception.
1493 if ((len + static_cast<int64_t>(argc)) > base::MAX_SAFE_INTEGER) {
1494 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1495 }
1496
1497 uint32_t newLength = argc + static_cast<uint32_t>(len);
1498 TaggedArray *element = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
1499 if (newLength > ElementAccessor::GetElementsLength(thisObjHandle)) {
1500 element = *JSObject::GrowElementsCapacity(thread, thisObjHandle, newLength, true);
1501 }
1502
1503 // 8. Repeat, while items is not empty
1504 // a. Remove the first element from items and let E be the value of the element.
1505 // b. Let setStatus be Set(O, ToString(len), E, true).
1506 // c. ReturnIfAbrupt(setStatus).
1507 // d. Let len be len+1.
1508 uint32_t k = 0;
1509 while (k < argc) {
1510 JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k);
1511 if (!kValue->IsSharedType()) {
1512 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1513 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1514 }
1515 element->Set(thread, len, kValue);
1516 k++;
1517 len++;
1518 }
1519
1520 // 9. Let setStatus be Set(O, "length", len, true).
1521 JSSharedArray::Cast(*thisObjHandle)->SetArrayLength(thread, len);
1522 // 10. ReturnIfAbrupt(setStatus).
1523 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1524
1525 // 11. Return len.
1526 return GetTaggedDouble(len);
1527 }
1528
ReduceUnStableJSArray(JSThread * thread,JSHandle<JSTaggedValue> & thisHandle,JSHandle<JSObject> & thisObjHandle,int64_t k,int64_t len,JSMutableHandle<JSTaggedValue> & accumulator,JSHandle<JSTaggedValue> & callbackFnHandle)1529 JSTaggedValue BuiltinsSharedArray::ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle,
1530 JSHandle<JSObject> &thisObjHandle, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator,
1531 JSHandle<JSTaggedValue> &callbackFnHandle)
1532 {
1533 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1534 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
1535 JSTaggedValue callResult = JSTaggedValue::Undefined();
1536 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1537 const int32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
1538 while (k < len) {
1539 kValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
1540 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1541 key.Update(JSTaggedValue(k));
1542 EcmaRuntimeCallInfo *info =
1543 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, undefined, undefined, argsLength);
1544 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1545 ASSERT(info != nullptr);
1546 info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(),
1547 key.GetTaggedValue(), thisHandle.GetTaggedValue());
1548 callResult = JSFunction::Call(info);
1549 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1550 accumulator.Update(callResult);
1551 k++;
1552 }
1553
1554 return accumulator.GetTaggedValue();
1555 }
1556
1557 // 22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] )
Reduce(EcmaRuntimeCallInfo * argv)1558 JSTaggedValue BuiltinsSharedArray::Reduce(EcmaRuntimeCallInfo *argv)
1559 {
1560 ASSERT(argv);
1561 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Reduce);
1562 JSThread *thread = argv->GetThread();
1563 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1564
1565 uint32_t argc = argv->GetArgsNumber();
1566 // 1. Let O be ToObject(this value).
1567 // thisHandle variable declare this Macro
1568 ARRAY_CHECK_SHARED_ARRAY("The reduce method cannot be bound.")
1569
1570 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1571 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1572 // 2. ReturnIfAbrupt(O).
1573 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1574
1575 // 3. Let len be ToLength(Get(O, "length")).
1576 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
1577 // 4. ReturnIfAbrupt(len).
1578 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1579
1580 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
1581 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1582 if (!callbackFnHandle->IsCallable()) {
1583 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
1584 }
1585
1586 // 6. If len is 0 and initialValue is not present, throw a TypeError exception.
1587 const int32_t argcLimitLength = 2; // argc limit length of the number parameters
1588 if (len == 0 && argc < argcLimitLength) { // 2:2 means the number of parameters
1589 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1590 }
1591
1592 // 7. Let k be len-1.
1593 int64_t k = 0;
1594 // 8. If initialValue is present, then
1595 // a. Set accumulator to initialValue.
1596 // 9. Else initialValue is not present,
1597 // a. Get last element initial accumulator
1598 JSMutableHandle<JSTaggedValue> accumulator(thread, JSTaggedValue::Undefined());
1599 if (argc >= argcLimitLength) { // 2:2 means the number of parameters
1600 accumulator.Update(GetCallArg(argv, 1).GetTaggedValue());
1601 } else if (len > 0) {
1602 accumulator.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
1603 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1604 k++;
1605 }
1606
1607 auto opResult = ReduceUnStableJSArray(thread, thisHandle, thisObjHandle, k, len, accumulator, callbackFnHandle);
1608 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1609
1610 return opResult;
1611 }
1612
1613 // 22.1.3.21 Array.prototype.shift ( )
Shift(EcmaRuntimeCallInfo * argv)1614 JSTaggedValue BuiltinsSharedArray::Shift(EcmaRuntimeCallInfo *argv)
1615 {
1616 ASSERT(argv);
1617 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Shift);
1618 JSThread *thread = argv->GetThread();
1619 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1620
1621 // 1. Let O be ToObject(this value).
1622 // thisHandle variable declare this Macro
1623 ARRAY_CHECK_SHARED_ARRAY("The shift method cannot be bound.")
1624
1625 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1626 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1627 // 2. ReturnIfAbrupt(O).
1628 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1629
1630 // 3. Let len be ToLength(Get(O, "length")).
1631 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
1632 // 4. ReturnIfAbrupt(len).
1633 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1634 // 5. If len is zero, then
1635 // a. Let setStatus be Set(O, "length", 0, true).
1636 // b. ReturnIfAbrupt(setStatus).
1637 // c. Return undefined.
1638 if (len == 0) {
1639 JSHandle<JSTaggedValue> zeroLenHandle(thread, JSTaggedValue(len));
1640 JSSharedArray::LengthSetter(thread, thisObjHandle, zeroLenHandle, false);
1641 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1642 return JSTaggedValue::Undefined();
1643 }
1644
1645 // 6. Let first be Get(O, "0").
1646 JSHandle<JSTaggedValue> firstValue(thread, BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, 0));
1647
1648 // 7. ReturnIfAbrupt(first).
1649 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1650
1651 // 8. Let k be 1.
1652 // 9. Repeat, while k < len
1653 // a. Let from be ToString(k).
1654 // b. Let to be ToString(k–1).
1655 // c. Let fromPresent be HasProperty(O, from).
1656 // d. ReturnIfAbrupt(fromPresent).
1657 // e. If fromPresent is true, then
1658 // i. Let fromVal be Get(O, from).
1659 // ii. ReturnIfAbrupt(fromVal).
1660 // iii. Let setStatus be Set(O, to, fromVal, true).
1661 // iv. ReturnIfAbrupt(setStatus).
1662 // f. Else fromPresent is false,
1663 // i. Let deleteStatus be DeletePropertyOrThrow(O, to).
1664 // ii. ReturnIfAbrupt(deleteStatus).
1665 // g. Increase k by 1.
1666 TaggedArray *element = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
1667 int64_t newLen = len - 1;
1668 element->Copy<true, true>(thread, 0, 1, element, newLen);
1669 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1670
1671 uint32_t capacity = ElementAccessor::GetElementsLength(thisObjHandle);
1672 if (TaggedArray::ShouldTrim(capacity, newLen)) {
1673 TaggedArray *elements = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
1674 elements->Trim(thread, newLen);
1675 }
1676
1677 // 12. Let setStatus be Set(O, "length", len–1, true).
1678 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
1679 JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
1680 // 13. ReturnIfAbrupt(setStatus).
1681 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1682
1683 // 14. Return first.
1684 return firstValue.GetTaggedValue();
1685 }
1686
1687 // 22.1.3.22 Array.prototype.slice (start, end)
Slice(EcmaRuntimeCallInfo * argv)1688 JSTaggedValue BuiltinsSharedArray::Slice(EcmaRuntimeCallInfo *argv)
1689 {
1690 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Slice);
1691 ASSERT(argv);
1692 JSThread *thread = argv->GetThread();
1693 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1694
1695 // 1. Let O be ToObject(this value).
1696 // thisHandle variable declare this Macro
1697 ARRAY_CHECK_SHARED_ARRAY("The slice method cannot be bound.")
1698
1699 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1700 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1701 // 2. ReturnIfAbrupt(O).
1702 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1703
1704 // 3. Let len be ToLength(Get(O, "length")).
1705 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
1706 // 4. ReturnIfAbrupt(len).
1707 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1708
1709 // 5. Let relativeStart be ToInteger(start).
1710 int64_t start = GetNumberArgVal(thread, argv, 0, len, 0);
1711 // 6. ReturnIfAbrupt(relativeStart).
1712 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1713
1714 // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
1715 // 9. ReturnIfAbrupt(relativeEnd).
1716 // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
1717 int64_t final = GetNumberArgVal(thread, argv, 1, len, len);
1718 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1719
1720 // 11. Let count be max(final – k, 0).
1721 int64_t count = final > start ? (final - start) : 0;
1722
1723 // 12. Let A be ArraySpeciesCreate(O, count).
1724 JSTaggedValue newArray =
1725 JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(count)));
1726 // 13. ReturnIfAbrupt(A).
1727 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1728 if (count == 0) {
1729 return newArray;
1730 }
1731 JSHandle<JSObject> newArrayHandle(thread, newArray);
1732 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1733 JSHandle<TaggedArray> eleArray = factory->NewTaggedArray(count, JSTaggedValue::Undefined(),
1734 MemSpaceType::SHARED_OLD_SPACE);
1735 // 14. Let n be 0.
1736 // 15. Repeat, while start < final
1737 // a. Let Pk be ToString(start).
1738 // b. Let kPresent be HasProperty(O, Pk).
1739 // c. ReturnIfAbrupt(kPresent).
1740 // d. If kPresent is true, then
1741 // i. Let kValue be Get(O, Pk).
1742 // ii. ReturnIfAbrupt(kValue).
1743 // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue ).
1744 // iv. ReturnIfAbrupt(status).
1745 // e. Increase start by 1.
1746 // f. Increase n by 1.
1747 int64_t n = 0;
1748 JSMutableHandle<JSTaggedValue> kValueHandle(thread, JSTaggedValue::Undefined());
1749 while (start < final) {
1750 kValueHandle.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, start));
1751 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1752 eleArray->Set(thread, n, kValueHandle);
1753 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1754 start++;
1755 n++;
1756 }
1757
1758 newArrayHandle->SetElements(thread, eleArray);
1759 // 16. Let setStatus be Set(A, "length", n, true).
1760 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(n));
1761 JSSharedArray::LengthSetter(thread, newArrayHandle, newLenHandle, true);
1762 // 17. ReturnIfAbrupt(setStatus).
1763 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1764
1765 // 18. Return A.
1766 return newArrayHandle.GetTaggedValue();
1767 }
1768
1769 // 22.1.3.24 Array.prototype.sort (comparefn)
Sort(EcmaRuntimeCallInfo * argv)1770 JSTaggedValue BuiltinsSharedArray::Sort(EcmaRuntimeCallInfo *argv)
1771 {
1772 ASSERT(argv);
1773 JSThread *thread = argv->GetThread();
1774 BUILTINS_API_TRACE(thread, SharedArray, Sort);
1775 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1776
1777 // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
1778 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1779 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
1780 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
1781 }
1782
1783 // 2. Let obj be ToObject(this value).
1784 // thisHandle variable declare this Macro
1785 ARRAY_CHECK_SHARED_ARRAY("The sort method cannot be bound.")
1786
1787 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1788 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1789 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1790
1791 JSHandle<TaggedArray> elements(thread, thisObjHandle->GetElements());
1792 base::TimSort::Sort(thread, elements, callbackFnHandle);
1793 return thisObjHandle.GetTaggedValue();
1794 }
1795
1796 // 22.1.3.25 Array.prototype.splice (start, deleteCount , ...items )
1797 // NOLINTNEXTLINE(readability-function-size)
Splice(EcmaRuntimeCallInfo * argv)1798 JSTaggedValue BuiltinsSharedArray::Splice(EcmaRuntimeCallInfo *argv)
1799 {
1800 ASSERT(argv);
1801 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Splice);
1802 JSThread *thread = argv->GetThread();
1803 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1804 uint32_t argc = argv->GetArgsNumber();
1805 // 1. Let O be ToObject(this value).
1806 // thisHandle variable declare this Macro
1807 ARRAY_CHECK_SHARED_ARRAY("The splice method cannot be bound.")
1808
1809 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1810 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(
1811 thread, thisHandle);
1812 // 2. ReturnIfAbrupt(O).
1813 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1814 // 3. Let len be ToLength(Get(O, "length")).
1815 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
1816 // 4. ReturnIfAbrupt(len).
1817 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1818 // 5. Let relativeStart be ToInteger(start).
1819 int64_t start = 0;
1820 int64_t insertCount = 0;
1821 int64_t actualDeleteCount = 0;
1822 if (argc > 0) {
1823 // 6. ReturnIfAbrupt(relativeStart).
1824 start = GetNumberArgVal(thread, argv, 0, len, 0);
1825 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1826 actualDeleteCount = len - start;
1827 }
1828 // 8. If the number of actual arguments is 0, then
1829 // a. Let insertCount be 0.
1830 // b. Let actualDeleteCount be 0.
1831 // 9. Else if the number of actual arguments is 1, then
1832 // a. Let insertCount be 0.
1833 // b. Let actualDeleteCount be len – actualStart.
1834 // 10. Else,
1835 // a. Let insertCount be the number of actual arguments minus 2.
1836 // b. Let dc be ToInteger(deleteCount).
1837 // c. ReturnIfAbrupt(dc).
1838 // d. Let actualDeleteCount be min(max(dc,0), len – actualStart).
1839 if (argc > 1) {
1840 insertCount = argc - 2; // 2:2 means there are two arguments before the insert items.
1841 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
1842 JSTaggedNumber argDeleteCount = JSTaggedValue::ToInteger(thread, msg1);
1843 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1844 double deleteCount = argDeleteCount.GetNumber();
1845 deleteCount = deleteCount > 0 ? deleteCount : 0;
1846 actualDeleteCount = deleteCount < (len - start) ? deleteCount : len - start;
1847 }
1848 // 11. If len+insertCount−actualDeleteCount > 253-1, throw a TypeError exception.
1849 if (len + insertCount - actualDeleteCount > base::MAX_SAFE_INTEGER) {
1850 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1851 }
1852 // 12. Let A be ArraySpeciesCreate(O, actualDeleteCount).
1853 JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(
1854 thread, thisObjHandle, JSTaggedNumber(static_cast<double>(actualDeleteCount)));
1855 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1856 JSHandle<JSObject> newArrayHandle(thread, newArray);
1857
1858 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1859 JSHandle<TaggedArray> DelArrEle = factory->NewTaggedArray(actualDeleteCount, JSTaggedValue::Undefined(),
1860 MemSpaceType::SHARED_OLD_SPACE);
1861 TaggedArray *oldElement = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
1862 // 14. Let k be 0.
1863 // 15. Repeat, while k < actualDeleteCount
1864 // a. Let from be ToString(actualStart+k).
1865 // b. Let fromPresent be HasProperty(O, from).
1866 // d. If fromPresent is true, then
1867 // i. Let fromValue be Get(O, from).
1868 // iii. Let status be CreateDataPropertyOrThrow(A, ToString(k), fromValue).
1869 // e. Increase k by 1.
1870 DelArrEle->Copy(thread, 0, start, oldElement, actualDeleteCount);
1871 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1872
1873 newArrayHandle->SetElements(thread, DelArrEle);
1874 // 16. Let setStatus be Set(A, "length", actualDeleteCount, true).
1875 JSHandle<JSTaggedValue> deleteCountHandle(thread, JSTaggedValue(actualDeleteCount));
1876 JSSharedArray::LengthSetter(thread, newArrayHandle, deleteCountHandle, true);
1877 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1878
1879 int64_t newLen = len - actualDeleteCount + insertCount;
1880 JSHandle<TaggedArray> eleArray = factory->NewTaggedArray(newLen, JSTaggedValue::Undefined(),
1881 MemSpaceType::SHARED_OLD_SPACE);
1882 if (start > 0) {
1883 eleArray->Copy(thread, 0, 0, oldElement, start);
1884 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1885 }
1886
1887 eleArray->Copy(thread, start + insertCount, start + actualDeleteCount, oldElement,
1888 len - actualDeleteCount - start);
1889 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1890
1891 // 23. Repeat, while items is not empty
1892 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1893 for (uint32_t i = 2; i < argc; i++) {
1894 JSHandle<JSTaggedValue> itemValue = GetCallArg(argv, i);
1895 if (!itemValue->IsSharedType()) {
1896 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1897 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1898 }
1899 eleArray->Set(thread, start, itemValue);
1900 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1901 start++;
1902 }
1903
1904 thisObjHandle->SetElements(thread, eleArray);
1905 // 24. Let setStatus be Set(O, "length", len – actualDeleteCount + itemCount, true).
1906 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
1907 JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
1908 // 25. ReturnIfAbrupt(setStatus).
1909 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1910 // 26. Return A.
1911 return newArrayHandle.GetTaggedValue();
1912 }
1913
1914 // 22.1.3.27 Array.prototype.toString ( )
ToString(EcmaRuntimeCallInfo * argv)1915 JSTaggedValue BuiltinsSharedArray::ToString(EcmaRuntimeCallInfo *argv)
1916 {
1917 ASSERT(argv);
1918 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ToString);
1919 JSThread *thread = argv->GetThread();
1920 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1921 auto ecmaVm = thread->GetEcmaVM();
1922
1923 // 1. Let array be ToObject(this value).
1924 // thisHandle variable declare this Macro
1925 ARRAY_CHECK_SHARED_ARRAY("The toString method cannot be bound.")
1926
1927 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1928 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1929 // 2. ReturnIfAbrupt(array).
1930 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1931 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1932
1933 // 3. Let func be Get(array, "join").
1934 JSHandle<JSTaggedValue> joinKey = thread->GlobalConstants()->GetHandledJoinString();
1935 JSHandle<JSTaggedValue> callbackFnHandle = JSTaggedValue::GetProperty(thread, thisObjVal, joinKey).GetValue();
1936
1937 // 4. ReturnIfAbrupt(func).
1938 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1939
1940 // 5. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString% (19.1.3.6).
1941 if (!callbackFnHandle->IsCallable()) {
1942 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
1943 JSHandle<JSTaggedValue> objectPrototype = env->GetObjectFunctionPrototype();
1944 JSHandle<JSTaggedValue> toStringKey = thread->GlobalConstants()->GetHandledToStringString();
1945 callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue();
1946 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1947 }
1948 const uint32_t argsLength = argv->GetArgsNumber();
1949 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1950 EcmaRuntimeCallInfo *info =
1951 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength);
1952 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1953 ASSERT(info != nullptr);
1954 info->SetCallArg(argsLength, 0, argv, 0);
1955 auto opResult = JSFunction::Call(info);
1956 return opResult;
1957 }
1958
1959 // Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )
ToLocaleString(EcmaRuntimeCallInfo * argv)1960 JSTaggedValue BuiltinsSharedArray::ToLocaleString(EcmaRuntimeCallInfo *argv)
1961 {
1962 ASSERT(argv);
1963 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ToLocaleString);
1964 JSThread *thread = argv->GetThread();
1965 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1966
1967 auto ecmaVm = thread->GetEcmaVM();
1968 ObjectFactory *factory = ecmaVm->GetFactory();
1969
1970 ARRAY_CHECK_SHARED_ARRAY("The ToLocaleString method cannot be bound.")
1971 // 1. Let O be ToObject(this value).
1972 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1973 // add this to join stack to avoid circular call
1974 auto context = thread->GetCurrentEcmaContext();
1975 bool noCircular = context->JoinStackPushFastPath(thisHandle);
1976 if (!noCircular) {
1977 return factory->GetEmptyString().GetTaggedValue();
1978 }
1979 // 2. ReturnIfAbrupt(O).
1980 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
1981 // 3. Let len be ToLength(Get(O, "length")).
1982 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
1983 // 4. ReturnIfAbrupt(len).
1984 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
1985 // 6. If len is zero, return the empty String.
1986 if (len == 0) {
1987 // pop this from join stack
1988 context->JoinStackPopFastPath(thisHandle);
1989 return GetTaggedString(thread, "");
1990 }
1991
1992 return ToLocaleStringInternalHandle(argv, thread, context, factory, thisHandle, len);
1993 }
1994
ToLocaleStringInternalHandle(EcmaRuntimeCallInfo * argv,JSThread * thread,EcmaContext * context,ObjectFactory * factory,const JSHandle<JSTaggedValue> & thisHandle,int64_t len)1995 JSTaggedValue BuiltinsSharedArray::ToLocaleStringInternalHandle(EcmaRuntimeCallInfo *argv, JSThread *thread,
1996 EcmaContext *context, ObjectFactory *factory, const JSHandle<JSTaggedValue> &thisHandle, int64_t len)
1997 {
1998 JSHandle<JSObject> thisObjHandle(thread, JSObject::Cast(thisHandle.GetTaggedValue()));
1999 // Inject locales and options argument into a taggedArray
2000 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
2001 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
2002 // 7. Let firstElement be Get(array, "0").
2003 // 8. ReturnIfAbrupt(firstElement).
2004 // 9. If firstElement is undefined or null, then
2005 // a. Let R be the empty String.
2006 // 10. Else
2007 // a. Let R be ToString(Invoke(firstElement, "toLocaleString")).
2008 // b. ReturnIfAbrupt(R).
2009 // 11. Let k be 1.
2010 // 12. Repeat, while k < len
2011 // a. Let S be a String value produced by concatenating R and separator.
2012 // b. Let nextElement be Get(array, ToString(k)).
2013 // c. ReturnIfAbrupt(nextElement).
2014 // d. If nextElement is undefined or null, then
2015 // i. Let R be the empty String.
2016 // e. Else
2017 // i. Let R be ToString(Invoke(nextElement, "toLocaleString")).
2018 // ii. ReturnIfAbrupt(R).
2019 // f. Let R be a String value produced by concatenating S and R.
2020 // g. Increase k by 1.
2021 CString concatStr;
2022 auto globalConst = thread->GlobalConstants();
2023 JSHandle<JSTaggedValue> key = globalConst->GetHandledToLocaleStringString();
2024 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
2025 JSMutableHandle<JSTaggedValue> nextValue(thread, JSTaggedValue::Undefined());
2026 JSMutableHandle<JSTaggedValue> nextHandle(thread, JSTaggedValue::Undefined());
2027 JSTaggedValue next = globalConst->GetEmptyString();
2028 for (int64_t k = 0; k < len; k++) {
2029 nextValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2030 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
2031 if (!nextValue->IsUndefined() && !nextValue->IsNull()) {
2032 // 2: two args
2033 EcmaRuntimeCallInfo *info =
2034 EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, nextValue, undefined, 2);
2035 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
2036 ASSERT(info != nullptr);
2037 info->SetCallArg(locales.GetTaggedValue(), options.GetTaggedValue());
2038 JSTaggedValue callResult = JSFunction::Invoke(info, key);
2039 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
2040 next = callResult;
2041 } else {
2042 next = globalConst->GetEmptyString();
2043 }
2044 nextHandle.Update(next);
2045 JSHandle<EcmaString> nextStringHandle = JSTaggedValue::ToString(thread, nextHandle);
2046 RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle);
2047 CString nextString = ConvertToString(*nextStringHandle);
2048 if (k > 0) {
2049 concatStr += STRING_SEPERATOR;
2050 concatStr += nextString;
2051 continue;
2052 }
2053 concatStr += nextString;
2054 }
2055
2056 // pop this from join stack
2057 context->JoinStackPopFastPath(thisHandle);
2058 // 13. Return R.
2059 return factory->NewFromUtf8(concatStr).GetTaggedValue();
2060 }
2061
2062 // 22.1.3.28 Array.prototype.unshift ( ...items )
Unshift(EcmaRuntimeCallInfo * argv)2063 JSTaggedValue BuiltinsSharedArray::Unshift(EcmaRuntimeCallInfo *argv)
2064 {
2065 ASSERT(argv);
2066 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Unshift);
2067 JSThread *thread = argv->GetThread();
2068 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2069
2070 // 5. Let argCount be the number of actual arguments.
2071 int64_t argc = argv->GetArgsNumber();
2072
2073 // 1. Let O be ToObject(this value).
2074 // thisHandle variable declare this Macro
2075 ARRAY_CHECK_SHARED_ARRAY("The unshift method cannot be bound.")
2076
2077 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2078 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2079 // 2. ReturnIfAbrupt(O).
2080 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2081
2082 // 3. Let len be ToLength(Get(O, "length")).
2083 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
2084 // 4. ReturnIfAbrupt(len).
2085 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2086
2087 int64_t newLen = len + argc;
2088 if (argc > 0) {
2089 if (newLen > base::MAX_SAFE_INTEGER) {
2090 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
2091 }
2092
2093 TaggedArray *element = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
2094 if (newLen > ElementAccessor::GetElementsLength(thisObjHandle)) {
2095 element = *JSObject::GrowElementsCapacity(thread, thisObjHandle, newLen, true);
2096 }
2097 element->Copy<true, true>(thread, argc, 0, element, len);
2098 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2099
2100 int64_t j = 0;
2101 JSMutableHandle<JSTaggedValue> toValue(thread, JSTaggedValue::Undefined());
2102 while (j < argc) {
2103 toValue.Update(GetCallArg(argv, j));
2104 if (!toValue->IsSharedType()) {
2105 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
2106 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2107 }
2108 element->Set(thread, j, toValue);
2109 j++;
2110 }
2111 }
2112
2113 // 7. Let setStatus be Set(O, "length", len+argCount, true).
2114 JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
2115 JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
2116 // 8. ReturnIfAbrupt(setStatus).
2117 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2118
2119 // 9. Return len+argCount.
2120 return GetTaggedDouble(newLen);
2121 }
2122
2123 // 22.1.3.29 Array.prototype.values ( )
Values(EcmaRuntimeCallInfo * argv)2124 JSTaggedValue BuiltinsSharedArray::Values(EcmaRuntimeCallInfo *argv)
2125 {
2126 ASSERT(argv);
2127 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Values);
2128 JSThread *thread = argv->GetThread();
2129 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2130
2131 // thisHandle variable declare this Macro
2132 ARRAY_CHECK_SHARED_ARRAY("The values method cannot be bound.")
2133
2134 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2135 // 1. Let O be ToObject(this value).
2136 // 2. ReturnIfAbrupt(O).
2137 JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv));
2138 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2139 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2140 // 3. Return CreateArrayIterator(O, "value").
2141 JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE));
2142 return iter.GetTaggedValue();
2143 }
2144 // 22.1.3.31 Array.prototype [ @@unscopables ]
Unscopables(EcmaRuntimeCallInfo * argv)2145 JSTaggedValue BuiltinsSharedArray::Unscopables(EcmaRuntimeCallInfo *argv)
2146 {
2147 JSThread *thread = argv->GetThread();
2148 BUILTINS_API_TRACE(thread, SharedArray, Unscopables);
2149 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2150 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2151 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2152
2153 JSHandle<JSObject> unscopableList = factory->CreateNullJSObject();
2154
2155 JSHandle<JSTaggedValue> trueVal(thread, JSTaggedValue::True());
2156
2157 JSHandle<JSTaggedValue> atKey((factory->NewFromASCII("at")));
2158 JSObject::CreateDataProperty(thread, unscopableList, atKey, trueVal);
2159
2160 JSHandle<JSTaggedValue> copyWithKey = globalConst->GetHandledCopyWithinString();
2161 JSObject::CreateDataProperty(thread, unscopableList, copyWithKey, trueVal);
2162
2163 JSHandle<JSTaggedValue> entriesKey = globalConst->GetHandledEntriesString();
2164 JSObject::CreateDataProperty(thread, unscopableList, entriesKey, trueVal);
2165
2166 JSHandle<JSTaggedValue> fillKey = globalConst->GetHandledFillString();
2167 JSObject::CreateDataProperty(thread, unscopableList, fillKey, trueVal);
2168
2169 JSHandle<JSTaggedValue> findKey = globalConst->GetHandledFindString();
2170 JSObject::CreateDataProperty(thread, unscopableList, findKey, trueVal);
2171
2172 JSHandle<JSTaggedValue> findIndexKey = globalConst->GetHandledFindIndexString();
2173 JSObject::CreateDataProperty(thread, unscopableList, findIndexKey, trueVal);
2174
2175 JSHandle<JSTaggedValue> findLastKey((factory->NewFromASCII("findLast")));
2176 JSObject::CreateDataProperty(thread, unscopableList, findLastKey, trueVal);
2177
2178 JSHandle<JSTaggedValue> findLastIndexKey((factory->NewFromASCII("findLastIndex")));
2179 JSObject::CreateDataProperty(thread, unscopableList, findLastIndexKey, trueVal);
2180
2181 JSHandle<JSTaggedValue> flatKey = globalConst->GetHandledFlatString();
2182 JSObject::CreateDataProperty(thread, unscopableList, flatKey, trueVal);
2183
2184 JSHandle<JSTaggedValue> flatMapKey = globalConst->GetHandledFlatMapString();
2185 JSObject::CreateDataProperty(thread, unscopableList, flatMapKey, trueVal);
2186
2187 JSHandle<JSTaggedValue> includesKey = globalConst->GetHandledIncludesString();
2188 JSObject::CreateDataProperty(thread, unscopableList, includesKey, trueVal);
2189
2190 JSHandle<JSTaggedValue> keysKey = globalConst->GetHandledKeysString();
2191 JSObject::CreateDataProperty(thread, unscopableList, keysKey, trueVal);
2192
2193 JSHandle<JSTaggedValue> valuesKey = globalConst->GetHandledValuesString();
2194 JSObject::CreateDataProperty(thread, unscopableList, valuesKey, trueVal);
2195
2196 JSHandle<JSTaggedValue> toReversedKey((factory->NewFromASCII("toReversed")));
2197 JSObject::CreateDataProperty(thread, unscopableList, toReversedKey, trueVal);
2198
2199 JSHandle<JSTaggedValue> toSortedKey((factory->NewFromASCII("toSorted")));
2200 JSObject::CreateDataProperty(thread, unscopableList, toSortedKey, trueVal);
2201
2202 JSHandle<JSTaggedValue> toSplicedKey((factory->NewFromASCII("toSpliced")));
2203 JSObject::CreateDataProperty(thread, unscopableList, toSplicedKey, trueVal);
2204 return unscopableList.GetTaggedValue();
2205 }
2206
2207 // 23.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
Includes(EcmaRuntimeCallInfo * argv)2208 JSTaggedValue BuiltinsSharedArray::Includes(EcmaRuntimeCallInfo *argv)
2209 {
2210 ASSERT(argv);
2211 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Includes);
2212 JSThread *thread = argv->GetThread();
2213 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2214 // 1. Let O be ? ToObject(this value).
2215 // thisHandle variable declare this Macro
2216 ARRAY_CHECK_SHARED_ARRAY("The includes method cannot be bound.")
2217
2218 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2219 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2220 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2221
2222 uint32_t argc = argv->GetArgsNumber();
2223 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2224 JSHandle<JSTaggedValue> searchElement = GetCallArg(argv, 0);
2225
2226 // 2. Let len be ? LengthOfArrayLike(O).
2227 int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2228 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2229 // 3. If len is 0, return false.
2230 if (len == 0) {
2231 return GetTaggedBoolean(false);
2232 }
2233 // 4. Let n be ? ToIntegerOrInfinity(fromIndex).
2234 // 5. Assert: If fromIndex is undefined, then n is 0.
2235 double fromIndex = 0;
2236 if (argc > 1) {
2237 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
2238 JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1);
2239 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2240 fromIndex = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber());
2241 }
2242
2243 // 6. If n is +∞, return false.
2244 // 7. Else if n is -∞, set n to 0.
2245 if (fromIndex >= len) {
2246 return GetTaggedBoolean(false);
2247 } else if (fromIndex < -len) {
2248 fromIndex = 0;
2249 }
2250 // 8. If n ≥ 0, then
2251 // a. Let k be n.
2252 // 9. Else,
2253 // a. Let k be len + n.
2254 // b. If k < 0, let k be 0.
2255 int64_t from = (fromIndex >= 0) ? fromIndex : ((len + fromIndex) >= 0 ? len + fromIndex : 0);
2256
2257 // 10. Repeat, while k < len,
2258 // a. Let elementK be ? Get(O, ! ToString(!(k))).
2259 // b. If SameValueZero(searchElement, elementK) is true, return true.
2260 // c. Set k to k + 1.
2261 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2262 JSMutableHandle<JSTaggedValue> kValueHandle(thread, JSTaggedValue::Undefined());
2263 JSHandle<EcmaString> fromStr;
2264 while (from < len) {
2265 kValueHandle.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, from));
2266 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2267 if (JSTaggedValue::SameValueZero(searchElement.GetTaggedValue(), kValueHandle.GetTaggedValue())) {
2268 return GetTaggedBoolean(true);
2269 }
2270 from++;
2271 }
2272 // 11. Return false.
2273 return GetTaggedBoolean(false);
2274 }
2275
2276 // 23.1.3.1 Array.prototype.at ( index )
At(EcmaRuntimeCallInfo * argv)2277 JSTaggedValue BuiltinsSharedArray::At(EcmaRuntimeCallInfo *argv)
2278 {
2279 ASSERT(argv);
2280 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, At);
2281 JSThread *thread = argv->GetThread();
2282 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2283
2284 // 1. Let O be ToObject(this value).
2285 // thisHandle variable declare this Macro
2286 ARRAY_CHECK_SHARED_ARRAY("The at method cannot be bound.")
2287
2288 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2289 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2290
2291 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2292 // ReturnIfAbrupt(O).
2293 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2294
2295 // 2. Let len be ? LengthOfArrayLike(O).
2296 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2297 // ReturnIfAbrupt(len).
2298 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2299
2300 // 3. Let index be ? ToIntegerOrInfinity(index).
2301 JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
2302 // ReturnIfAbrupt(index).
2303 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2304
2305 // 4. If relativeIndex ≥ 0, then
2306 // a. Let k be relativeIndex.
2307 // 5. Else,
2308 // a. Let k be len + relativeIndex.
2309 int64_t relativeIndex = index.GetNumber();
2310 int64_t k = 0;
2311 if (relativeIndex >= 0) {
2312 k = relativeIndex;
2313 } else {
2314 k = len + relativeIndex;
2315 }
2316
2317 // 6. If k < 0 or k ≥ len, return undefined.
2318 if (k < 0 || k >= len) {
2319 // Return undefined.
2320 return JSTaggedValue::Undefined();
2321 }
2322 // 7. Return ? Get(O, ! ToString((k))).
2323 JSHandle<JSTaggedValue> element(thread, BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2324 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2325 return element.GetTaggedValue();
2326 }
2327
2328 // Array.prototype.findLast ( predicate [ , thisArg ] )
FindLast(EcmaRuntimeCallInfo * argv)2329 JSTaggedValue BuiltinsSharedArray::FindLast(EcmaRuntimeCallInfo *argv)
2330 {
2331 ASSERT(argv);
2332 JSThread *thread = argv->GetThread();
2333 BUILTINS_API_TRACE(thread, SharedArray, FindLast);
2334 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2335
2336 // 1. Let O be ToObject(this value).
2337 ARRAY_CHECK_SHARED_ARRAY("The FindLast method cannot be bound.")
2338
2339 JSHandle<JSObject> thisObjHandle(thread, JSObject::Cast(thisHandle.GetTaggedValue()));
2340 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2341 // 2. ReturnIfAbrupt(O).
2342 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2343
2344 // 3. Let len be ToLength(Get(O, "length")).
2345 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2346 // 4. ReturnIfAbrupt(len).
2347 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2348
2349 // 5. If IsCallable(predicate) is false, throw a TypeError exception.
2350 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
2351 if (!callbackFnHandle->IsCallable()) {
2352 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
2353 }
2354
2355 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
2356 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
2357 const uint32_t argsLength = 3; // 3: «kValue, k, O»
2358 // 7. Let k be (len - 1).
2359 int64_t k = len - 1;
2360 // 8. Repeat, while k >= 0
2361 // a. Let Pk be ToString(k).
2362 // b. Let kValue be Get(O, Pk).
2363 // c. ReturnIfAbrupt(kValue).
2364 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
2365 // e. ReturnIfAbrupt(testResult).
2366 // f. If testResult is true, return kValue.
2367 // g. Decrease k by 1.
2368 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2369 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
2370 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2371 JSTaggedValue callResult = GetTaggedBoolean(false);
2372 while (k >= 0) {
2373 kValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2374 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2375 key.Update(JSTaggedValue(k));
2376 EcmaRuntimeCallInfo *info =
2377 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
2378 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2379 ASSERT(info != nullptr);
2380 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
2381 callResult = JSFunction::Call(info);
2382 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2383 if (callResult.ToBoolean()) {
2384 return kValue.GetTaggedValue();
2385 }
2386 k--;
2387 }
2388
2389 // 9. Return undefined.
2390 return JSTaggedValue::Undefined();
2391 }
2392
2393 // Array.prototype.findLastIndex ( predicate [ , thisArg ] )
FindLastIndex(EcmaRuntimeCallInfo * argv)2394 JSTaggedValue BuiltinsSharedArray::FindLastIndex(EcmaRuntimeCallInfo *argv)
2395 {
2396 ASSERT(argv);
2397 JSThread *thread = argv->GetThread();
2398 BUILTINS_API_TRACE(thread, SharedArray, FindLastIndex);
2399 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2400
2401 // 1. Let O be ToObject(this value).
2402 ARRAY_CHECK_SHARED_ARRAY("The FindLastIndex method cannot be bound.")
2403
2404 JSHandle<JSObject> thisObjHandle(thread, JSObject::Cast(thisHandle.GetTaggedValue()));
2405 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2406 // 2. ReturnIfAbrupt(O).
2407 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2408
2409 // 3. Let len be ToLength(Get(O, "length")).
2410 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2411 // 4. ReturnIfAbrupt(len).
2412 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2413
2414 // 5. If IsCallable(predicate) is false, throw a TypeError exception.
2415 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
2416 if (!callbackFnHandle->IsCallable()) {
2417 THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
2418 }
2419
2420 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
2421 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
2422 const uint32_t argsLength = 3; // 3: «kValue, k, O»
2423 // 7. Let k be (len - 1).
2424 int64_t k = len - 1;
2425 // 8. Repeat, while k >= 0
2426 // a. Let Pk be ToString(k).
2427 // b. Let kValue be Get(O, Pk).
2428 // c. ReturnIfAbrupt(kValue).
2429 // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
2430 // e. ReturnIfAbrupt(testResult).
2431 // f. If testResult is true, return k.
2432 // g. Decrease k by 1.
2433 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2434 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
2435 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2436 JSTaggedValue callResult = GetTaggedBoolean(false);
2437 while (k >= 0) {
2438 kValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2439 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2440 key.Update(JSTaggedValue(k));
2441 EcmaRuntimeCallInfo *info =
2442 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
2443 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2444 ASSERT(info != nullptr);
2445 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
2446 callResult = JSFunction::Call(info);
2447 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2448 if (callResult.ToBoolean()) {
2449 return GetTaggedDouble(k);
2450 }
2451 k--;
2452 }
2453
2454 // 9. Return -1.
2455 return GetTaggedDouble(-1);
2456 }
2457
2458 // Array.prototype.shrinkTo ( arrayLength )
ShrinkTo(EcmaRuntimeCallInfo * argv)2459 JSTaggedValue BuiltinsSharedArray::ShrinkTo(EcmaRuntimeCallInfo *argv)
2460 {
2461 ASSERT(argv);
2462 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo);
2463 JSThread *thread = argv->GetThread();
2464 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2465 if (argv->GetArgsNumber() != 1) {
2466 auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameter.");
2467 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2468 }
2469
2470 // thisHandle variable declare this Macro
2471 ARRAY_CHECK_SHARED_ARRAY("The shrinkTo method cannot be bound.")
2472
2473 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2474 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2475 JSHandle<JSTaggedValue> newLengthValue = GetCallArg(argv, 0);
2476 if (!newLengthValue->IsNumber()) {
2477 auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2478 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2479 }
2480 auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue);
2481 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2482 if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) {
2483 auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2484 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2485 }
2486 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2487 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2488 if (newLength >= len) {
2489 return JSTaggedValue::Undefined();
2490 }
2491 JSSharedArray::LengthSetter(thread, thisObjHandle, newLengthValue, true);
2492 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2493 return JSTaggedValue::Undefined();
2494 }
2495
2496 // Array.prototype.ExtendTo ( arrayLength, initialValue )
ExtendTo(EcmaRuntimeCallInfo * argv)2497 JSTaggedValue BuiltinsSharedArray::ExtendTo(EcmaRuntimeCallInfo *argv)
2498 {
2499 ASSERT(argv);
2500 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo);
2501 JSThread *thread = argv->GetThread();
2502 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2503 if (argv->GetArgsNumber() < COUNT_LENGTH_AND_INIT) {
2504 auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameters.");
2505 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2506 }
2507
2508 // thisHandle variable declare this Macro
2509 ARRAY_CHECK_SHARED_ARRAY("The extendTo method cannot be bound.")
2510
2511 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2512 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2513 JSHandle<JSTaggedValue> newLengthValue = GetCallArg(argv, 0);
2514 if (!newLengthValue->IsNumber()) {
2515 auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2516 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2517 }
2518 auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue);
2519 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2520 if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) {
2521 auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2522 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2523 }
2524
2525 int64_t length = ArrayHelper::GetLength(thread, thisHandle);
2526 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2527 if (newLength <= length) {
2528 return JSTaggedValue::Undefined();
2529 }
2530
2531 JSHandle<JSTaggedValue> initValue = GetCallArg(argv, 1);
2532 if (!initValue->IsSharedType()) {
2533 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
2534 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2535 }
2536
2537 if (newLength > ElementAccessor::GetElementsLength(thisObjHandle)) {
2538 JSObject::GrowElementsCapacity(thread, thisObjHandle, newLength, true);
2539 }
2540
2541 for (uint32_t k = static_cast<uint32_t>(length); k < newLength; k++) {
2542 BuiltinsSharedArray::SetElementValue(thread, thisObjHandle, k, initValue);
2543 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2544 }
2545
2546 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(newLength));
2547 JSSharedArray::LengthSetter(thread, thisObjHandle, key, true);
2548 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2549 return JSTaggedValue::Undefined();
2550 }
2551
LastIndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle)2552 JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath(EcmaRuntimeCallInfo *argv, JSThread *thread,
2553 const JSHandle<JSTaggedValue> &thisHandle)
2554 {
2555 // 1. Let O be ToObject(this value).
2556 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2557 // 2. ReturnIfAbrupt(O).
2558 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2559 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2560 // 3. Let len be ToLength(Get(O, "length")).
2561 int64_t length = ArrayHelper::GetLength(thread, thisObjVal);
2562 // 4. ReturnIfAbrupt(len).
2563 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2564 // 5. If len is 0, return −1.
2565 if (length == 0) {
2566 return JSTaggedValue(-1);
2567 }
2568 // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0.
2569 int64_t fromIndex = ArrayHelper::GetLastStartIndexFromArgs(thread, argv, 1, length);
2570 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2571 return LastIndexOfSlowPath(argv, thread, thisObjVal, fromIndex);
2572 }
2573
LastIndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisObjVal,int64_t fromIndex)2574 JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath(EcmaRuntimeCallInfo *argv, JSThread *thread,
2575 const JSHandle<JSTaggedValue> &thisObjVal, int64_t fromIndex)
2576 {
2577 if (fromIndex < 0) {
2578 return JSTaggedValue(-1);
2579 }
2580 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2581 JSHandle<JSTaggedValue> target = base::BuiltinsBase::GetCallArg(argv, 0);
2582 // 11. Repeat, while k < len
2583 for (int64_t curIndex = fromIndex; curIndex >= 0; --curIndex) {
2584 keyHandle.Update(JSTaggedValue(curIndex));
2585 bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target);
2586 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2587 if (UNLIKELY(found)) {
2588 return JSTaggedValue(curIndex);
2589 }
2590 }
2591 // 12. Return -1.
2592 return JSTaggedValue(-1);
2593 }
2594
2595 // Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] )
LastIndexOf(EcmaRuntimeCallInfo * argv)2596 JSTaggedValue BuiltinsSharedArray::LastIndexOf(EcmaRuntimeCallInfo *argv)
2597 {
2598 ASSERT(argv);
2599 JSThread *thread = argv->GetThread();
2600 BUILTINS_API_TRACE(thread, SharedArray, LastIndexOf);
2601 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2602
2603 // thisHandle variable declare this Macro
2604 ARRAY_CHECK_SHARED_ARRAY("The lastIndexOf method cannot be bound.")
2605
2606 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2607 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2608
2609 return LastIndexOfSlowPath(argv, thread, thisHandle);
2610 }
2611
2612 // Array.of ( ...items )
Of(EcmaRuntimeCallInfo * argv)2613 JSTaggedValue BuiltinsSharedArray::Of(EcmaRuntimeCallInfo *argv)
2614 {
2615 ASSERT(argv);
2616 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Of);
2617 JSThread *thread = argv->GetThread();
2618 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2619 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2620
2621 // 1. Let len be the actual number of arguments passed to this function.
2622 uint32_t argc = argv->GetArgsNumber();
2623
2624 // 3. Let C be the this value.
2625 // thisHandle variable declare this Macro
2626 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2627
2628 // 4. If IsConstructor(C) is true, then
2629 // a. Let A be Construct(C, «len»).
2630 // 5. Else,
2631 // a. Let A be ArrayCreate(len).
2632 // 6. ReturnIfAbrupt(A).
2633 JSHandle<JSTaggedValue> newArray;
2634 if (thisHandle->IsConstructor()) {
2635 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
2636 EcmaRuntimeCallInfo *info =
2637 EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 1);
2638 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2639 ASSERT(info != nullptr);
2640 info->SetCallArg(JSTaggedValue(argc));
2641 JSTaggedValue taggedArray = JSFunction::Construct(info);
2642 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2643 newArray = JSHandle<JSTaggedValue>(thread, taggedArray);
2644 } else {
2645 newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(argc));
2646 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2647 }
2648
2649 if (!newArray->IsJSSharedArray()) {
2650 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception());
2651 }
2652
2653 JSHandle<JSObject> newArrayHandle(newArray);
2654 if (UNLIKELY(argc > ElementAccessor::GetElementsLength(newArrayHandle))) {
2655 JSObject::GrowElementsCapacity(thread, JSHandle<JSObject>::Cast(newArrayHandle), argc, true);
2656 }
2657
2658 // 7. Let k be 0.
2659 // 8. Repeat, while k < len
2660 // a. Let kValue be items[k].
2661 // b. Let Pk be ToString(k).
2662 // c. Let defineStatus be CreateDataPropertyOrThrow(A,Pk, kValue).
2663 // d. ReturnIfAbrupt(defineStatus).
2664 // e. Increase k by 1.
2665 for (uint32_t k = 0; k < argc; k++) {
2666 JSHandle<JSTaggedValue> value = argv->GetCallArg(k);
2667 BuiltinsSharedArray::SetElementValue(thread, newArrayHandle, k, value);
2668 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2669 }
2670 JSSharedArray::Cast(*newArrayHandle)->SetArrayLength(thread, argc);
2671 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2672
2673 return newArrayHandle.GetTaggedValue();
2674 }
2675
ConvertTagValueToInteger(JSThread * thread,JSHandle<JSTaggedValue> & number,int64_t len)2676 int64_t BuiltinsSharedArray::ConvertTagValueToInteger(JSThread *thread, JSHandle<JSTaggedValue>& number, int64_t len)
2677 {
2678 JSTaggedNumber targetTemp = JSTaggedValue::ToInteger(thread, number);
2679 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
2680 double target = targetTemp.GetNumber();
2681 // If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to be min(relativeTarget, len).
2682 if (target < 0) {
2683 return target + len > 0 ? static_cast<int64_t>(target + len) : 0;
2684 } else {
2685 return target < len ? static_cast<int64_t>(target) : len;
2686 }
2687 }
2688
GetNumberArgVal(JSThread * thread,EcmaRuntimeCallInfo * argv,uint32_t idx,int64_t len,int64_t defVal)2689 int64_t BuiltinsSharedArray::GetNumberArgVal(JSThread *thread, EcmaRuntimeCallInfo *argv, uint32_t idx, int64_t len,
2690 int64_t defVal)
2691 {
2692 JSHandle<JSTaggedValue> argValue = GetCallArg(argv, idx);
2693
2694 return argValue->IsUndefined() ? defVal : BuiltinsSharedArray::ConvertTagValueToInteger(thread, argValue, len);
2695 }
2696
GetNumberArgValThrow(JSThread * thread,EcmaRuntimeCallInfo * argv,uint32_t idx,int64_t len,const char * err)2697 int64_t BuiltinsSharedArray::GetNumberArgValThrow(JSThread *thread, EcmaRuntimeCallInfo *argv, uint32_t idx,
2698 int64_t len, const char* err)
2699 {
2700 JSHandle<JSTaggedValue> argValue = GetCallArg(argv, idx);
2701 if (UNLIKELY(argValue->IsUndefined())) {
2702 auto error = ContainerError::BindError(thread, err);
2703 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, 0);
2704 }
2705
2706 return BuiltinsSharedArray::ConvertTagValueToInteger(thread, argValue, len);
2707 }
2708
2709 // Array.prototype.copyWithin (target, start [ , end ] )
CopyWithin(EcmaRuntimeCallInfo * argv)2710 JSTaggedValue BuiltinsSharedArray::CopyWithin(EcmaRuntimeCallInfo *argv)
2711 {
2712 ASSERT(argv);
2713 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, CopyWithin);
2714 JSThread *thread = argv->GetThread();
2715 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2716
2717 // 1. Let O be ToObject(this value).
2718 // 3. Let C be the this value.
2719 // thisHandle variable declare this Macro
2720 ARRAY_CHECK_SHARED_ARRAY("The CopyWithin method cannot be bound.")
2721
2722 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2723 // 2. ReturnIfAbrupt(O).
2724 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2725
2726 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2727 // 3. Let len be ToLength(Get(O, "length")).
2728 int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2729 // 4. ReturnIfAbrupt(len).
2730 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2731
2732 int64_t copyTo = GetNumberArgValThrow(thread, argv, 0, len, "Target index cannot be undefined.");
2733 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2734
2735 // 5. Let relativeStart be ToInteger(start).
2736 int64_t copyFrom = GetNumberArgVal(thread, argv, 1, len, 0);
2737 // 6. ReturnIfAbrupt(relativeStart).
2738 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2739
2740 // 7. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
2741 int64_t copyEnd = GetNumberArgVal(thread, argv, 2, len, len);
2742 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2743
2744 // 14. Let count be min(final-from, len-to).
2745 int64_t count = std::min(copyEnd - copyFrom, len - copyTo);
2746
2747 // 15. If from<to and to<from+count
2748 // a. Let direction be -1.
2749 // b. Let from be from + count -1.
2750 // c. Let to be to + count -1.
2751 // 16. Else,
2752 // a. Let direction = 1.
2753 if (count > 0) {
2754 TaggedArray *element = TaggedArray::Cast(thisObjHandle->GetElements().GetTaggedObject());
2755 element->Copy<true, true>(thread, copyTo, copyFrom, element, count);
2756 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2757 }
2758
2759 // 18. Return O.
2760 return thisObjHandle.GetTaggedValue();
2761 }
2762
FastReverse(JSThread * thread,JSHandle<TaggedArray> & elements,uint32_t lower,uint32_t len,ElementsKind kind)2763 JSTaggedValue BuiltinsSharedArray::FastReverse(JSThread *thread, JSHandle<TaggedArray> &elements,
2764 uint32_t lower, uint32_t len, ElementsKind kind)
2765 {
2766 JSMutableHandle<JSTaggedValue> lowerValueHandle(thread, JSTaggedValue::Undefined());
2767 JSMutableHandle<JSTaggedValue> upperValueHandle(thread, JSTaggedValue::Undefined());
2768 uint32_t middle = std::floor(len / 2);
2769 while (lower != middle) {
2770 uint32_t upper = len - lower - 1;
2771 lowerValueHandle.Update(ElementAccessor::FastGet(elements, lower, kind));
2772 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2773 upperValueHandle.Update(ElementAccessor::FastGet(elements, upper, kind));
2774 ElementAccessor::FastSet(thread, elements, lower, upperValueHandle, kind);
2775 ElementAccessor::FastSet(thread, elements, upper, lowerValueHandle, kind);
2776 lower++;
2777 }
2778 return base::BuiltinsBase::GetTaggedDouble(true);
2779 }
2780
2781 // Array.prototype.reverse ( )
Reverse(EcmaRuntimeCallInfo * argv)2782 JSTaggedValue BuiltinsSharedArray::Reverse(EcmaRuntimeCallInfo *argv)
2783 {
2784 ASSERT(argv);
2785 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Reverse);
2786 JSThread *thread = argv->GetThread();
2787 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2788
2789 // 1. Let O be ToObject(this value).
2790 // thisHandle variable declare this Macro
2791 ARRAY_CHECK_SHARED_ARRAY("The Reverse method cannot be bound.")
2792 JSHandle<JSObject> thisObjHandle(thread, JSObject::Cast(thisHandle.GetTaggedValue()));
2793 [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2794 // 2. ReturnIfAbrupt(O).
2795 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2796 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2797
2798 // 3. Let len be ToLength(Get(O, "length")).
2799 int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2800 // 4. ReturnIfAbrupt(len).
2801 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2802
2803 // 7. Repeat, while lower != middle
2804 // a. Let upper be len-lower-1.
2805 // b. Let upperP be ToString(upper).
2806
2807 // c. Let lowerP be ToString(lower).
2808 // d. Let lowerExists be HasProperty(O, lowerP).
2809 // e. ReturnIfAbrupt(lowerExists).
2810 // f. If lowerExists is true, then
2811 // i. Let lowerValue be Get(O, lowerP).
2812 // ii. ReturnIfAbrupt(lowerValue).
2813 // g. Let upperExists be HasProperty(O, upperP).
2814 // h. ReturnIfAbrupt(upperExists).
2815 // i. If upperExists is true, then
2816 // i. Let upperValue be Get(O, upperP).
2817 // ii. ReturnIfAbrupt(upperValue).
2818 // j. If lowerExists is true and upperExists is true, then
2819 // i. Let setStatus be Set(O, lowerP, upperValue, true).
2820 // ii. ReturnIfAbrupt(setStatus).
2821 // iii. Let setStatus be Set(O, upperP, lowerValue, true).
2822 // iv. ReturnIfAbrupt(setStatus).
2823 // k. Else if lowerExists is false and upperExists is true, then
2824 // i. Let setStatus be Set(O, lowerP, upperValue, true).
2825 // ii. ReturnIfAbrupt(setStatus).
2826 // iii. Let deleteStatus be DeletePropertyOrThrow (O, upperP).
2827 // iv. ReturnIfAbrupt(deleteStatus).
2828 // l. Else if lowerExists is true and upperExists is false, then
2829 // i. Let deleteStatus be DeletePropertyOrThrow (O, lowerP).
2830 // ii. ReturnIfAbrupt(deleteStatus).
2831 // iii. Let setStatus be Set(O, upperP, lowerValue, true).
2832 // iv. ReturnIfAbrupt(setStatus).
2833 // m. Else both lowerExists and upperExists are false,
2834 // i. No action is required.
2835 // n. Increase lower by 1.
2836 ElementsKind kind = thisObjHandle->GetClass()->GetElementsKind();
2837 JSHandle<TaggedArray> elements(thread, thisObjHandle->GetElements());
2838 bool enableElementsKind = thread->GetEcmaVM()->IsEnableElementsKind();
2839 if (enableElementsKind) {
2840 if (kind == ElementsKind::INT || kind == ElementsKind::HOLE_INT) {
2841 FastReverse(thread, elements, 0, len, ElementsKind::INT);
2842 return thisObjHandle.GetTaggedValue();
2843 } else if (kind == ElementsKind::NUMBER || kind == ElementsKind::HOLE_NUMBER) {
2844 FastReverse(thread, elements, 0, len, ElementsKind::NUMBER);
2845 return thisObjHandle.GetTaggedValue();
2846 }
2847 }
2848 FastReverse(thread, elements, 0, len, ElementsKind::TAGGED);
2849
2850 // 8. Return O .
2851 return thisObjHandle.GetTaggedValue();
2852 }
2853
2854 // Array.prototype.reduceRight ( callbackfn [ , initialValue ] )
ReduceRight(EcmaRuntimeCallInfo * argv)2855 JSTaggedValue BuiltinsSharedArray::ReduceRight(EcmaRuntimeCallInfo *argv)
2856 {
2857 ASSERT(argv);
2858 BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ReduceRight);
2859 JSThread *thread = argv->GetThread();
2860 [[maybe_unused]] EcmaHandleScope handleScope(thread);
2861
2862 uint32_t argc = argv->GetArgsNumber();
2863 // 1. Let O be ToObject(this value).
2864 // thisHandle variable declare this Macro
2865 ARRAY_CHECK_SHARED_ARRAY("The ReduceRight method cannot be bound.")
2866
2867 JSHandle<JSObject> thisObjHandle(thread, JSObject::Cast(thisHandle.GetTaggedValue()));
2868 [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2869 // 2. ReturnIfAbrupt(O).
2870 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2871
2872 // 3. Let len be ToLength(Get(O, "length")).
2873 int64_t len = ArrayHelper::GetArrayLength(thread, thisHandle);
2874 // 4. ReturnIfAbrupt(len).
2875 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2876 return ReduceRightInternalHandle(argv, thread, thisHandle, thisObjHandle, argc, len);
2877 }
2878
ReduceRightInternalHandle(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,JSHandle<JSObject> & thisObjHandle,uint32_t argc,int64_t len)2879 JSTaggedValue BuiltinsSharedArray::ReduceRightInternalHandle(EcmaRuntimeCallInfo *argv, JSThread *thread,
2880 const JSHandle<JSTaggedValue> &thisHandle, JSHandle<JSObject> &thisObjHandle, uint32_t argc, int64_t len)
2881 {
2882 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
2883 if (!callbackFnHandle->IsCallable()) {
2884 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
2885 }
2886
2887 // 6. If len is 0 and initialValue is not present, throw a TypeError exception.
2888 const int32_t argcLimitLength = 2; // argc limit length of the number parameters
2889 if (len == 0 && argc < argcLimitLength) {
2890 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
2891 }
2892 // 7. Let k be len-1.
2893 int64_t k = len - 1;
2894 // 8. If initialValue is present, then
2895 // a. Set accumulator to initialValue.
2896 // 9. Else initialValue is not present,
2897 // a. Get last element initial accumulator
2898 JSMutableHandle<JSTaggedValue> accumulator(thread, JSTaggedValue::Undefined());
2899 if (argc >= argcLimitLength) { // 2:2 means the number of parameters
2900 accumulator.Update(GetCallArg(argv, 1).GetTaggedValue());
2901 } else if (k >= 0) {
2902 accumulator.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2903 k--;
2904 }
2905
2906 // 10. Repeat, while k ≥ 0
2907 // a. Let Pk be ToString(k).
2908 // b. Let kPresent be HasProperty(O, Pk).
2909 // c. ReturnIfAbrupt(kPresent).
2910 // d. If kPresent is true, then
2911 // i. Let kValue be Get(O, Pk).
2912 // ii. ReturnIfAbrupt(kValue).
2913 // iii. Let accumulator be Call(callbackfn, undefined, «accumulator, kValue, k, O»).
2914 // iv. ReturnIfAbrupt(accumulator).
2915 // e. Decrease k by 1.
2916 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2917 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
2918 JSTaggedValue callResult = JSTaggedValue::Undefined();
2919 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
2920 const int32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
2921 while (k >= 0) {
2922 kValue.Update(BuiltinsSharedArray::GetElementByKey(thread, thisObjHandle, k));
2923 key.Update(JSTaggedValue(k));
2924 EcmaRuntimeCallInfo *info =
2925 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, undefined, undefined, argsLength);
2926 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2927 ASSERT(info != nullptr);
2928 info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(),
2929 key.GetTaggedValue(), thisHandle.GetTaggedValue());
2930 callResult = JSFunction::Call(info);
2931 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2932 accumulator.Update(callResult);
2933 k--;
2934 }
2935
2936 // 11. Return accumulator.
2937 return accumulator.GetTaggedValue();
2938 }
2939
2940 } // namespace panda::ecmascript::builtins
2941