• 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 #include <cmath>
19 
20 #include "ecmascript/builtins/builtins_array.h"
21 #include "ecmascript/builtins/builtins_string.h"
22 #include "ecmascript/interpreter/interpreter.h"
23 #include "ecmascript/js_map_iterator.h"
24 #include "ecmascript/js_stable_array.h"
25 #include "ecmascript/object_fast_operator-inl.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 
35 // 22.1.1
ArrayConstructor(EcmaRuntimeCallInfo * argv)36 JSTaggedValue BuiltinsSharedArray::ArrayConstructor(EcmaRuntimeCallInfo *argv)
37 {
38     BUILTINS_ENTRY_DEBUG_LOG();
39     ASSERT(argv);
40     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Constructor);
41     JSThread *thread = argv->GetThread();
42     [[maybe_unused]] EcmaHandleScope handleScope(thread);
43 
44     // 1. Let numberOfArgs be the number of arguments passed to this function call.
45     uint32_t argc = argv->GetArgsNumber();
46 
47     // 3. If NewTarget is undefined, throw exception
48     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
49     if (newTarget->IsUndefined()) {
50         JSTaggedValue error = containers::ContainerError::BusinessError(
51             thread, containers::ErrorFlag::IS_NULL_ERROR, "The ArkTS Array's constructor cannot be directly invoked.");
52         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
53     }
54 
55     // 4. Let proto be GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").
56     // In NewJSObjectByConstructor(), will get prototype.
57     // 5. ReturnIfAbrupt(proto).
58 
59     // 22.1.1.1 Array ( )
60     if (argc == 0) {
61         // 6. Return ArrayCreate(0, proto).
62         return JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0), newTarget).GetTaggedValue();
63     }
64 
65     // 22.1.1.3 Array(...items )
66     JSTaggedValue newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(argc), newTarget).GetTaggedValue();
67     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
68     if (!newArray.IsJSSharedArray()) {
69         THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create array.", JSTaggedValue::Exception());
70     }
71     JSHandle<JSObject> newArrayHandle(thread, newArray);
72     // 8. Let k be 0.
73     // 9. Let items be a zero-origined List containing the argument items in order.
74     // 10. Repeat, while k < numberOfArgs
75     //   a. Let Pk be ToString(k).
76     //   b. Let itemK be items[k].
77     //   c. Let defineStatus be CreateDataProperty(array, Pk, itemK).
78     //   d. Assert: defineStatus is true.
79     //   e. Increase k by 1.
80     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
81     JSMutableHandle<JSTaggedValue> itemK(thread, JSTaggedValue::Undefined());
82     for (uint32_t k = 0; k < argc; k++) {
83         key.Update(JSTaggedValue(k));
84         itemK.Update(GetCallArg(argv, k));
85         if (!itemK->IsSharedType()) {
86             auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
87             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
88         }
89         JSObject::CreateDataProperty(thread, newArrayHandle, key, itemK);
90     }
91     // 11. Assert: the value of array’s length property is numberOfArgs.
92     // 12. Return array.
93     JSSharedArray::Cast(*newArrayHandle)->SetArrayLength(thread, argc);
94     newArrayHandle->GetJSHClass()->SetExtensible(false);
95     return newArrayHandle.GetTaggedValue();
96 }
97 
98 // 22.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] )
99 // NOLINTNEXTLINE(readability-function-size)
From(EcmaRuntimeCallInfo * argv)100 JSTaggedValue BuiltinsSharedArray::From(EcmaRuntimeCallInfo *argv)
101 {
102     ASSERT(argv);
103     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, From);
104     JSThread *thread = argv->GetThread();
105     [[maybe_unused]] EcmaHandleScope handleScope(thread);
106     // 1. Let C be the this value.
107     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
108     // 2. If mapfn is undefined, let mapping be false.
109     bool mapping = false;
110     // 3. else
111     //   a. If IsCallable(mapfn) is false, throw a TypeError exception.
112     //   b. If thisArg was supplied, let T be thisArg; else let T be undefined.
113     //   c. Let mapping be true
114     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, INDEX_TWO);
115     JSHandle<JSTaggedValue> mapfn = GetCallArg(argv, 1);
116     if (!mapfn->IsUndefined()) {
117         if (!mapfn->IsCallable()) {
118             THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception());
119         }
120         mapping = true;
121     }
122     // 4. Let usingIterator be GetMethod(items, @@iterator).
123     JSHandle<JSTaggedValue> items = GetCallArg(argv, 0);
124     if (items->IsNull()) {
125         THROW_TYPE_ERROR_AND_RETURN(thread, "The items is null.", JSTaggedValue::Exception());
126     }
127     if (!mapping && items->IsString()) {
128         JSHandle<EcmaString> strItems(items);
129         return BuiltinsString::StringToSList(thread, strItems);
130     }
131     // Fast path for TypedArray
132     if (!mapping && (items->IsTypedArray() || items->IsSharedTypedArray())) {
133         auto error = ContainerError::ParamError(thread, "Parameter error.TypedArray not support yet.");
134         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
135     }
136 
137     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
138     JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
139     JSHandle<JSTaggedValue> usingIterator = JSObject::GetMethod(thread, items, iteratorSymbol);
140     // 5. ReturnIfAbrupt(usingIterator).
141     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
142     // 6. If usingIterator is not undefined, then
143     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
144     if (!usingIterator->IsUndefined()) {
145         // Fast path for MapIterator
146         JSHandle<JSTaggedValue> iterator(thread, JSTaggedValue::Hole());
147         if (!mapping && items->IsJSMapIterator()) {
148             iterator = JSIterator::GetIterator(thread, items, usingIterator);
149             if (iterator->IsJSMapIterator()) {
150                 return JSMapIterator::MapIteratorToList(thread, iterator);
151             }
152         }
153 
154         //   a. If IsConstructor(C) is true, then
155         //     i. Let A be Construct(C).
156         //   b. Else,
157         //     i. Let A be ArrayCreate(0).
158         //   c. ReturnIfAbrupt(A).
159         JSTaggedValue newArray;
160         if (thisHandle->IsConstructor()) {
161             EcmaRuntimeCallInfo *info =
162                 EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 0);
163             newArray = JSFunction::Construct(info);
164             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
165         } else {
166             newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue();
167             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
168         }
169         if (!newArray.IsJSSharedArray()) {
170             THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception());
171         }
172         JSHandle<JSObject> newArrayHandle(thread, newArray);
173         //   d. Let iterator be GetIterator(items, usingIterator).
174         if (iterator->IsHole()) {
175             iterator = JSIterator::GetIterator(thread, items, usingIterator);
176             //   e. ReturnIfAbrupt(iterator).
177             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
178         }
179         //   f. Let k be 0.
180         int k = 0;
181         //   g. Repeat
182         JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
183         JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
184         while (true) {
185             key.Update(JSTaggedValue(k));
186             //     i. Let Pk be ToString(k).
187             //     ii. Let next be IteratorStep(iterator).
188             JSHandle<JSTaggedValue> next = JSIterator::IteratorStep(thread, iterator);
189             //     iii. ReturnIfAbrupt(next).
190             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191             //     iv. If next is false, then
192             //       1. Let setStatus be Set(A, "length", k, true).
193             //       2. ReturnIfAbrupt(setStatus).
194             //       3. Return A.
195             if (next->IsFalse()) {
196                 JSSharedArray::LengthSetter(thread, newArrayHandle, key, true);
197                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
198                 newArrayHandle->GetJSHClass()->SetExtensible(false);
199                 return newArrayHandle.GetTaggedValue();
200             }
201             //     v. Let nextValue be IteratorValue(next).
202             JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
203             //     vi. ReturnIfAbrupt(nextValue).
204             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
205             //     vii. If mapping is true, then
206             //       1. Let mappedValue be Call(mapfn, T, «nextValue, k»).
207             //       2. If mappedValue is an abrupt completion, return IteratorClose(iterator, mappedValue).
208             //       3. Let mappedValue be mappedValue.[[value]].
209             //     viii. Else, let mappedValue be nextValue.
210             if (mapping) {
211                 const uint32_t argsLength = 2; // 2: «nextValue, k»
212                 EcmaRuntimeCallInfo *info =
213                     EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
214                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
215                 info->SetCallArg(nextValue.GetTaggedValue(), key.GetTaggedValue());
216                 JSTaggedValue callResult = JSFunction::Call(info);
217                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread,
218                     JSIterator::IteratorClose(thread, iterator, mapValue).GetTaggedValue());
219                 mapValue.Update(callResult);
220             } else {
221                 mapValue.Update(nextValue.GetTaggedValue());
222             }
223             if (!mapValue->IsSharedType()) {
224                 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
225                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
226             }
227             //     ix. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
228             //     x. If defineStatus is an abrupt completion, return IteratorClose(iterator, defineStatus).
229             //     xi. Increase k by 1.
230             JSHandle<JSTaggedValue> defineStatus(thread, JSTaggedValue(JSObject::CreateDataPropertyOrThrow(
231                 thread, newArrayHandle, key, mapValue, SCheckMode::SKIP)));
232             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread,
233                 JSIterator::IteratorClose(thread, iterator, defineStatus).GetTaggedValue());
234             k++;
235         }
236     }
237     // 7. Assert: items is not an Iterable so assume it is an array-like object.
238     // 8. Let arrayLike be ToObject(items).
239     JSHandle<JSObject> arrayLikeObj = JSTaggedValue::ToObject(thread, items);
240     // 9. ReturnIfAbrupt(arrayLike).
241     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
242     JSHandle<JSTaggedValue> arrayLike(arrayLikeObj);
243     // 10. Let len be ToLength(Get(arrayLike, "length")).
244     int64_t len = ArrayHelper::GetArrayLength(thread, arrayLike);
245     // 11. ReturnIfAbrupt(len).
246     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
247     // 12. If IsConstructor(C) is true, then
248     //   a. Let A be Construct(C, «len»).
249     // 13. Else,
250     //   a. Let A be ArrayCreate(len).
251     // 14. ReturnIfAbrupt(A).
252     JSTaggedValue newArray;
253     if (thisHandle->IsConstructor()) {
254         EcmaRuntimeCallInfo *info =
255             EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 1);
256         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
257         info->SetCallArg(JSTaggedValue(len));
258         newArray = JSFunction::Construct(info);
259         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
260     } else {
261         newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue();
262         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
263     }
264     if (!newArray.IsJSSharedArray()) {
265         THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception());
266     }
267     JSHandle<JSObject> newArrayHandle(thread, newArray);
268     // 15. Let k be 0.
269     // 16. Repeat, while k < len
270     //   a. Let Pk be ToString(k).
271     //   b. Let kValue be Get(arrayLike, Pk).
272     //   d. If mapping is true, then
273     //     i. Let mappedValue be Call(mapfn, T, «kValue, k»).
274     //   e. Else, let mappedValue be kValue.
275     //   f. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
276     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
277     JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
278     int64_t k = 0;
279     while (k < len) {
280         JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, arrayLike, k);
281         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
282         if (mapping) {
283             key.Update(JSTaggedValue(k));
284             const uint32_t argsLength = 2; // 2: «kValue, k»
285             EcmaRuntimeCallInfo *info =
286                 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
287             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
288             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue());
289             JSTaggedValue callResult = JSFunction::Call(info);
290             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
291             mapValue.Update(callResult);
292         } else {
293             mapValue.Update(kValue.GetTaggedValue());
294         }
295         if (!mapValue->IsSharedType()) {
296             auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
297             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
298         }
299         JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapValue, SCheckMode::SKIP);
300         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
301         k++;
302     }
303     // 17. Let setStatus be Set(A, "length", len, true).
304     JSHandle<JSTaggedValue> lenHandle(thread, JSTaggedValue(len));
305     JSSharedArray::LengthSetter(thread, newArrayHandle, lenHandle, true);
306     newArrayHandle->GetJSHClass()->SetExtensible(false);
307     // 18. ReturnIfAbrupt(setStatus).
308     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
309     // 19. Return A.
310     return newArrayHandle.GetTaggedValue();
311 }
312 
313 // Array.create ( arrayLength, initialValue )
Create(EcmaRuntimeCallInfo * argv)314 JSTaggedValue BuiltinsSharedArray::Create(EcmaRuntimeCallInfo *argv)
315 {
316     ASSERT(argv);
317     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, From);
318     JSThread *thread = argv->GetThread();
319     [[maybe_unused]] EcmaHandleScope handleScope(thread);
320     if (argv->GetArgsNumber() < COUNT_LENGTH_AND_INIT) {
321         auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameters.");
322         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
323     }
324     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
325     JSHandle<JSTaggedValue> arrayLengthValue = GetCallArg(argv, 0);
326     if (!arrayLengthValue->IsNumber()) {
327         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
328         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
329     }
330     auto arrayLength = JSTaggedValue::ToUint32(thread, arrayLengthValue);
331     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
332     if (JSTaggedNumber(arrayLengthValue.GetTaggedValue()).GetNumber() != arrayLength) {
333         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
334         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
335     }
336     JSHandle<JSTaggedValue> initValue = GetCallArg(argv, 1);
337     if (!initValue->IsSharedType()) {
338         auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
339         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
340     }
341     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
342     JSTaggedValue newArray;
343     if (thisHandle->IsConstructor()) {
344         EcmaRuntimeCallInfo *info =
345             EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 0);
346         newArray = JSFunction::Construct(info);
347         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
348     } else {
349         newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue();
350         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
351     }
352     if (!newArray.IsJSSharedArray()) {
353         THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception());
354     }
355     JSHandle<JSObject> newArrayHandle(thread, newArray);
356     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
357     auto elements = factory->NewSOldSpaceTaggedArray(arrayLength, JSTaggedValue::Hole());
358     for (uint32_t k = 0; k < arrayLength; k++) {
359         elements->Set(thread, k, initValue);
360     }
361     newArrayHandle->SetElements(thread, elements);
362     auto len = JSHandle<JSTaggedValue>(thread, JSTaggedValue(arrayLength));
363     JSSharedArray::LengthSetter(thread, newArrayHandle, len, true);
364     newArrayHandle->GetJSHClass()->SetExtensible(false);
365     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
366     // Return A.
367     return newArrayHandle.GetTaggedValue();
368 }
369 
370 // Array.isArray ( arg )
IsArray(EcmaRuntimeCallInfo * argv)371 JSTaggedValue BuiltinsSharedArray::IsArray(EcmaRuntimeCallInfo *argv)
372 {
373     ASSERT(argv);
374     JSThread *thread = argv->GetThread();
375     BUILTINS_API_TRACE(thread, SharedArray, IsArray);
376     [[maybe_unused]] EcmaHandleScope handleScope(thread);
377     if (GetCallArg(argv, 0)->IsJSSharedArray()) {
378         return GetTaggedBoolean(true);
379     }
380     return GetTaggedBoolean(false);
381 }
382 
383 // 22.1.2.5 get Array [ @@species ]
Species(EcmaRuntimeCallInfo * argv)384 JSTaggedValue BuiltinsSharedArray::Species(EcmaRuntimeCallInfo *argv)
385 {
386     ASSERT(argv);
387     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Species);
388     return BuiltinsArray::Species(argv);
389 }
390 
391 // 22.1.3.1 Array.prototype.concat ( ...arguments )
Concat(EcmaRuntimeCallInfo * argv)392 JSTaggedValue BuiltinsSharedArray::Concat(EcmaRuntimeCallInfo *argv)
393 {
394     ASSERT(argv);
395     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Concat);
396     JSThread *thread = argv->GetThread();
397     [[maybe_unused]] EcmaHandleScope handleScope(thread);
398     int argc = static_cast<int>(argv->GetArgsNumber());
399 
400     // 1. Let O be ToObject(this value).
401     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
402     if (!thisHandle->IsJSSharedArray()) {
403         auto error = ContainerError::BindError(thread, "The concat method cannot be bound.");
404         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
405     }
406     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
407     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
408     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
409     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
410 
411     // 2. Let A be ArraySpeciesCreate(O, 0).
412     uint32_t arrayLen = 0;
413     JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen));
414     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
415     if (!(newArray.IsECMAObject() || newArray.IsUndefined())) {
416         THROW_TYPE_ERROR_AND_RETURN(thread, "array must be object or undefined.", JSTaggedValue::Exception());
417     }
418     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
419     JSHandle<JSObject> newArrayHandle(thread, newArray);
420 
421     // 3. Let n be 0.
422     int64_t n = 0;
423     JSMutableHandle<JSTaggedValue> ele(thread, JSTaggedValue::Undefined());
424     JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
425     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
426     // 4. Prepend O to items.
427     // 5. For each element E of items, do
428     for (int i = -1; i < argc; i++) {
429         if (i < 0) {
430             ele.Update(thisObjHandle.GetTaggedValue());
431         } else {
432             ele.Update(GetCallArg(argv, i));
433         }
434         if (!ele->IsSharedType()) {
435             auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
436             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
437         }
438         // a. Let spreadable be ? IsConcatSpreadable(E).
439         bool isSpreadable = ArrayHelper::IsConcatSpreadable(thread, ele);
440         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
441         // b. If spreadable is true, then
442         if (isSpreadable) {
443             // i. Let k be 0.
444             // ii. Let len be ? LengthOfArrayLike(E).
445             // iii. If n + len > 253 - 1, throw a TypeError exception.
446             int64_t len = ArrayHelper::GetArrayLength(thread, ele);
447             int64_t k = 0;
448             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
449             if (n + len > base::MAX_SAFE_INTEGER) {
450                 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
451             }
452 
453             if (ele->IsStableJSArray(thread)) {
454                 JSStableArray::Concat(thread, newArrayHandle, JSHandle<JSObject>::Cast(ele), k, n);
455                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
456             }
457             // iv. Repeat, while k < len,
458             while (k < len) {
459                 // 1. Let P be ToString(k).
460                 // 2. Let exists be HasProperty(E, P).
461                 // 3. If exists is true, then
462                 fromKey.Update(JSTaggedValue::ToString(thread, JSTaggedValue(k)));
463                 toKey.Update(JSTaggedValue(n));
464                 bool exists = JSTaggedValue::HasProperty(thread, ele, fromKey);
465                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
466                 if (exists) {
467                     // a. Let subElement be Get(E, P).
468                     JSHandle<JSTaggedValue> fromValHandle =
469                         JSSharedArray::FastGetPropertyByValue(thread, ele, fromKey);
470                     if (!fromValHandle->IsSharedType()) {
471                         auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
472                         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
473                     }
474                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
475                     // b. Perform ? CreateDataPropertyOrThrow(A, ! ToString(��(n)), subElement).
476                     JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValHandle, SCheckMode::SKIP);
477                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
478                 }
479                 // 4. Set n to n + 1.
480                 // 5. Set k to k + 1.
481                 n++;
482                 k++;
483             }
484         //c. Else
485         } else {
486             // ii. If n ≥ 253 - 1, throw a TypeError exception.
487             if (n >= base::MAX_SAFE_INTEGER) {
488                 THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
489             }
490             // iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(��(n)), E).
491             // iv. Set n to n + 1.
492             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, n, ele, SCheckMode::SKIP);
493             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
494             n++;
495         }
496     }
497     // 6. Perform ? Set(A, "length", ��(n), true).
498     JSHandle<JSTaggedValue> lenHandle(thread, JSTaggedValue(n));
499     JSSharedArray::LengthSetter(thread, newArrayHandle, lenHandle, true);
500     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
501 
502     // 7. Return A.
503     return newArrayHandle.GetTaggedValue();
504 }
505 
506 // 22.1.3.4 Array.prototype.entries ( )
Entries(EcmaRuntimeCallInfo * argv)507 JSTaggedValue BuiltinsSharedArray::Entries(EcmaRuntimeCallInfo *argv)
508 {
509     ASSERT(argv);
510     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Entries);
511     JSThread *thread = argv->GetThread();
512     [[maybe_unused]] EcmaHandleScope handleScope(thread);
513     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
514     if (!thisHandle->IsJSSharedArray()) {
515         auto error = ContainerError::BindError(thread, "The entries method cannot be bound.");
516         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
517     }
518     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
519     // 1. Let O be ToObject(this value).
520     // 2. ReturnIfAbrupt(O).
521     JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv));
522     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
523     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
524     // 3. Return CreateArrayIterator(O, "key+value").
525     JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY_AND_VALUE));
526     return iter.GetTaggedValue();
527 }
528 
529 // 22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] )
Fill(EcmaRuntimeCallInfo * argv)530 JSTaggedValue BuiltinsSharedArray::Fill(EcmaRuntimeCallInfo *argv)
531 {
532     ASSERT(argv);
533     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Fill);
534     JSThread *thread = argv->GetThread();
535     [[maybe_unused]] EcmaHandleScope handleScope(thread);
536 
537     // 1. Let O be ToObject(this value).
538     JSHandle<JSTaggedValue> thisObjVal = GetThis(argv);
539     if (!thisObjVal->IsJSSharedArray()) {
540         auto error = ContainerError::BindError(thread, "The fill method cannot be bound.");
541         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
542     }
543     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisObjVal);
544     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisObjVal);
545     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
546     if (thisObjVal->IsJSSharedArray()) {
547         bool isDictionary = thisObjHandle->GetJSHClass()->IsDictionaryElement();
548         if (isDictionary) {
549             uint32_t length = JSSharedArray::Cast(*thisObjHandle)->GetLength();
550             uint32_t size = thisObjHandle->GetNumberOfElements();
551             if (length - size > JSObject::MAX_GAP) {
552                 JSObject::TryOptimizeAsFastElements(thread, thisObjHandle);
553             }
554         }
555     }
556 
557     // 2. ReturnIfAbrupt(O).
558     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
559 
560     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
561     if (!value->IsSharedType()) {
562         auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
563         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
564     }
565     if (thisObjVal->IsTypedArray() || thisObjVal->IsSharedTypedArray()) {
566         ContentType contentType = JSHandle<JSTypedArray>::Cast(thisObjVal)->GetContentType();
567         if (contentType == ContentType::BigInt) {
568             value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, value));
569         } else {
570             value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToNumber(thread, value));
571         }
572         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
573     }
574 
575     // 3. Let len be ToLength(Get(O, "length")).
576     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
577     // 4. ReturnIfAbrupt(len).
578     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
579 
580     // 5. Let relativeStart be ToInteger(start).
581     JSHandle<JSTaggedValue> startArg = GetCallArg(argv, 1);
582     JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, startArg);
583     // 6. ReturnIfAbrupt(relativeStart).
584     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
585     double argStart = argStartTemp.GetNumber();
586     // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
587     int64_t start = 0;
588     if (argStart < 0) {
589         double tempStart = argStart + len;
590         start = tempStart > 0 ? tempStart : 0;
591     } else {
592         start = argStart < len ? argStart : len;
593     }
594 
595     // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
596     double argEnd = len;
597     JSHandle<JSTaggedValue> endArg = GetCallArg(argv, INDEX_TWO);
598     if (!endArg->IsUndefined()) {
599         JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, endArg);
600         // 9. ReturnIfAbrupt(relativeEnd).
601         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
602         argEnd = argEndTemp.GetNumber();
603     }
604 
605     // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
606     int64_t end = len;
607     if (argEnd < 0) {
608         double tempEnd = argEnd + len;
609         end = tempEnd > 0 ? tempEnd : 0;
610     } else {
611         end = argEnd < len ? argEnd : len;
612     }
613     // 11. Repeat, while k < final
614     //   a. Let Pk be ToString(k).
615     //   b. Let setStatus be Set(O, Pk, value, true).
616     //   c. ReturnIfAbrupt(setStatus).
617     //   d. Increase k by 1.
618 
619     if (thisObjVal->IsStableJSArray(thread) && !startArg->IsJSObject() && !endArg->IsJSObject()) {
620         auto opResult = JSStableArray::Fill(thread, thisObjHandle, value, start, end, len);
621         return opResult;
622     }
623 
624     if (thisObjVal->IsTypedArray() || thisObjVal->IsSharedTypedArray()) {
625         bool result = JSTypedArray::FastTypedArrayFill(thread, thisObjVal, value, start, end);
626         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
627         if (result) {
628             return thisObjHandle.GetTaggedValue();
629         }
630     }
631 
632     int64_t k = start;
633     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
634     while (k < end) {
635         key.Update(JSTaggedValue(k));
636         JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, key, value);
637         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
638         k++;
639     }
640 
641     // 12. Return O.
642     return thisObjHandle.GetTaggedValue();
643 }
644 
FilterUnStableJSArray(JSThread * thread,JSHandle<JSTaggedValue> & thisArgHandle,JSHandle<JSTaggedValue> & thisObjVal,int64_t k,int64_t len,uint32_t toIndex,JSHandle<JSObject> newArrayHandle,JSHandle<JSTaggedValue> & callbackFnHandle)645 JSTaggedValue BuiltinsSharedArray::FilterUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisArgHandle,
646     JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, uint32_t toIndex, JSHandle<JSObject> newArrayHandle,
647     JSHandle<JSTaggedValue> &callbackFnHandle)
648 {
649     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
650     const uint32_t argsLength = 3; // 3: «kValue, k, O»
651     JSTaggedValue callResult = GetTaggedBoolean(true);
652     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
653     JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined());
654     while (k < len) {
655         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k);
656         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
657         if (exists) {
658             JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
659             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
660             key.Update(JSTaggedValue(k));
661             EcmaRuntimeCallInfo *info =
662                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
663             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
664             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
665             callResult = JSFunction::Call(info);
666             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
667             if (callResult.ToBoolean()) {
668                 toIndexHandle.Update(JSTaggedValue(toIndex));
669                 JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toIndexHandle, kValue, SCheckMode::SKIP);
670                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
671                 toIndex++;
672             }
673         }
674         k++;
675     }
676     return newArrayHandle.GetTaggedValue();
677 }
678 
679 // 22.1.3.7 Array.prototype.filter ( callbackfn [ , thisArg ] )
Filter(EcmaRuntimeCallInfo * argv)680 JSTaggedValue BuiltinsSharedArray::Filter(EcmaRuntimeCallInfo *argv)
681 {
682     ASSERT(argv);
683     JSThread *thread = argv->GetThread();
684     BUILTINS_API_TRACE(thread, SharedArray, Filter);
685     [[maybe_unused]] EcmaHandleScope handleScope(thread);
686 
687     // 1. Let O be ToObject(this value).
688     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
689     if (!thisHandle->IsJSSharedArray()) {
690         auto error = ContainerError::BindError(thread, "The filter method cannot be bound.");
691         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
692     }
693     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
694     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
695     // 2. ReturnIfAbrupt(O).
696     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
697     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
698 
699     // 3. Let len be ToLength(Get(O, "length")).
700     uint64_t len = static_cast<uint64_t>(ArrayHelper::GetArrayLength(thread, thisObjVal));
701     // 4. ReturnIfAbrupt(len).
702     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
703 
704     // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
705     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
706     if (!callbackFnHandle->IsCallable()) {
707         THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
708     }
709 
710     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
711     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
712 
713     // 7. Let A be ArraySpeciesCreate(O, 0).
714     int32_t arrayLen = 0;
715     JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen));
716     // 8. ReturnIfAbrupt(A).
717     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
718     JSHandle<JSObject> newArrayHandle(thread, newArray);
719 
720     // 9. Let k be 0.
721     // 10. Let to be 0.
722     // 11. Repeat, while k < len
723     //   a. Let Pk be ToString(k).
724     //   b. Let kPresent be HasProperty(O, Pk).
725     //   c. ReturnIfAbrupt(kPresent).
726     //   d. If kPresent is true, then
727     //     i. Let kValue be Get(O, Pk).
728     //     ii. ReturnIfAbrupt(kValue).
729     //     iii. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)).
730     //     iv. ReturnIfAbrupt(selected).
731     //     v. If selected is true, then
732     //       1. Let status be CreateDataPropertyOrThrow (A, ToString(to), kValue).
733     //       2. ReturnIfAbrupt(status).
734     //       3. Increase to by 1.
735     //   e. Increase k by 1.
736     uint32_t toIndex = 0;
737     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
738     JSMutableHandle<JSTaggedValue> toIndexHandle(thread, JSTaggedValue::Undefined());
739     uint32_t k = 0;
740     if (thisObjVal->IsStableJSArray(thread)) {
741         JSStableArray::Filter(newArrayHandle, thisObjHandle, argv, k, toIndex);
742         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
743     }
744     auto opResult =
745         FilterUnStableJSArray(thread, thisArgHandle, thisObjVal, k, len, toIndex, newArrayHandle, callbackFnHandle);
746 
747     return opResult;
748 }
749 
750 // 22.1.3.8 Array.prototype.find ( predicate [ , thisArg ] )
Find(EcmaRuntimeCallInfo * argv)751 JSTaggedValue BuiltinsSharedArray::Find(EcmaRuntimeCallInfo *argv)
752 {
753     ASSERT(argv);
754     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Find);
755     JSThread *thread = argv->GetThread();
756     [[maybe_unused]] EcmaHandleScope handleScope(thread);
757 
758     // 1. Let O be ToObject(this value).
759     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
760     if (!thisHandle->IsJSSharedArray()) {
761         auto error = ContainerError::BindError(thread, "The find method cannot be bound.");
762         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
763     }
764     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
765     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
766     // 2. ReturnIfAbrupt(O).
767     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
768     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
769 
770     // 3. Let len be ToLength(Get(O, "length")).
771     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
772     // 4. ReturnIfAbrupt(len).
773     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
774 
775     // 5. If IsCallable(predicate) is false, throw a TypeError exception.
776     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
777     if (!callbackFnHandle->IsCallable()) {
778         THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
779     }
780 
781     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
782     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
783 
784     // 7. Let k be 0.
785     // 8. Repeat, while k < len
786     //   a. Let Pk be ToString(k).
787     //   b. Let kValue be Get(O, Pk).
788     //   c. ReturnIfAbrupt(kValue).
789     //   d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
790     //   e. ReturnIfAbrupt(testResult).
791     //   f. If testResult is true, return kValue.
792     //   g. Increase k by 1.
793     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
794     int64_t k = 0;
795     while (k < len) {
796         JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
797         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
798         key.Update(JSTaggedValue(k));
799         const uint32_t argsLength = 3; // 3: «kValue, k, O»
800         JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
801         EcmaRuntimeCallInfo *info =
802             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
803         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
804         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
805         JSTaggedValue callResult = JSFunction::Call(info);
806         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
807         if (callResult.ToBoolean()) {
808             return kValue.GetTaggedValue();
809         }
810         k++;
811     }
812 
813     // 9. Return undefined.
814     return JSTaggedValue::Undefined();
815 }
816 
817 // 22.1.3.9 Array.prototype.findIndex ( predicate [ , thisArg ] )
FindIndex(EcmaRuntimeCallInfo * argv)818 JSTaggedValue BuiltinsSharedArray::FindIndex(EcmaRuntimeCallInfo *argv)
819 {
820     ASSERT(argv);
821     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, FindIndex);
822     JSThread *thread = argv->GetThread();
823     [[maybe_unused]] EcmaHandleScope handleScope(thread);
824 
825     // 1. Let O be ToObject(this value).
826     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
827     if (!thisHandle->IsJSSharedArray()) {
828         auto error = ContainerError::BindError(thread, "The findIndex method cannot be bound.");
829         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
830     }
831     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
832     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
833     // 2. ReturnIfAbrupt(O).
834     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
835     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
836 
837     // 3. Let len be ToLength(Get(O, "length")).
838     uint64_t len = static_cast<uint64_t>(ArrayHelper::GetLength(thread, thisObjVal));
839     // 4. ReturnIfAbrupt(len).
840     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
841 
842     // 5. If IsCallable(predicate) is false, throw a TypeError exception.
843     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
844     if (!callbackFnHandle->IsCallable()) {
845         THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception());
846     }
847 
848     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
849     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
850 
851     // 7. Let k be 0.
852     // 8. Repeat, while k < len
853     //   a. Let Pk be ToString(k).
854     //   b. Let kValue be Get(O, Pk).
855     //   c. ReturnIfAbrupt(kValue).
856     //   d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)).
857     //   e. ReturnIfAbrupt(testResult).
858     //   f. If testResult is true, return k.
859     //   g. Increase k by 1.
860     uint32_t k = 0;
861     JSTaggedValue callResult = GetTaggedBoolean(true);
862     if (thisObjVal->IsStableJSArray(thread)) {
863         callResult = JSStableArray::HandleFindIndexOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k);
864         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
865         if (callResult.ToBoolean()) {
866             return GetTaggedDouble(k);
867         }
868     }
869     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
870     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
871     const uint32_t argsLength = 3; // 3: «kValue, k, O»
872     while (k < len) {
873         JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
874         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
875         key.Update(JSTaggedValue(k));
876         EcmaRuntimeCallInfo *info =
877             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
878         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
879         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
880         callResult = JSFunction::Call(info);
881         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
882         if (callResult.ToBoolean()) {
883             return GetTaggedDouble(k);
884         }
885         k++;
886     }
887 
888     // 9. Return -1.
889     return GetTaggedDouble(-1);
890 }
891 
892 // 22.1.3.10 Array.prototype.forEach ( callbackfn [ , thisArg ] )
ForEach(EcmaRuntimeCallInfo * argv)893 JSTaggedValue BuiltinsSharedArray::ForEach(EcmaRuntimeCallInfo *argv)
894 {
895     ASSERT(argv);
896     JSThread *thread = argv->GetThread();
897     BUILTINS_API_TRACE(thread, SharedArray, ForEach);
898     [[maybe_unused]] EcmaHandleScope handleScope(thread);
899 
900     // 1. Let O be ToObject(this value).
901     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
902     if (!thisHandle->IsJSSharedArray()) {
903         auto error = ContainerError::BindError(thread, "The forEach method cannot be bound.");
904         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
905     }
906     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
907     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
908     // 2. ReturnIfAbrupt(O).
909     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
910     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
911 
912     // 3. Let len be ToLength(Get(O, "length")).
913     uint64_t len = static_cast<uint64_t>(ArrayHelper::GetArrayLength(thread, thisObjVal));
914     // 4. ReturnIfAbrupt(len).
915     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
916 
917     // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
918     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
919     if (!callbackFnHandle->IsCallable()) {
920         THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
921     }
922 
923     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
924     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
925 
926     // 7. Let k be 0.
927     // 8. Repeat, while k < len
928     //   a. Let Pk be ToString(k).
929     //   b. Let kPresent be HasProperty(O, Pk).
930     //   c. ReturnIfAbrupt(kPresent).
931     //   d. If kPresent is true, then
932     //     i. Let kValue be Get(O, Pk).
933     //     ii. ReturnIfAbrupt(kValue).
934     //     iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
935     //     iv. ReturnIfAbrupt(funcResult).
936     //   e. Increase k by 1.
937     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
938     uint32_t k = 0;
939     if (thisObjVal->IsStableJSArray(thread)) {
940         JSStableArray::HandleforEachOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, len, k);
941         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
942     }
943     const uint32_t argsLength = 3; // 3: «kValue, k, O»
944     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
945     while (k < len) {
946         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k);
947         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
948         if (exists) {
949             JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
950             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
951             key.Update(JSTaggedValue(k));
952             EcmaRuntimeCallInfo *info =
953                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
954             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
955             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
956             JSTaggedValue funcResult = JSFunction::Call(info);
957             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
958         }
959         k++;
960     }
961 
962     // 9. Return undefined.
963     return JSTaggedValue::Undefined();
964 }
965 
IndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle)966 JSTaggedValue BuiltinsSharedArray::IndexOfSlowPath(
967     EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle)
968 {
969     // 1. Let O be ToObject(this value).
970     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
971     // 2. ReturnIfAbrupt(O).
972     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
973     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
974     // 3. Let len be ToLength(Get(O, "length")).
975     int64_t length = ArrayHelper::GetLength(thread, thisObjVal);
976     // 4. ReturnIfAbrupt(len).
977     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
978     // 5. If len is 0, return −1.
979     if (length == 0) {
980         return JSTaggedValue(-1);
981     }
982     // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0.
983     int64_t fromIndex = ArrayHelper::GetStartIndexFromArgs(thread, argv, 1, length);
984     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
985     return IndexOfSlowPath(argv, thread, thisObjVal, length, fromIndex);
986 }
987 
IndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisObjVal,int64_t length,int64_t fromIndex)988 JSTaggedValue BuiltinsSharedArray::IndexOfSlowPath(
989     EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle<JSTaggedValue> &thisObjVal,
990     int64_t length, int64_t fromIndex)
991 {
992     if (fromIndex >= length) {
993         return JSTaggedValue(-1);
994     }
995     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
996     JSHandle<JSTaggedValue> target = GetCallArg(argv, 0);
997     // 11. Repeat, while k < len
998     for (int64_t curIndex = fromIndex; curIndex < length; ++curIndex) {
999         keyHandle.Update(JSTaggedValue(curIndex));
1000         bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target);
1001         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1002         if (UNLIKELY(found)) {
1003             return JSTaggedValue(curIndex);
1004         }
1005     }
1006     // 12. Return -1.
1007     return JSTaggedValue(-1);
1008 }
1009 
1010 // 22.1.3.11 Array.prototype.indexOf ( searchElement [ , fromIndex ] )
IndexOf(EcmaRuntimeCallInfo * argv)1011 JSTaggedValue BuiltinsSharedArray::IndexOf(EcmaRuntimeCallInfo *argv)
1012 {
1013     ASSERT(argv);
1014     JSThread *thread = argv->GetThread();
1015     BUILTINS_API_TRACE(thread, SharedArray, IndexOf);
1016     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1017 
1018     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1019     if (!thisHandle->IsJSSharedArray()) {
1020         auto error = ContainerError::BindError(thread, "The indexOf method cannot be bound.");
1021         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1022     }
1023     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1024     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1025 
1026     JSTaggedValue opResult;
1027     if (thisHandle->IsStableJSArray(thread)) {
1028         auto error = ContainerError::BindError(thread, "The indexOf method not support stable array.");
1029         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1030     } else {
1031         opResult = IndexOfSlowPath(argv, thread, thisHandle);
1032     }
1033 
1034     return opResult;
1035 }
1036 
1037 // 22.1.3.12 Array.prototype.join (separator)
Join(EcmaRuntimeCallInfo * argv)1038 JSTaggedValue BuiltinsSharedArray::Join(EcmaRuntimeCallInfo *argv)
1039 {
1040     ASSERT(argv);
1041     JSThread *thread = argv->GetThread();
1042     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Join);
1043     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1044     if (!thisHandle->IsJSSharedArray()) {
1045         auto error = ContainerError::BindError(thread, "The join method cannot be bound.");
1046         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1047     }
1048     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1049     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1050     auto opResult = BuiltinsArray::Join(argv);
1051     return opResult;
1052 }
1053 
1054 // 22.1.3.13 Array.prototype.keys ( )
Keys(EcmaRuntimeCallInfo * argv)1055 JSTaggedValue BuiltinsSharedArray::Keys(EcmaRuntimeCallInfo *argv)
1056 {
1057     ASSERT(argv);
1058     JSThread *thread = argv->GetThread();
1059     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Keys);
1060     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1061     if (!thisHandle->IsJSSharedArray()) {
1062         auto error = ContainerError::BindError(thread, "The keys method cannot be bound.");
1063         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1064     }
1065     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1066     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1067     auto opResult = BuiltinsArray::Keys(argv);
1068     return opResult;
1069 }
1070 
1071 // 22.1.3.15 Array.prototype.map ( callbackfn [ , thisArg ] )
Map(EcmaRuntimeCallInfo * argv)1072 JSTaggedValue BuiltinsSharedArray::Map(EcmaRuntimeCallInfo *argv)
1073 {
1074     ASSERT(argv);
1075     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Map);
1076     JSThread *thread = argv->GetThread();
1077     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1078 
1079     // 1. Let O be ToObject(this value).
1080     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1081     if (!thisHandle->IsJSSharedArray()) {
1082         auto error = ContainerError::BindError(thread, "The map method cannot be bound.");
1083         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1084     }
1085     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1086     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1087     // 2. ReturnIfAbrupt(O).
1088     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1089     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1090 
1091     // 3. Let len be ToLength(Get(O, "length")).
1092     int64_t rawLen = ArrayHelper::GetArrayLength(thread, thisObjVal);
1093     // 4. ReturnIfAbrupt(len).
1094     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1095 
1096     // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
1097     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1098     if (!callbackFnHandle->IsCallable()) {
1099         THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
1100     }
1101 
1102     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
1103     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
1104 
1105     // 7. Let A be ArraySpeciesCreate(O, len).
1106     JSTaggedValue newArray =
1107         JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(rawLen)));
1108     // 8. ReturnIfAbrupt(A).
1109     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1110     if (!newArray.IsECMAObject()) {
1111         THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception());
1112     }
1113     JSHandle<JSObject> newArrayHandle(thread, newArray);
1114 
1115     // 9. Let k be 0.
1116     // 10. Repeat, while k < len
1117     //   a. Let Pk be ToString(k).
1118     //   b. Let kPresent be HasProperty(O, Pk).
1119     //   c. ReturnIfAbrupt(kPresent).
1120     //   d. If kPresent is true, then
1121     //     i. Let kValue be Get(O, Pk).
1122     //     ii. ReturnIfAbrupt(kValue).
1123     //     iii. Let mappedValue be Call(callbackfn, T, «kValue, k, O»).
1124     //     iv. ReturnIfAbrupt(mappedValue).
1125     //     v. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue).
1126     //     vi. ReturnIfAbrupt(status).
1127     //   e. Increase k by 1.
1128     uint32_t k = 0;
1129     uint32_t len = static_cast<uint32_t>(rawLen);
1130     if (thisObjVal->IsStableJSArray(thread)) {
1131         JSStableArray::Map(newArrayHandle, thisObjHandle, argv, k, len);
1132         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1133     }
1134     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1135     JSMutableHandle<JSTaggedValue> mapResultHandle(thread, JSTaggedValue::Undefined());
1136     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1137     const uint32_t argsLength = 3; // 3: «kValue, k, O»
1138     while (k < len) {
1139         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k);
1140         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1141         if (exists) {
1142             JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
1143             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1144             key.Update(JSTaggedValue(k));
1145             EcmaRuntimeCallInfo *info =
1146                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
1147             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1148             info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
1149             JSTaggedValue mapResult = JSFunction::Call(info);
1150             if (!mapResult.IsSharedType()) {
1151                 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1152                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1153             }
1154             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1155             mapResultHandle.Update(mapResult);
1156             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle, SCheckMode::SKIP);
1157             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1158         }
1159         k++;
1160     }
1161 
1162     // 11. Return A.
1163     return newArrayHandle.GetTaggedValue();
1164 }
1165 
1166 // 22.1.3.16 Array.prototype.pop ( )
Pop(EcmaRuntimeCallInfo * argv)1167 JSTaggedValue BuiltinsSharedArray::Pop(EcmaRuntimeCallInfo *argv)
1168 {
1169     ASSERT(argv);
1170     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Pop);
1171 
1172     JSThread *thread = argv->GetThread();
1173     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1174 
1175     // 1. Let O be ToObject(this value).
1176     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1177     if (!thisHandle->IsJSSharedArray()) {
1178         auto error = ContainerError::BindError(thread, "The pop method cannot be bound.");
1179         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1180     }
1181     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1182     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1183     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1184 
1185     JSTaggedValue opResult = PopInner(argv, thisHandle, thisObjHandle);
1186     return opResult;
1187 }
1188 
PopInner(EcmaRuntimeCallInfo * argv,JSHandle<JSTaggedValue> & thisHandle,JSHandle<JSObject> & thisObjHandle)1189 JSTaggedValue BuiltinsSharedArray::PopInner(EcmaRuntimeCallInfo *argv, JSHandle<JSTaggedValue> &thisHandle,
1190                                             JSHandle<JSObject> &thisObjHandle)
1191 {
1192     JSThread *thread = argv->GetThread();
1193     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1194 
1195     // 1. Let O be ToObject(this value).
1196     if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) {
1197         return JSStableArray::Pop(JSHandle<JSSharedArray>::Cast(thisHandle), argv);
1198     }
1199 
1200     // 2. ReturnIfAbrupt(O).
1201     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1202     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1203 
1204     // 3. Let len be ToLength(Get(O, "length")).
1205     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1206     // 4. ReturnIfAbrupt(len).
1207     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1208     // 5. If len is zero,
1209     //   a. Let setStatus be Set(O, "length", 0, true).
1210     //   b. ReturnIfAbrupt(setStatus).
1211     //   c. Return undefined.
1212     if (len == 0) {
1213         JSHandle<JSTaggedValue> lengthValue(thread, JSTaggedValue(0));
1214         JSSharedArray::LengthSetter(thread, thisObjHandle, lengthValue, true);
1215         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1216         return JSTaggedValue::Undefined();
1217     }
1218 
1219     // 6. Else len > 0,
1220     //   a. Let newLen be len–1.
1221     //   b. Let indx be ToString(newLen).
1222     //   c. Let element be Get(O, indx).
1223     //   d. ReturnIfAbrupt(element).
1224     //   e. Let deleteStatus be DeletePropertyOrThrow(O, indx).
1225     //   f. ReturnIfAbrupt(deleteStatus).
1226     //   g. Let setStatus be Set(O, "length", newLen, true).
1227     //   h. ReturnIfAbrupt(setStatus).
1228     //   i. Return element.
1229     int64_t newLen = len - 1;
1230     JSHandle<JSTaggedValue> indexHandle(thread, JSTaggedValue(newLen));
1231     JSHandle<JSTaggedValue> element =
1232         JSTaggedValue::GetProperty(thread, thisObjVal, indexHandle, SCheckMode::SKIP).GetValue();
1233     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1234     JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, indexHandle);
1235     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1236     JSSharedArray::LengthSetter(thread, thisObjHandle, indexHandle, true);
1237     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1238 
1239     return element.GetTaggedValue();
1240 }
1241 
1242 // 22.1.3.17 Array.prototype.push ( ...items )
Push(EcmaRuntimeCallInfo * argv)1243 JSTaggedValue BuiltinsSharedArray::Push(EcmaRuntimeCallInfo *argv)
1244 {
1245     ASSERT(argv);
1246     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Push);
1247     JSThread *thread = argv->GetThread();
1248     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1249     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1250     if (!thisHandle->IsJSSharedArray()) {
1251         auto error = ContainerError::BindError(thread, "The push method cannot be bound.");
1252         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1253     }
1254     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1255     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1256     if (thisHandle->IsStableJSArray(thread)) {
1257         auto opResult = JSStableArray::Push(JSHandle<JSSharedArray>::Cast(thisHandle), argv);
1258         return opResult;
1259     }
1260     // 6. Let argCount be the number of elements in items.
1261     uint32_t argc = argv->GetArgsNumber();
1262 
1263     // 1. Let O be ToObject(this value).
1264     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1265     // 2. ReturnIfAbrupt(O).
1266     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1267     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1268 
1269     // 3. Let len be ToLength(Get(O, "length")).
1270     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1271     // 4. ReturnIfAbrupt(len).
1272     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1273     // 7. If len + argCount > 253-1, throw a TypeError exception.
1274     if ((len + static_cast<int64_t>(argc)) > base::MAX_SAFE_INTEGER) {
1275         THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1276     }
1277 
1278     // 8. Repeat, while items is not empty
1279     //   a. Remove the first element from items and let E be the value of the element.
1280     //   b. Let setStatus be Set(O, ToString(len), E, true).
1281     //   c. ReturnIfAbrupt(setStatus).
1282     //   d. Let len be len+1.
1283     uint32_t k = 0;
1284     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1285     while (k < argc) {
1286         key.Update(JSTaggedValue(len));
1287         JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k);
1288         if (!kValue->IsSharedType()) {
1289             auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1290             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1291         }
1292         JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, key, kValue);
1293         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1294         k++;
1295         len++;
1296     }
1297 
1298     // 9. Let setStatus be Set(O, "length", len, true).
1299     key.Update(JSTaggedValue(len));
1300     JSSharedArray::LengthSetter(thread, thisObjHandle, key, true);
1301     // 10. ReturnIfAbrupt(setStatus).
1302     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1303 
1304     // 11. Return len.
1305     return GetTaggedDouble(len);
1306 }
1307 
ReduceUnStableJSArray(JSThread * thread,JSHandle<JSTaggedValue> & thisHandle,JSHandle<JSTaggedValue> & thisObjVal,int64_t k,int64_t len,JSMutableHandle<JSTaggedValue> & accumulator,JSHandle<JSTaggedValue> & callbackFnHandle)1308 JSTaggedValue BuiltinsSharedArray::ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle,
1309     JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator,
1310     JSHandle<JSTaggedValue> &callbackFnHandle)
1311 {
1312     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
1313     JSTaggedValue callResult = JSTaggedValue::Undefined();
1314     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1315     while (k < len) {
1316         bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k));
1317         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1318         if (exists) {
1319             JSHandle<JSTaggedValue> kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
1320             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1321             key.Update(JSTaggedValue(k));
1322             JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
1323             const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
1324             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
1325             EcmaRuntimeCallInfo *info =
1326                 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
1327             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1328             info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(),
1329                 thisObjVal.GetTaggedValue());
1330             callResult = JSFunction::Call(info);
1331             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1332             accumulator.Update(callResult);
1333         }
1334         k++;
1335     }
1336     return accumulator.GetTaggedValue();
1337 }
1338 
1339 // 22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] )
Reduce(EcmaRuntimeCallInfo * argv)1340 JSTaggedValue BuiltinsSharedArray::Reduce(EcmaRuntimeCallInfo *argv)
1341 {
1342     ASSERT(argv);
1343     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Reduce);
1344     JSThread *thread = argv->GetThread();
1345     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1346 
1347     uint32_t argc = argv->GetArgsNumber();
1348     // 1. Let O be ToObject(this value).
1349     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1350     if (!thisHandle->IsJSSharedArray()) {
1351         auto error = ContainerError::BindError(thread, "The reduce method cannot be bound.");
1352         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1353     }
1354     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1355     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1356     // 2. ReturnIfAbrupt(O).
1357     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1358     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1359 
1360     // 3. Let len be ToLength(Get(O, "length")).
1361     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
1362     // 4. ReturnIfAbrupt(len).
1363     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1364 
1365     // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
1366     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1367     if (!callbackFnHandle->IsCallable()) {
1368         THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
1369     }
1370 
1371     // 6. If len is 0 and initialValue is not present, throw a TypeError exception.
1372     if (len == 0 && argc < 2) {  // 2:2 means the number of parameters
1373         THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1374     }
1375 
1376     // 7. Let k be 0.
1377     // 8. If initialValue is present, then
1378     //   a. Set accumulator to initialValue.
1379     // 9. Else initialValue is not present,
1380     //   a. Let kPresent be false.
1381     //   b. Repeat, while kPresent is false and k < len
1382     //     i. Let Pk be ToString(k).
1383     //     ii. Let kPresent be HasProperty(O, Pk).
1384     //     iii. ReturnIfAbrupt(kPresent).
1385     //     iv. If kPresent is true, then
1386     //       1. Let accumulator be Get(O, Pk).
1387     //       2. ReturnIfAbrupt(accumulator).
1388     //     v. Increase k by 1.
1389     //   c. If kPresent is false, throw a TypeError exception.
1390     int64_t k = 0;
1391     JSMutableHandle<JSTaggedValue> accumulator(thread, JSTaggedValue::Undefined());
1392     if (argc == 2) {  // 2:2 means the number of parameters
1393         accumulator.Update(GetCallArg(argv, 1).GetTaggedValue());
1394     } else {
1395         bool kPresent = false;
1396         while (!kPresent && k < len) {
1397             kPresent = (thisHandle->IsTypedArray() || thisHandle->IsSharedTypedArray() ||
1398                JSTaggedValue::HasProperty(thread, thisObjVal, k));
1399             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1400             if (kPresent) {
1401                 accumulator.Update(JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue());
1402                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1403             }
1404             k++;
1405         }
1406         if (!kPresent) {
1407             THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception());
1408         }
1409     }
1410 
1411     if (thisObjVal->IsStableJSArray(thread)) {
1412         JSStableArray::Reduce(thread, thisObjHandle, callbackFnHandle, accumulator, k, len);
1413         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1414     }
1415     auto opResult = ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len, accumulator, callbackFnHandle);
1416     return opResult;
1417 }
1418 
1419 // 22.1.3.21 Array.prototype.shift ( )
Shift(EcmaRuntimeCallInfo * argv)1420 JSTaggedValue BuiltinsSharedArray::Shift(EcmaRuntimeCallInfo *argv)
1421 {
1422     ASSERT(argv);
1423     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Shift);
1424     JSThread *thread = argv->GetThread();
1425     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1426 
1427     // 1. Let O be ToObject(this value).
1428     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1429     if (!thisHandle->IsJSSharedArray()) {
1430         auto error = ContainerError::BindError(thread, "The shift method cannot be bound.");
1431         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1432     }
1433     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1434     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1435     // 2. ReturnIfAbrupt(O).
1436     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1437     if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) {
1438         auto opResult = JSStableArray::Shift(JSHandle<JSSharedArray>::Cast(thisHandle), argv);
1439         return opResult;
1440     }
1441     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1442 
1443     // 3. Let len be ToLength(Get(O, "length")).
1444     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1445     // 4. ReturnIfAbrupt(len).
1446     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1447     // 5. If len is zero, then
1448     //   a. Let setStatus be Set(O, "length", 0, true).
1449     //   b. ReturnIfAbrupt(setStatus).
1450     //   c. Return undefined.
1451     if (len == 0) {
1452         JSHandle<JSTaggedValue> zeroLenHandle(thread, JSTaggedValue(len));
1453         JSSharedArray::LengthSetter(thread, thisObjHandle, zeroLenHandle, false);
1454         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1455         return JSTaggedValue::Undefined();
1456     }
1457 
1458     // 6. Let first be Get(O, "0").
1459     JSHandle<JSTaggedValue> firstKey(thread, JSTaggedValue(0));
1460     JSHandle<JSTaggedValue> firstValue =
1461         JSTaggedValue::GetProperty(thread, thisObjVal, firstKey, SCheckMode::SKIP).GetValue();
1462     // 7. ReturnIfAbrupt(first).
1463     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1464 
1465     // 8. Let k be 1.
1466     // 9. Repeat, while k < len
1467     //   a. Let from be ToString(k).
1468     //   b. Let to be ToString(k–1).
1469     //   c. Let fromPresent be HasProperty(O, from).
1470     //   d. ReturnIfAbrupt(fromPresent).
1471     //   e. If fromPresent is true, then
1472     //     i. Let fromVal be Get(O, from).
1473     //     ii. ReturnIfAbrupt(fromVal).
1474     //     iii. Let setStatus be Set(O, to, fromVal, true).
1475     //     iv. ReturnIfAbrupt(setStatus).
1476     //   f. Else fromPresent is false,
1477     //     i. Let deleteStatus be DeletePropertyOrThrow(O, to).
1478     //     ii. ReturnIfAbrupt(deleteStatus).
1479     //   g. Increase k by 1.
1480     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
1481     int64_t k = 1;
1482     while (k < len) {
1483         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k);
1484         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1485         if (exists) {
1486             JSHandle<JSTaggedValue> fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
1487             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1488             JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, k - 1, fromValue);
1489             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1490         } else {
1491             toKey.Update(JSTaggedValue(k - 1));
1492             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
1493             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1494         }
1495         k++;
1496     }
1497     // 10. Let deleteStatus be DeletePropertyOrThrow(O, ToString(len–1)).
1498     JSHandle<JSTaggedValue> deleteKey(thread, JSTaggedValue(len - 1));
1499     JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey);
1500     // 11. ReturnIfAbrupt(deleteStatus).
1501     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1502 
1503     // 12. Let setStatus be Set(O, "length", len–1, true).
1504     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(len - 1));
1505     JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
1506     // 13. ReturnIfAbrupt(setStatus).
1507     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1508 
1509     // 14. Return first.
1510     return firstValue.GetTaggedValue();
1511 }
1512 
1513 // 22.1.3.22 Array.prototype.slice (start, end)
Slice(EcmaRuntimeCallInfo * argv)1514 JSTaggedValue BuiltinsSharedArray::Slice(EcmaRuntimeCallInfo *argv)
1515 {
1516     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Slice);
1517     ASSERT(argv);
1518     JSThread *thread = argv->GetThread();
1519     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1520 
1521     // 1. Let O be ToObject(this value).
1522     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1523     if (!thisHandle->IsJSSharedArray()) {
1524         auto error = ContainerError::BindError(thread, "The slice method cannot be bound.");
1525         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1526     }
1527     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1528     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1529     // 2. ReturnIfAbrupt(O).
1530     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1531     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1532 
1533     // 3. Let len be ToLength(Get(O, "length")).
1534     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1535     // 4. ReturnIfAbrupt(len).
1536     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1537 
1538     JSHandle<JSTaggedValue> msg0 = GetCallArg(argv, 0);
1539     double argStart;
1540     if (msg0->IsInt()) {
1541         argStart = msg0->GetInt();
1542     } else {
1543         // 5. Let relativeStart be ToInteger(start).
1544         JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0);
1545         // 6. ReturnIfAbrupt(relativeStart).
1546         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1547         argStart = argStartTemp.GetNumber();
1548     }
1549 
1550     // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
1551     int64_t k = 0;
1552     if (argStart < 0) {
1553         double tempStart = len + argStart;
1554         k = tempStart > 0 ? tempStart : 0;
1555     } else {
1556         k = argStart < len ? argStart : len;
1557     }
1558 
1559     // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
1560     // 9. ReturnIfAbrupt(relativeEnd).
1561     // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
1562     JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
1563     double argEnd = len;
1564     if (!msg1->IsUndefined()) {
1565         if (msg1->IsInt()) {
1566             argEnd = msg1->GetInt();
1567         } else {
1568             JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, msg1);
1569             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1570             argEnd = argEndTemp.GetNumber();
1571         }
1572     }
1573     int64_t final = 0;
1574     if (argEnd < 0) {
1575         double tempFinal = len + argEnd;
1576         final = tempFinal > 0 ? tempFinal : 0;
1577     } else {
1578         final = argEnd < len ? argEnd : len;
1579     }
1580     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1581 
1582     // 11. Let count be max(final – k, 0).
1583     int64_t count = final > k ? (final - k) : 0;
1584 
1585     if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor()
1586         && JSObject::GetPrototype(thisObjHandle).IsJSArray()) {
1587         auto opResult = JSStableArray::Slice(thread, thisObjHandle, k, count);
1588         return opResult;
1589     }
1590 
1591     // 12. Let A be ArraySpeciesCreate(O, count).
1592     JSTaggedValue newArray =
1593         JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast<double>(count)));
1594     // 13. ReturnIfAbrupt(A).
1595     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1596     if (count == 0) {
1597         return newArray;
1598     }
1599     JSHandle<JSObject> newArrayHandle(thread, newArray);
1600 
1601     // 14. Let n be 0.
1602     // 15. Repeat, while k < final
1603     //   a. Let Pk be ToString(k).
1604     //   b. Let kPresent be HasProperty(O, Pk).
1605     //   c. ReturnIfAbrupt(kPresent).
1606     //   d. If kPresent is true, then
1607     //     i. Let kValue be Get(O, Pk).
1608     //     ii. ReturnIfAbrupt(kValue).
1609     //     iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue ).
1610     //     iv. ReturnIfAbrupt(status).
1611     //   e. Increase k by 1.
1612     //   f. Increase n by 1.
1613     int64_t n = 0;
1614     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1615     JSMutableHandle<JSTaggedValue> nKey(thread, JSTaggedValue::Undefined());
1616     while (k < final) {
1617         key.Update(JSTaggedValue(k));
1618         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, key);
1619         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1620         if (exists) {
1621             nKey.Update(JSTaggedValue(n));
1622             JSHandle<JSTaggedValue> kValueHandle = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, key);
1623             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1624             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, nKey, kValueHandle, SCheckMode::SKIP);
1625             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1626         }
1627         k++;
1628         n++;
1629     }
1630 
1631     // 16. Let setStatus be Set(A, "length", n, true).
1632     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(n));
1633     JSSharedArray::LengthSetter(thread, newArrayHandle, newLenHandle, true);
1634     // 17. ReturnIfAbrupt(setStatus).
1635     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1636 
1637     // 18. Return A.
1638     return newArrayHandle.GetTaggedValue();
1639 }
1640 
1641 // 22.1.3.24 Array.prototype.sort (comparefn)
Sort(EcmaRuntimeCallInfo * argv)1642 JSTaggedValue BuiltinsSharedArray::Sort(EcmaRuntimeCallInfo *argv)
1643 {
1644     ASSERT(argv);
1645     JSThread *thread = argv->GetThread();
1646     BUILTINS_API_TRACE(thread, SharedArray, Sort);
1647     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1648 
1649     // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
1650     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1651     if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
1652         THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
1653     }
1654 
1655     // 2. Let obj be ToObject(this value).
1656     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1657     if (!thisHandle->IsJSSharedArray()) {
1658         auto error = ContainerError::BindError(thread, "The sort method cannot be bound.");
1659         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1660     }
1661     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1662     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1663     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1664 
1665     // Array sort
1666     if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) {
1667         JSStableArray::Sort(thread, thisObjHandle, callbackFnHandle);
1668     } else {
1669         JSSharedArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle);
1670         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1671     }
1672     return thisObjHandle.GetTaggedValue();
1673 }
1674 
1675 // 22.1.3.25 Array.prototype.splice (start, deleteCount , ...items )
1676 // NOLINTNEXTLINE(readability-function-size)
Splice(EcmaRuntimeCallInfo * argv)1677 JSTaggedValue BuiltinsSharedArray::Splice(EcmaRuntimeCallInfo *argv)
1678 {
1679     ASSERT(argv);
1680     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Splice);
1681     JSThread *thread = argv->GetThread();
1682     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1683     uint32_t argc = argv->GetArgsNumber();
1684     // 1. Let O be ToObject(this value).
1685     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1686     if (!thisHandle->IsJSSharedArray()) {
1687         auto error = ContainerError::BindError(thread, "The splice method cannot be bound.");
1688         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1689     }
1690     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1691     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(
1692         thread, thisHandle);
1693     // 2. ReturnIfAbrupt(O).
1694     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1695     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1696     // 3. Let len be ToLength(Get(O, "length")).
1697     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1698     // 4. ReturnIfAbrupt(len).
1699     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1700     // 5. Let relativeStart be ToInteger(start).
1701     int64_t start = 0;
1702     int64_t insertCount = 0;
1703     int64_t actualDeleteCount = 0;
1704     int64_t end = len;
1705     double argStart = 0;
1706     if (argc > 0) {
1707         JSHandle<JSTaggedValue> msg0 = GetCallArg(argv, 0);
1708         JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0);
1709         // 6. ReturnIfAbrupt(relativeStart).
1710         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1711         argStart = argStartTemp.GetNumber();
1712         // 7. If relativeStart < 0, let actualStart be max((len + relativeStart),0); else let actualStart be
1713         // min(relativeStart, len).
1714         if (argStart < 0) {
1715             double tempStart = argStart + len;
1716             start = tempStart > 0 ? tempStart : 0;
1717         } else {
1718             start = argStart < end ? argStart : end;
1719         }
1720         actualDeleteCount = len - start;
1721     }
1722     // 8. If the number of actual arguments is 0, then
1723     //   a. Let insertCount be 0.
1724     //   b. Let actualDeleteCount be 0.
1725     // 9. Else if the number of actual arguments is 1, then
1726     //   a. Let insertCount be 0.
1727     //   b. Let actualDeleteCount be len – actualStart.
1728     // 10. Else,
1729     //   a. Let insertCount be the number of actual arguments minus 2.
1730     //   b. Let dc be ToInteger(deleteCount).
1731     //   c. ReturnIfAbrupt(dc).
1732     //   d. Let actualDeleteCount be min(max(dc,0), len – actualStart).
1733     if (argc > 1) {
1734         insertCount = argc - 2;  // 2:2 means there are two arguments before the insert items.
1735         JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
1736         JSTaggedNumber argDeleteCount = JSTaggedValue::ToInteger(thread, msg1);
1737         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1738         double deleteCount = argDeleteCount.GetNumber();
1739         deleteCount = deleteCount > 0 ? deleteCount : 0;
1740         actualDeleteCount = deleteCount < (len - start) ? deleteCount : len - start;
1741     }
1742     // 11. If len+insertCount−actualDeleteCount > 253-1, throw a TypeError exception.
1743     if (len + insertCount - actualDeleteCount > base::MAX_SAFE_INTEGER) {
1744         THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1745     }
1746     // 12. Let A be ArraySpeciesCreate(O, actualDeleteCount).
1747     JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(
1748         thread, thisObjHandle, JSTaggedNumber(static_cast<double>(actualDeleteCount)));
1749     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1750     JSHandle<JSObject> newArrayHandle(thread, newArray);
1751     if (thisHandle->IsStableJSArray(thread)) {
1752         return JSStableArray::Splice(JSHandle<JSSharedArray>::Cast(thisHandle), argv, start, insertCount,
1753             actualDeleteCount, newArrayHandle, len);
1754     }
1755     // 14. Let k be 0.
1756     // 15. Repeat, while k < actualDeleteCount
1757     //   a. Let from be ToString(actualStart+k).
1758     //   b. Let fromPresent be HasProperty(O, from).
1759     //   d. If fromPresent is true, then
1760     //     i. Let fromValue be Get(O, from).
1761     //     iii. Let status be CreateDataPropertyOrThrow(A, ToString(k), fromValue).
1762     //   e. Increase k by 1.
1763     JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
1764     JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
1765     int64_t k = 0;
1766     while (k < actualDeleteCount) {
1767         int64_t from = start + k;
1768         fromKey.Update(JSTaggedValue(from));
1769         bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
1770         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1771         if (exists) {
1772             JSHandle<JSTaggedValue> fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
1773             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1774             toKey.Update(JSTaggedValue(k));
1775             if (newArrayHandle->IsJSProxy()) {
1776                 toKey.Update(JSTaggedValue::ToString(thread, toKey).GetTaggedValue());
1777                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1778             }
1779             JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue);
1780             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1781         }
1782         k++;
1783     }
1784     // 16. Let setStatus be Set(A, "length", actualDeleteCount, true).
1785     JSHandle<JSTaggedValue> deleteCountHandle(thread, JSTaggedValue(actualDeleteCount));
1786     JSSharedArray::LengthSetter(thread, newArrayHandle, deleteCountHandle, true);
1787     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1788     // 19. Let itemCount be the number of elements in items.
1789     // 20. If itemCount < actualDeleteCount, then
1790     //   a. Let k be actualStart.
1791     //   b. Repeat, while k < (len – actualDeleteCount)
1792     //     i. Let from be ToString(k+actualDeleteCount).
1793     //     ii. Let to be ToString(k+itemCount).
1794     //     iii. Let fromPresent be HasProperty(O, from).
1795     //     v. If fromPresent is true, then
1796     //       1. Let fromValue be Get(O, from).
1797     //       3. Let setStatus be Set(O, to, fromValue, true).
1798     //     vi. Else fromPresent is false,
1799     //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
1800     //     vii. Increase k by 1.
1801     //   c. Let k be len.
1802     //   d. Repeat, while k > (len – actualDeleteCount + itemCount)
1803     //     i. Let deleteStatus be DeletePropertyOrThrow(O, ToString(k–1)).
1804     //     iii. Decrease k by 1.
1805     if (insertCount < actualDeleteCount) {
1806         k = start;
1807         while (k < len - actualDeleteCount) {
1808             fromKey.Update(JSTaggedValue(k + actualDeleteCount));
1809             toKey.Update(JSTaggedValue(k + insertCount));
1810             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
1811             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1812             if (exists) {
1813                 JSHandle<JSTaggedValue> fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
1814                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1815                 JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
1816                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1817             } else {
1818                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
1819                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1820             }
1821             k++;
1822         }
1823         k = len;
1824         JSMutableHandle<JSTaggedValue> deleteKey(thread, JSTaggedValue::Undefined());
1825         while (k > len - actualDeleteCount + insertCount) {
1826             deleteKey.Update(JSTaggedValue(k - 1));
1827             JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey);
1828             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1829             k--;
1830         }
1831     } else if (insertCount > actualDeleteCount) {
1832         // 21. Else if itemCount > actualDeleteCount, then
1833         //   a. Let k be (len – actualDeleteCount).
1834         //   b. Repeat, while k > actualStart
1835         //     i. Let from be ToString(k + actualDeleteCount – 1).
1836         //     ii. Let to be ToString(k + itemCount – 1)
1837         //     iii. Let fromPresent be HasProperty(O, from).
1838         //     iv. ReturnIfAbrupt(fromPresent).
1839         //     v. If fromPresent is true, then
1840         //       1. Let fromValue be Get(O, from).
1841         //       2. ReturnIfAbrupt(fromValue).
1842         //       3. Let setStatus be Set(O, to, fromValue, true).
1843         //       4. ReturnIfAbrupt(setStatus).
1844         //     vi. Else fromPresent is false,
1845         //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
1846         //       2. ReturnIfAbrupt(deleteStatus).
1847         //     vii. Decrease k by 1.
1848         k = len - actualDeleteCount;
1849         while (k > start) {
1850             fromKey.Update(JSTaggedValue(k + actualDeleteCount - 1));
1851             toKey.Update(JSTaggedValue(k + insertCount - 1));
1852             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
1853             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1854             if (exists) {
1855                 JSHandle<JSTaggedValue> fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
1856                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1857                 JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
1858                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1859             } else {
1860                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
1861                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1862             }
1863             k--;
1864         }
1865     }
1866     // 22. Let k be actualStart.
1867     k = start;
1868     // 23. Repeat, while items is not empty
1869     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1870     for (uint32_t i = 2; i < argc; i++) {
1871         JSHandle<JSTaggedValue> itemValue = GetCallArg(argv, i);
1872         if (!itemValue->IsSharedType()) {
1873             auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
1874             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1875         }
1876         key.Update(JSTaggedValue(k));
1877         JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, key, itemValue);
1878         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1879         k++;
1880     }
1881     // 24. Let setStatus be Set(O, "length", len – actualDeleteCount + itemCount, true).
1882     int64_t newLen = len - actualDeleteCount + insertCount;
1883     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
1884     JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
1885     // 25. ReturnIfAbrupt(setStatus).
1886     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1887     // 26. Return A.
1888     return newArrayHandle.GetTaggedValue();
1889 }
1890 
1891 // 22.1.3.27 Array.prototype.toString ( )
ToString(EcmaRuntimeCallInfo * argv)1892 JSTaggedValue BuiltinsSharedArray::ToString(EcmaRuntimeCallInfo *argv)
1893 {
1894     ASSERT(argv);
1895     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ToString);
1896     JSThread *thread = argv->GetThread();
1897     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1898     auto ecmaVm = thread->GetEcmaVM();
1899 
1900     // 1. Let array be ToObject(this value).
1901     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1902     if (!thisHandle->IsJSSharedArray()) {
1903         auto error = ContainerError::BindError(thread, "The toString method cannot be bound.");
1904         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1905     }
1906     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1907     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
1908     // 2. ReturnIfAbrupt(array).
1909     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1910     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1911 
1912     // 3. Let func be Get(array, "join").
1913     JSHandle<JSTaggedValue> joinKey = thread->GlobalConstants()->GetHandledJoinString();
1914     JSHandle<JSTaggedValue> callbackFnHandle = JSTaggedValue::GetProperty(thread, thisObjVal, joinKey).GetValue();
1915 
1916     // 4. ReturnIfAbrupt(func).
1917     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1918 
1919     // 5. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString% (19.1.3.6).
1920     if (!callbackFnHandle->IsCallable()) {
1921         JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
1922         JSHandle<JSTaggedValue> objectPrototype = env->GetObjectFunctionPrototype();
1923         JSHandle<JSTaggedValue> toStringKey = thread->GlobalConstants()->GetHandledToStringString();
1924         callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue();
1925         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1926     }
1927     const uint32_t argsLength = argv->GetArgsNumber();
1928     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1929     EcmaRuntimeCallInfo *info =
1930         EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength);
1931     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1932     info->SetCallArg(argsLength, 0, argv, 0);
1933     auto opResult = JSFunction::Call(info);
1934     return opResult;
1935 }
1936 
1937 // 22.1.3.28 Array.prototype.unshift ( ...items )
Unshift(EcmaRuntimeCallInfo * argv)1938 JSTaggedValue BuiltinsSharedArray::Unshift(EcmaRuntimeCallInfo *argv)
1939 {
1940     ASSERT(argv);
1941     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Unshift);
1942     JSThread *thread = argv->GetThread();
1943     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1944 
1945     // 5. Let argCount be the number of actual arguments.
1946     int64_t argc = argv->GetArgsNumber();
1947 
1948     // 1. Let O be ToObject(this value).
1949     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1950     if (!thisHandle->IsJSSharedArray()) {
1951         auto error = ContainerError::BindError(thread, "The unshift method cannot be bound.");
1952         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1953     }
1954     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1955     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
1956     // 2. ReturnIfAbrupt(O).
1957     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1958     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1959 
1960     // 3. Let len be ToLength(Get(O, "length")).
1961     int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal);
1962     // 4. ReturnIfAbrupt(len).
1963     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1964 
1965     // 6. If argCount > 0, then
1966     //   a. If len+ argCount > 253-1, throw a TypeError exception.
1967     //   b. Let k be len.
1968     //   c. Repeat, while k > 0,
1969     //     i. Let from be ToString(k–1).
1970     //     ii. Let to be ToString(k+argCount –1).
1971     //     iii. Let fromPresent be HasProperty(O, from).
1972     //     iv. ReturnIfAbrupt(fromPresent).
1973     //     v. If fromPresent is true, then
1974     //       1. Let fromValue be Get(O, from).
1975     //       2. ReturnIfAbrupt(fromValue).
1976     //       3. Let setStatus be Set(O, to, fromValue, true).
1977     //       4. ReturnIfAbrupt(setStatus).
1978     //     vi. Else fromPresent is false,
1979     //       1. Let deleteStatus be DeletePropertyOrThrow(O, to).
1980     //       2. ReturnIfAbrupt(deleteStatus).
1981     //     vii. Decrease k by 1.
1982     if (argc > 0) {
1983         if (len + argc > base::MAX_SAFE_INTEGER) {
1984             THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception());
1985         }
1986         JSMutableHandle<JSTaggedValue> fromKey(thread, JSTaggedValue::Undefined());
1987         JSMutableHandle<JSTaggedValue> toKey(thread, JSTaggedValue::Undefined());
1988         int64_t k = len;
1989         while (k > 0) {
1990             fromKey.Update(JSTaggedValue(k - 1));
1991             toKey.Update(JSTaggedValue(k + argc - 1));
1992             bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey);
1993             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1994             if (exists) {
1995                 JSHandle<JSTaggedValue> fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, fromKey);
1996                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1997                 JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue);
1998                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1999             } else {
2000                 JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey);
2001                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2002             }
2003             k--;
2004         }
2005         //   d. Let j be 0.
2006         //   e. Let items be a List whose elements are, in left to right order, the arguments that were passed to this
2007         //   function invocation.
2008         //   f. Repeat, while items is not empty
2009         //     i. Remove the first element from items and let E be the value of that element.
2010         //     ii. Let setStatus be Set(O, ToString(j), E, true).
2011         //     iii. ReturnIfAbrupt(setStatus).
2012         //     iv. Increase j by 1.
2013         int64_t j = 0;
2014         while (j < argc) {
2015             toKey.Update(JSTaggedValue(j));
2016             JSHandle<JSTaggedValue> toValue = GetCallArg(argv, j);
2017             if (!toValue->IsSharedType()) {
2018                 auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
2019                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2020             }
2021             JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, toValue);
2022             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2023             j++;
2024         }
2025     }
2026 
2027     // 7. Let setStatus be Set(O, "length", len+argCount, true).
2028     int64_t newLen = len + argc;
2029     JSHandle<JSTaggedValue> newLenHandle(thread, JSTaggedValue(newLen));
2030     JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true);
2031     // 8. ReturnIfAbrupt(setStatus).
2032     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2033 
2034     // 9. Return len+argCount.
2035     return GetTaggedDouble(newLen);
2036 }
2037 
2038 // 22.1.3.29 Array.prototype.values ( )
Values(EcmaRuntimeCallInfo * argv)2039 JSTaggedValue BuiltinsSharedArray::Values(EcmaRuntimeCallInfo *argv)
2040 {
2041     ASSERT(argv);
2042     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Values);
2043     JSThread *thread = argv->GetThread();
2044     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2045     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2046     if (!thisHandle->IsJSSharedArray()) {
2047         auto error = ContainerError::BindError(thread, "The values method cannot be bound.");
2048         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2049     }
2050     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2051     // 1. Let O be ToObject(this value).
2052     // 2. ReturnIfAbrupt(O).
2053     JSHandle<JSObject> self = JSTaggedValue::ToObject(thread, GetThis(argv));
2054     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2055     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2056     // 3. Return CreateArrayIterator(O, "value").
2057     JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE));
2058     return iter.GetTaggedValue();
2059 }
2060 // 22.1.3.31 Array.prototype [ @@unscopables ]
Unscopables(EcmaRuntimeCallInfo * argv)2061 JSTaggedValue BuiltinsSharedArray::Unscopables(EcmaRuntimeCallInfo *argv)
2062 {
2063     JSThread *thread = argv->GetThread();
2064     BUILTINS_API_TRACE(thread, SharedArray, Unscopables);
2065     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2066     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
2067     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
2068 
2069     JSHandle<JSObject> unscopableList = factory->CreateNullJSObject();
2070 
2071     JSHandle<JSTaggedValue> trueVal(thread, JSTaggedValue::True());
2072 
2073     JSHandle<JSTaggedValue> atKey((factory->NewFromASCII("at")));
2074     JSObject::CreateDataProperty(thread, unscopableList, atKey, trueVal);
2075 
2076     JSHandle<JSTaggedValue> copyWithKey = globalConst->GetHandledCopyWithinString();
2077     JSObject::CreateDataProperty(thread, unscopableList, copyWithKey, trueVal);
2078 
2079     JSHandle<JSTaggedValue> entriesKey = globalConst->GetHandledEntriesString();
2080     JSObject::CreateDataProperty(thread, unscopableList, entriesKey, trueVal);
2081 
2082     JSHandle<JSTaggedValue> fillKey = globalConst->GetHandledFillString();
2083     JSObject::CreateDataProperty(thread, unscopableList, fillKey, trueVal);
2084 
2085     JSHandle<JSTaggedValue> findKey = globalConst->GetHandledFindString();
2086     JSObject::CreateDataProperty(thread, unscopableList, findKey, trueVal);
2087 
2088     JSHandle<JSTaggedValue> findIndexKey = globalConst->GetHandledFindIndexString();
2089     JSObject::CreateDataProperty(thread, unscopableList, findIndexKey, trueVal);
2090 
2091     JSHandle<JSTaggedValue> findLastKey((factory->NewFromASCII("findLast")));
2092     JSObject::CreateDataProperty(thread, unscopableList, findLastKey, trueVal);
2093 
2094     JSHandle<JSTaggedValue> findLastIndexKey((factory->NewFromASCII("findLastIndex")));
2095     JSObject::CreateDataProperty(thread, unscopableList, findLastIndexKey, trueVal);
2096 
2097     JSHandle<JSTaggedValue> flatKey = globalConst->GetHandledFlatString();
2098     JSObject::CreateDataProperty(thread, unscopableList, flatKey, trueVal);
2099 
2100     JSHandle<JSTaggedValue> flatMapKey = globalConst->GetHandledFlatMapString();
2101     JSObject::CreateDataProperty(thread, unscopableList, flatMapKey, trueVal);
2102 
2103     JSHandle<JSTaggedValue> includesKey = globalConst->GetHandledIncludesString();
2104     JSObject::CreateDataProperty(thread, unscopableList, includesKey, trueVal);
2105 
2106     JSHandle<JSTaggedValue> keysKey = globalConst->GetHandledKeysString();
2107     JSObject::CreateDataProperty(thread, unscopableList, keysKey, trueVal);
2108 
2109     JSHandle<JSTaggedValue> valuesKey = globalConst->GetHandledValuesString();
2110     JSObject::CreateDataProperty(thread, unscopableList, valuesKey, trueVal);
2111 
2112     JSHandle<JSTaggedValue> toReversedKey((factory->NewFromASCII("toReversed")));
2113     JSObject::CreateDataProperty(thread, unscopableList, toReversedKey, trueVal);
2114 
2115     JSHandle<JSTaggedValue> toSortedKey((factory->NewFromASCII("toSorted")));
2116     JSObject::CreateDataProperty(thread, unscopableList, toSortedKey, trueVal);
2117 
2118     JSHandle<JSTaggedValue> toSplicedKey((factory->NewFromASCII("toSpliced")));
2119     JSObject::CreateDataProperty(thread, unscopableList, toSplicedKey, trueVal);
2120     return unscopableList.GetTaggedValue();
2121 }
2122 
2123 // 23.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
Includes(EcmaRuntimeCallInfo * argv)2124 JSTaggedValue BuiltinsSharedArray::Includes(EcmaRuntimeCallInfo *argv)
2125 {
2126     ASSERT(argv);
2127     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Includes);
2128     JSThread *thread = argv->GetThread();
2129     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2130     // 1. Let O be ? ToObject(this value).
2131     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2132     if (!thisHandle->IsJSSharedArray()) {
2133         auto error = ContainerError::BindError(thread, "The includes method cannot be bound.");
2134         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2135     }
2136     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2137     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2138     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2139 
2140     uint32_t argc = argv->GetArgsNumber();
2141     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2142     JSHandle<JSTaggedValue> searchElement = GetCallArg(argv, 0);
2143 
2144     // 2. Let len be ? LengthOfArrayLike(O).
2145     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2146     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2147     // 3. If len is 0, return false.
2148     if (len == 0) {
2149         return GetTaggedBoolean(false);
2150     }
2151     // 4. Let n be ? ToIntegerOrInfinity(fromIndex).
2152     // 5. Assert: If fromIndex is undefined, then n is 0.
2153     double fromIndex = 0;
2154     if (argc > 1) {
2155         JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 1);
2156         JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1);
2157         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2158         fromIndex = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber());
2159     }
2160 
2161     // 6. If n is +∞, return false.
2162     // 7. Else if n is -∞, set n to 0.
2163     if (fromIndex >= len) {
2164         return GetTaggedBoolean(false);
2165     } else if (fromIndex < -len) {
2166         fromIndex = 0;
2167     }
2168     // 8. If n ≥ 0, then
2169     //     a. Let k be n.
2170     // 9. Else,
2171     //     a. Let k be len + n.
2172     //     b. If k < 0, let k be 0.
2173     int64_t from = (fromIndex >= 0) ? fromIndex : ((len + fromIndex) >= 0 ? len + fromIndex : 0);
2174 
2175     // 10. Repeat, while k < len,
2176     //     a. Let elementK be ? Get(O, ! ToString(!(k))).
2177     //     b. If SameValueZero(searchElement, elementK) is true, return true.
2178     //     c. Set k to k + 1.
2179     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2180     JSMutableHandle<JSTaggedValue> kValueHandle(thread, JSTaggedValue::Undefined());
2181     JSHandle<EcmaString> fromStr;
2182     while (from < len) {
2183         JSHandle<JSTaggedValue> handledFrom(thread, JSTaggedValue(from));
2184         fromStr = JSTaggedValue::ToString(thread, handledFrom);
2185         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2186         key.Update(fromStr.GetTaggedValue());
2187         kValueHandle.Update(JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, key).GetTaggedValue());
2188         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2189         if (JSTaggedValue::SameValueZero(searchElement.GetTaggedValue(), kValueHandle.GetTaggedValue())) {
2190             return GetTaggedBoolean(true);
2191         }
2192         from++;
2193     }
2194     // 11. Return false.
2195     return GetTaggedBoolean(false);
2196 }
2197 
2198 // 23.1.3.1 Array.prototype.at ( index )
At(EcmaRuntimeCallInfo * argv)2199 JSTaggedValue BuiltinsSharedArray::At(EcmaRuntimeCallInfo *argv)
2200 {
2201     ASSERT(argv);
2202     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, At);
2203     JSThread *thread = argv->GetThread();
2204     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2205 
2206     // 1. Let O be ToObject(this value).
2207     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2208     if (!thisHandle->IsJSSharedArray()) {
2209         auto error = ContainerError::BindError(thread, "The at method cannot be bound.");
2210         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2211     }
2212     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2213     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2214     if (thisHandle->IsStableJSArray(thread)) {
2215         auto opResult = JSStableArray::At(JSHandle<JSSharedArray>::Cast(thisHandle), argv);
2216         return opResult;
2217     }
2218     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2219     // ReturnIfAbrupt(O).
2220     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2221     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2222 
2223     // 2. Let len be ? LengthOfArrayLike(O).
2224     int64_t len = ArrayHelper::GetLength(thread, thisObjVal);
2225     // ReturnIfAbrupt(len).
2226     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2227 
2228     // 3. Let index be ? ToIntegerOrInfinity(index).
2229     JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
2230     // ReturnIfAbrupt(index).
2231     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2232 
2233     // 4. If relativeIndex ≥ 0, then
2234     //     a. Let k be relativeIndex.
2235     // 5. Else,
2236     //     a. Let k be len + relativeIndex.
2237     int64_t relativeIndex = index.GetNumber();
2238     int64_t k = 0;
2239     if (relativeIndex >= 0) {
2240         k = relativeIndex;
2241     } else {
2242         k = len + relativeIndex;
2243     }
2244 
2245     // 6. If k < 0 or k ≥ len, return undefined.
2246     if (k < 0 || k >= len) {
2247         // Return undefined.
2248         return JSTaggedValue::Undefined();
2249     }
2250     // 7. Return ? Get(O, ! ToString(��(k))).
2251     JSHandle<JSTaggedValue> element = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k);
2252     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2253     return element.GetTaggedValue();
2254 }
2255 
2256 // Array.prototype.shrinkTo ( arrayLength )
ShrinkTo(EcmaRuntimeCallInfo * argv)2257 JSTaggedValue BuiltinsSharedArray::ShrinkTo(EcmaRuntimeCallInfo *argv)
2258 {
2259     ASSERT(argv);
2260     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo);
2261     JSThread *thread = argv->GetThread();
2262     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2263     if (argv->GetArgsNumber() != 1) {
2264         auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameter.");
2265         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2266     }
2267     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2268     if (!thisHandle->IsJSSharedArray()) {
2269         auto error = ContainerError::BindError(thread, "The ShrinkTo method cannot be bound.");
2270         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2271     }
2272     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2273     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2274     JSHandle<JSTaggedValue> newLengthValue = GetCallArg(argv, 0);
2275     if (!newLengthValue->IsNumber()) {
2276         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2277         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2278     }
2279     auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue);
2280     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2281     if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) {
2282         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2283         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2284     }
2285     int64_t len = ArrayHelper::GetLength(thread, thisHandle);
2286     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2287     if (newLength >= len) {
2288         return JSTaggedValue::Undefined();
2289     }
2290     JSSharedArray::LengthSetter(thread, thisObjHandle, newLengthValue, true);
2291     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2292     return JSTaggedValue::Undefined();
2293 }
2294 
2295 // Array.prototype.ExtendTo ( arrayLength, initialValue )
ExtendTo(EcmaRuntimeCallInfo * argv)2296 JSTaggedValue BuiltinsSharedArray::ExtendTo(EcmaRuntimeCallInfo *argv)
2297 {
2298     ASSERT(argv);
2299     BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo);
2300     JSThread *thread = argv->GetThread();
2301     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2302     if (argv->GetArgsNumber() < COUNT_LENGTH_AND_INIT) {
2303         auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameters.");
2304         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2305     }
2306     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2307     if (!thisHandle->IsJSSharedArray()) {
2308         auto error = ContainerError::BindError(thread, "The ExtendTo method cannot be bound.");
2309         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2310     }
2311     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2312     [[maybe_unused]] ConcurrentApiScope<JSSharedArray, ModType::WRITE> scope(thread, thisHandle);
2313     JSHandle<JSTaggedValue> newLengthValue = GetCallArg(argv, 0);
2314     if (!newLengthValue->IsNumber()) {
2315         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2316         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2317     }
2318     auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue);
2319     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2320     if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) {
2321         auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length.");
2322         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2323     }
2324 
2325     int64_t length = ArrayHelper::GetLength(thread, thisHandle);
2326     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2327     if (newLength <= length) {
2328         return JSTaggedValue::Undefined();
2329     }
2330 
2331     JSHandle<JSTaggedValue> initValue = GetCallArg(argv, 1);
2332     if (!initValue->IsSharedType()) {
2333         auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value.");
2334         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2335     }
2336     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
2337     for (uint32_t k = static_cast<uint32_t>(length); k < newLength; k++) {
2338         key.Update(JSTaggedValue(k));
2339         JSObject::CreateDataPropertyOrThrow(thread, thisObjHandle, key, initValue, SCheckMode::SKIP);
2340     }
2341     key.Update(JSTaggedValue(newLength));
2342     JSSharedArray::LengthSetter(thread, thisObjHandle, key, true);
2343     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2344     return JSTaggedValue::Undefined();
2345 }
2346 
LastIndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle)2347 JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath(EcmaRuntimeCallInfo *argv, JSThread *thread,
2348                                                        const JSHandle<JSTaggedValue> &thisHandle)
2349 {
2350     // 1. Let O be ToObject(this value).
2351     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
2352     // 2. ReturnIfAbrupt(O).
2353     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2354     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
2355     // 3. Let len be ToLength(Get(O, "length")).
2356     int64_t length = ArrayHelper::GetLength(thread, thisObjVal);
2357     // 4. ReturnIfAbrupt(len).
2358     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2359     // 5. If len is 0, return −1.
2360     if (length == 0) {
2361         return JSTaggedValue(-1);
2362     }
2363     // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0.
2364     int64_t fromIndex = ArrayHelper::GetLastStartIndexFromArgs(thread, argv, 1, length);
2365     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2366     return LastIndexOfSlowPath(argv, thread, thisObjVal, fromIndex);
2367 }
2368 
LastIndexOfSlowPath(EcmaRuntimeCallInfo * argv,JSThread * thread,const JSHandle<JSTaggedValue> & thisObjVal,int64_t fromIndex)2369 JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath(EcmaRuntimeCallInfo *argv, JSThread *thread,
2370                                                        const JSHandle<JSTaggedValue> &thisObjVal, int64_t fromIndex)
2371 {
2372     if (fromIndex < 0) {
2373         return JSTaggedValue(-1);
2374     }
2375     JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
2376     JSHandle<JSTaggedValue> target = base::BuiltinsBase::GetCallArg(argv, 0);
2377     // 11. Repeat, while k < len
2378     for (int64_t curIndex = fromIndex; curIndex >= 0; --curIndex) {
2379         keyHandle.Update(JSTaggedValue(curIndex));
2380         bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target);
2381         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2382         if (UNLIKELY(found)) {
2383             return JSTaggedValue(curIndex);
2384         }
2385     }
2386     // 12. Return -1.
2387     return JSTaggedValue(-1);
2388 }
2389 
2390 // Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] )
LastIndexOf(EcmaRuntimeCallInfo * argv)2391 JSTaggedValue BuiltinsSharedArray::LastIndexOf(EcmaRuntimeCallInfo *argv)
2392 {
2393     ASSERT(argv);
2394     JSThread *thread = argv->GetThread();
2395     BUILTINS_API_TRACE(thread, SharedArray, LastIndexOf);
2396     [[maybe_unused]] EcmaHandleScope handleScope(thread);
2397 
2398     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
2399     if (UNLIKELY(!thisHandle->IsJSSharedArray())) {
2400         auto error = ContainerError::BindError(thread, "The lastIndexOf method cannot be bound.");
2401         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2402     }
2403     [[maybe_unused]] ConcurrentApiScope<JSSharedArray> scope(thread, thisHandle);
2404     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
2405 
2406     if (thisHandle->IsStableJSArray(thread)) {
2407         auto error = ContainerError::BindError(thread, "The lastIndexOf method not support stable array.");
2408         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
2409     }
2410     return LastIndexOfSlowPath(argv, thread, thisHandle);
2411 }
2412 
2413 }  // namespace panda::ecmascript::builtins
2414