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