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