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_typedarray.h"
17
18 #include "ecmascript/base/typed_array_helper-inl.h"
19 #include "ecmascript/builtins/builtins_array.h"
20 #include "ecmascript/ecma_string-inl.h"
21 #include "ecmascript/interpreter/interpreter.h"
22 #include "ecmascript/js_stable_array.h"
23 #include "ecmascript/object_fast_operator-inl.h"
24
25
26 namespace panda::ecmascript::builtins {
27 using TypedArrayHelper = base::TypedArrayHelper;
28 using TypedArrayKind = base::TypedArrayKind;
29 using BuiltinsArray = builtins::BuiltinsArray;
30 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
31 using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer;
32 using ContainerError = containers::ContainerError;
33
TypedArrayBaseConstructor(EcmaRuntimeCallInfo * argv)34 JSTaggedValue BuiltinsSharedTypedArray::TypedArrayBaseConstructor(EcmaRuntimeCallInfo *argv)
35 {
36 ASSERT(argv);
37 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BaseConstructor);
38 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "SharedTypedArray Constructor cannot be called.",
39 JSTaggedValue::Exception());
40 }
41
Int8ArrayConstructor(EcmaRuntimeCallInfo * argv)42 JSTaggedValue BuiltinsSharedTypedArray::Int8ArrayConstructor(EcmaRuntimeCallInfo *argv)
43 {
44 ASSERT(argv);
45 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int8ArrayConstructor);
46 JSThread *thread = argv->GetThread();
47 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
48 thread->GlobalConstants()->GetHandledSharedInt8ArrayString(), DataViewType::INT8);
49 }
50
Uint8ArrayConstructor(EcmaRuntimeCallInfo * argv)51 JSTaggedValue BuiltinsSharedTypedArray::Uint8ArrayConstructor(EcmaRuntimeCallInfo *argv)
52 {
53 ASSERT(argv);
54 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint8ArrayConstructor);
55 JSThread *thread = argv->GetThread();
56 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
57 thread->GlobalConstants()->GetHandledSharedUint8ArrayString(), DataViewType::UINT8);
58 }
59
Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo * argv)60 JSTaggedValue BuiltinsSharedTypedArray::Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo *argv)
61 {
62 ASSERT(argv);
63 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint8ClampedArrayConstructor);
64 JSThread *thread = argv->GetThread();
65 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
66 thread->GlobalConstants()->GetHandledSharedUint8ClampedArrayString(), DataViewType::UINT8_CLAMPED);
67 }
68
Int16ArrayConstructor(EcmaRuntimeCallInfo * argv)69 JSTaggedValue BuiltinsSharedTypedArray::Int16ArrayConstructor(EcmaRuntimeCallInfo *argv)
70 {
71 ASSERT(argv);
72 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int16ArrayConstructor);
73 JSThread *thread = argv->GetThread();
74 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
75 thread->GlobalConstants()->GetHandledSharedInt16ArrayString(), DataViewType::INT16);
76 }
77
Uint16ArrayConstructor(EcmaRuntimeCallInfo * argv)78 JSTaggedValue BuiltinsSharedTypedArray::Uint16ArrayConstructor(EcmaRuntimeCallInfo *argv)
79 {
80 ASSERT(argv);
81 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint16ArrayConstructor);
82 JSThread *thread = argv->GetThread();
83 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
84 thread->GlobalConstants()->GetHandledSharedUint16ArrayString(), DataViewType::UINT16);
85 }
86
Int32ArrayConstructor(EcmaRuntimeCallInfo * argv)87 JSTaggedValue BuiltinsSharedTypedArray::Int32ArrayConstructor(EcmaRuntimeCallInfo *argv)
88 {
89 ASSERT(argv);
90 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int32ArrayConstructor);
91 JSThread *thread = argv->GetThread();
92 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
93 thread->GlobalConstants()->GetHandledSharedInt32ArrayString(), DataViewType::INT32);
94 }
95
Uint32ArrayConstructor(EcmaRuntimeCallInfo * argv)96 JSTaggedValue BuiltinsSharedTypedArray::Uint32ArrayConstructor(EcmaRuntimeCallInfo *argv)
97 {
98 ASSERT(argv);
99 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint32ArrayConstructor);
100 JSThread *thread = argv->GetThread();
101 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
102 thread->GlobalConstants()->GetHandledSharedUint32ArrayString(), DataViewType::UINT32);
103 }
104
Float32ArrayConstructor(EcmaRuntimeCallInfo * argv)105 JSTaggedValue BuiltinsSharedTypedArray::Float32ArrayConstructor(EcmaRuntimeCallInfo *argv)
106 {
107 ASSERT(argv);
108 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Float32ArrayConstructor);
109 JSThread *thread = argv->GetThread();
110 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
111 thread->GlobalConstants()->GetHandledSharedFloat32ArrayString(), DataViewType::FLOAT32);
112 }
113
Float64ArrayConstructor(EcmaRuntimeCallInfo * argv)114 JSTaggedValue BuiltinsSharedTypedArray::Float64ArrayConstructor(EcmaRuntimeCallInfo *argv)
115 {
116 ASSERT(argv);
117 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Float64ArrayConstructor);
118 JSThread *thread = argv->GetThread();
119 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
120 thread->GlobalConstants()->GetHandledSharedFloat64ArrayString(), DataViewType::FLOAT64);
121 }
122
BigInt64ArrayConstructor(EcmaRuntimeCallInfo * argv)123 JSTaggedValue BuiltinsSharedTypedArray::BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv)
124 {
125 ASSERT(argv);
126 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BigInt64ArrayConstructor);
127 JSThread *thread = argv->GetThread();
128 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
129 thread->GlobalConstants()->GetHandledSharedBigInt64ArrayString(), DataViewType::BIGINT64);
130 }
131
BigUint64ArrayConstructor(EcmaRuntimeCallInfo * argv)132 JSTaggedValue BuiltinsSharedTypedArray::BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv)
133 {
134 ASSERT(argv);
135 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BigUint64ArrayConstructor);
136 JSThread *thread = argv->GetThread();
137 return TypedArrayHelper::SharedTypedArrayConstructor(argv,
138 thread->GlobalConstants()->GetHandledSharedBigUint64ArrayString(), DataViewType::BIGUINT64);
139 }
140
141 // %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
From(EcmaRuntimeCallInfo * argv)142 JSTaggedValue BuiltinsSharedTypedArray::From(EcmaRuntimeCallInfo *argv)
143 {
144 ASSERT(argv);
145 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, From);
146 JSThread *thread = argv->GetThread();
147 [[maybe_unused]] EcmaHandleScope handleScope(thread);
148 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
149 // 1. Let C be the this value.
150 // 2. If IsConstructor(C) is false, throw a TypeError exception.
151 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
152 if (!thisHandle->IsConstructor()) {
153 THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception());
154 }
155
156 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
157 // 3. If mapfn is undefined, let mapping be false.
158 // 4. Else,
159 // a. If IsCallable(mapfn) is false, throw a TypeError exception.
160 // b. Let mapping be true.
161 bool mapping = false;
162 JSHandle<JSTaggedValue> mapfn = GetCallArg(argv, 1);
163 if (!mapfn->IsUndefined()) {
164 if (!mapfn->IsCallable()) {
165 THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception());
166 }
167 mapping = true;
168 }
169
170 // 5. Let usingIterator be ? GetMethod(source, @@iterator).
171 JSHandle<JSTaggedValue> source = GetCallArg(argv, 0);
172 JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
173 JSHandle<JSTaggedValue> usingIterator = JSObject::GetMethod(thread, source, iteratorSymbol);
174 // 6. If usingIterator is not undefined, then
175 // a. Let values be ? IterableToList(source, usingIterator).
176 // b. Let len be the number of elements in values.
177 // c. Let targetObj be ? TypedArrayCreate(C, « len »).
178 if (!usingIterator->IsUndefined() &&
179 !TypedArrayHelper::IsNativeArrayIterator(thread, source, usingIterator)) {
180 CVector<JSHandle<JSTaggedValue>> vec;
181 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, source, usingIterator);
182 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
183 JSHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
184 while (!next->IsFalse()) {
185 next = JSIterator::IteratorStep(thread, iterator);
186 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
187 if (!next->IsFalse()) {
188 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
189 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue());
190 vec.push_back(nextValue);
191 }
192 }
193 uint32_t len = vec.size();
194 JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
195 JSHandle<JSObject> targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
196 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
197 // d. Let k be 0.
198 // e. Repeat, while k < len
199 // i. Let Pk be ! ToString(k).
200 // ii. Let kValue be the first element of values and remove that element from values.
201 // iii. If mapping is true, then
202 // 1. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
203 // iv. Else, let mappedValue be kValue.
204 // v. Perform ? Set(targetObj, Pk, mappedValue, true).
205 // vi. Set k to k + 1.
206 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
207 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
208 const uint32_t argsLength = 2;
209 uint32_t k = 0;
210 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
211 while (k < len) {
212 tKey.Update(JSTaggedValue(k));
213 JSHandle<JSTaggedValue> kValue = vec[k];
214 if (mapping) {
215 EcmaRuntimeCallInfo *info =
216 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
217 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
218 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue());
219 JSTaggedValue callResult = JSFunction::Call(info);
220 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
221 mapValue.Update(callResult);
222 } else {
223 mapValue.Update(kValue.GetTaggedValue());
224 }
225 ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k,
226 mapValue.GetTaggedValue());
227 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
228 k++;
229 }
230 // f. Assert: values is now an empty List.
231 // g. Return targetObj.
232 return targetObj.GetTaggedValue();
233 }
234
235 // 7. NOTE: source is not an Iterable so assume it is already an array-like object.
236 // 8. Let arrayLike be ! ToObject(source).
237 JSHandle<JSObject> arrayLikeObj = JSTaggedValue::ToObject(thread, source);
238 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
239 JSHandle<JSTaggedValue> arrayLike(arrayLikeObj);
240 // 9. Let len be ? LengthOfArrayLike(arrayLike).
241 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
242 JSHandle<JSTaggedValue> lenResult = JSTaggedValue::GetProperty(thread, arrayLike, lengthKey).GetValue();
243 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
244 JSTaggedNumber tLen = JSTaggedValue::ToLength(thread, lenResult);
245 // 6. ReturnIfAbrupt(relativeTarget).
246 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
247 int64_t len = tLen.GetNumber();
248
249 // 10. Let targetObj be ? TypedArrayCreate(C, « len »).
250 JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
251 JSHandle<JSObject> targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
252 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
253 // 11. Let k be 0.
254 // 12. Repeat, while k < len
255 // a. Let Pk be ! ToString(k).
256 // b. Let kValue be ? Get(arrayLike, Pk).
257 // c. If mapping is true, then
258 // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
259 // d. Else, let mappedValue be kValue.
260 // e. Perform ? Set(targetObj, Pk, mappedValue, true).
261 // f. Set k to k + 1.
262 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
263 const uint32_t argsLength = 2;
264 int64_t k = 0;
265 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
266 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
267 JSHandle<JSTaggedValue> mapValue;
268 while (k < len) {
269 tKey.Update(JSTaggedValue(k));
270 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, arrayLike.GetTaggedValue(),
271 tKey.GetTaggedValue()));
272 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
273 if (mapping) {
274 EcmaRuntimeCallInfo *info =
275 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
276 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
277 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue());
278 JSTaggedValue callResult = JSFunction::Call(info);
279 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
280 mapValue = JSHandle<JSTaggedValue>(thread, callResult);
281 } else {
282 mapValue = kValue;
283 }
284 ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k, mapValue.GetTaggedValue());
285 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
286 k++;
287 }
288 // 13. Return targetObj.
289 return targetObj.GetTaggedValue();
290 }
291
Of(EcmaRuntimeCallInfo * argv)292 JSTaggedValue BuiltinsSharedTypedArray::Of(EcmaRuntimeCallInfo *argv)
293 {
294 ASSERT(argv);
295 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Of);
296 JSThread *thread = argv->GetThread();
297 [[maybe_unused]] EcmaHandleScope handleScope(thread);
298 // 1. Let len be the actual number of arguments passed to this function.
299 uint32_t len = argv->GetArgsNumber();
300 // 2. Let items be the List of arguments passed to this function.
301 // 3. Let C be the this value.
302 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
303 // 4. If IsConstructor(C) is false, throw a TypeError exception.
304 if (!thisHandle->IsConstructor()) {
305 THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception());
306 }
307 // 5. Let newObj be TypedArrayCreate(C, « len »).
308 JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
309 JSHandle<JSObject> newObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
310 // 6. ReturnIfAbrupt(newObj).
311 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
312 // 7. Let k be 0.
313 // 8. Repeat, while k < len
314 // a. Let kValue be items[k].
315 // b. Let Pk be ! ToString(k).
316 // c. Perform ? Set(newObj, Pk, kValue, true).
317 // d. ReturnIfAbrupt(status).
318 // e. Set k to k + 1.
319 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
320 uint32_t k = 0;
321 while (k < len) {
322 tKey.Update(JSTaggedValue(k));
323 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
324 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
325 JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k);
326 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newObj), kKey, kValue, true);
327 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
328 k++;
329 }
330 // 9. Return newObj.
331 return newObj.GetTaggedValue();
332 }
333
Species(EcmaRuntimeCallInfo * argv)334 JSTaggedValue BuiltinsSharedTypedArray::Species(EcmaRuntimeCallInfo *argv)
335 {
336 ASSERT(argv);
337 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Species);
338 // 1. Return the this value.
339 return GetThis(argv).GetTaggedValue();
340 }
341
342 // prototype
343 // get %TypedArray%.prototype.buffer
GetBuffer(EcmaRuntimeCallInfo * argv)344 JSTaggedValue BuiltinsSharedTypedArray::GetBuffer(EcmaRuntimeCallInfo *argv)
345 {
346 ASSERT(argv);
347 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetBuffer);
348 JSThread *thread = argv->GetThread();
349 [[maybe_unused]] EcmaHandleScope handleScope(thread);
350 // 1. Let O be the this value.
351 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
352 // 2. If Type(O) is not Object, throw a TypeError exception.
353 if (!thisHandle->IsECMAObject()) {
354 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
355 }
356 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
357 if (!thisHandle->IsSharedTypedArray()) {
358 auto error = ContainerError::BindError(thread, "The buffer property cannot be bound.");
359 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
360 }
361 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
362 JSHandle<JSSharedTypedArray> typedArray = JSHandle<JSSharedTypedArray>::Cast(thisHandle);
363 JSTaggedValue buffer = JSSharedTypedArray::GetSharedOffHeapBuffer(thread, typedArray);
364 // 5. Return buffer.
365 return buffer;
366 }
367
GetByteLength(EcmaRuntimeCallInfo * argv)368 JSTaggedValue BuiltinsSharedTypedArray::GetByteLength(EcmaRuntimeCallInfo *argv)
369 {
370 ASSERT(argv);
371 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetByteLength);
372 JSThread *thread = argv->GetThread();
373 [[maybe_unused]] EcmaHandleScope handleScope(thread);
374 // 1. Let O be the this value.
375 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
376 // 2. If Type(O) is not Object, throw a TypeError exception.
377 if (!thisHandle->IsECMAObject()) {
378 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
379 }
380 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
381 if (!thisHandle->IsSharedTypedArray()) {
382 auto error = ContainerError::BindError(thread, "The byteLength property cannot be bound.");
383 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
384 }
385 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
386 JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
387 JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray();
388 // 5. If IsDetachedBuffer(buffer) is true, return 0.
389 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
390 return JSTaggedValue(0);
391 }
392 // 6. Let size be the value of O’s [[ByteLength]] internal slot.
393 // 7. Return size.
394 return JSTaggedValue(typeArrayObj->GetByteLength());
395 }
396
GetByteOffset(EcmaRuntimeCallInfo * argv)397 JSTaggedValue BuiltinsSharedTypedArray::GetByteOffset(EcmaRuntimeCallInfo *argv)
398 {
399 ASSERT(argv);
400 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetByteOffset);
401 JSThread *thread = argv->GetThread();
402 [[maybe_unused]] EcmaHandleScope handleScope(thread);
403 // 1. Let O be the this value.
404 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
405 // 2. If Type(O) is not Object, throw a TypeError exception.
406 if (!thisHandle->IsECMAObject()) {
407 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
408 }
409 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
410 if (!thisHandle->IsSharedTypedArray()) {
411 auto error = ContainerError::BindError(thread, "The byteOffset property cannot be bound.");
412 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
413 }
414 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
415 JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
416 JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray();
417 // 5. If IsDetachedBuffer(buffer) is true, return 0.
418 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
419 return JSTaggedValue(0);
420 }
421 // 6. Let offset be the value of O’s [[ByteOffset]] internal slot.
422 uint32_t offset = typeArrayObj->GetByteOffset();
423 // 7. Return offset.
424 return JSTaggedValue(offset);
425 }
426
CopyWithin(EcmaRuntimeCallInfo * argv)427 JSTaggedValue BuiltinsSharedTypedArray::CopyWithin(EcmaRuntimeCallInfo *argv)
428 {
429 ASSERT(argv);
430 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, CopyWithin);
431 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
432 JSThread *thread = argv->GetThread();
433 if (!thisHandle->IsSharedTypedArray()) {
434 auto error = ContainerError::BindError(thread, "The copyWithin method cannot be bound.");
435 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
436 }
437 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray, ModType::WRITE> scope(thread, thisHandle);
438 return BuiltinsArray::CopyWithin(argv);
439 }
440
Entries(EcmaRuntimeCallInfo * argv)441 JSTaggedValue BuiltinsSharedTypedArray::Entries(EcmaRuntimeCallInfo *argv)
442 {
443 ASSERT(argv);
444 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Entries);
445 JSThread *thread = argv->GetThread();
446 [[maybe_unused]] EcmaHandleScope handleScope(thread);
447 // 1. Let O be the this value.
448 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
449 // 2. Let valid be ValidateTypedArray(O).
450 if (!thisHandle->IsSharedTypedArray()) {
451 auto error = ContainerError::BindError(thread, "The entries method cannot be bound.");
452 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
453 }
454 // 3. ReturnIfAbrupt(valid).
455 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
456 JSHandle<JSObject> self(thisHandle);
457 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
458 // 4. Return CreateArrayIterator(O, "key+value").
459 JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY_AND_VALUE));
460 return iter.GetTaggedValue();
461 }
462
Every(EcmaRuntimeCallInfo * argv)463 JSTaggedValue BuiltinsSharedTypedArray::Every(EcmaRuntimeCallInfo *argv)
464 {
465 ASSERT(argv);
466 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Every);
467 JSThread *thread = argv->GetThread();
468 [[maybe_unused]] EcmaHandleScope handleScope(thread);
469
470 // 1. Let O be ToObject(this value).
471 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
472 if (!thisHandle->IsSharedTypedArray()) {
473 auto error = ContainerError::BindError(thread, "The every method cannot be bound.");
474 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
475 }
476 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
477 // 2. ReturnIfAbrupt(O).
478 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
479 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
480
481 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
482 // 3. Let len be ToLength(Get(O, "length")).
483 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
484 // 4. ReturnIfAbrupt(len).
485 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
486
487 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
488 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
489 if (!callbackFnHandle->IsCallable()) {
490 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
491 }
492
493 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
494 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
495
496 // 7. Let k be 0.
497 // 8. Repeat, while k < len
498 // a. Let Pk be ToString(k).
499 // b. Let kPresent be HasProperty(O, Pk).
500 // c. ReturnIfAbrupt(kPresent).
501 // d. If kPresent is true, then
502 // i. Let kValue be Get(O, Pk).
503 // ii. ReturnIfAbrupt(kValue).
504 // iii. Let testResult be ToBoolean(Call(callbackfn, T, «kValue, k, O»)).
505 // iv. ReturnIfAbrupt(testResult).
506 // v. If testResult is false, return false.
507 // e. Increase k by 1.
508 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
509 const uint32_t argsLength = 3;
510 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
511 uint32_t k = 0;
512 while (k < len) {
513 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
514 JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue();
515 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
516 key.Update(JSTaggedValue(k));
517 EcmaRuntimeCallInfo *info =
518 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
519 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
520 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
521 JSTaggedValue callResult = JSFunction::Call(info);
522 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
523 bool boolResult = callResult.ToBoolean();
524 if (!boolResult) {
525 return GetTaggedBoolean(false);
526 }
527 k++;
528 }
529
530 // 9. Return true.
531 return GetTaggedBoolean(true);
532 }
533
Fill(EcmaRuntimeCallInfo * argv)534 JSTaggedValue BuiltinsSharedTypedArray::Fill(EcmaRuntimeCallInfo *argv)
535 {
536 ASSERT(argv);
537 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Fill);
538 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
539 JSThread *thread = argv->GetThread();
540 if (!thisHandle->IsSharedTypedArray()) {
541 auto error = ContainerError::BindError(thread, "The fill method cannot be bound.");
542 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
543 }
544 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray, ModType::WRITE> scope(thread, thisHandle);
545 return BuiltinsArray::Fill(argv);
546 }
547
548 // %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] )
Filter(EcmaRuntimeCallInfo * argv)549 JSTaggedValue BuiltinsSharedTypedArray::Filter(EcmaRuntimeCallInfo *argv)
550 {
551 ASSERT(argv);
552 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Filter);
553 JSThread *thread = argv->GetThread();
554 [[maybe_unused]] EcmaHandleScope handleScope(thread);
555 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
556 // 1. Let O be the this value.
557 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
558 // 2. Let valid be ValidateTypedArray(O).
559 if (!thisHandle->IsSharedTypedArray()) {
560 auto error = ContainerError::BindError(thread, "The filter method cannot be bound.");
561 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
562 }
563 // 3. ReturnIfAbrupt(valid).
564 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
565
566 JSHandle<JSTypedArray> thisObj(thisHandle);
567 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
568 uint32_t len = thisObj->GetArrayLength();
569 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
570 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
571 if (!callbackFnHandle->IsCallable()) {
572 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
573 }
574 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
575
576 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
577 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
578 // 10. Let kept be a new empty List.
579 JSHandle<TaggedArray> kept(factory->NewTaggedArray(len));
580
581 // 11. Let k be 0.
582 // 12. Let captured be 0.
583 // 13. Repeat, while k < len
584 // a. Let Pk be ToString(k).
585 // b. Let kValue be Get(O, Pk).
586 // c. ReturnIfAbrupt(kValue).
587 // d. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)).
588 // e. ReturnIfAbrupt(selected).
589 // f. If selected is true, then
590 // i. Append kValue to the end of kept.
591 // ii. Increase captured by 1.
592 // g. Increase k by 1.
593 int32_t captured = 0;
594 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
595 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
596 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
597 for (uint32_t k = 0; k < len; k++) {
598 tKey.Update(JSTaggedValue(k));
599 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
600 tKey.GetTaggedValue()));
601 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
602 EcmaRuntimeCallInfo *info =
603 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle,
604 undefined, 3); // 3: «kValue, k, O»
605 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
606 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue(), thisHandle.GetTaggedValue());
607 JSTaggedValue callResult = JSFunction::Call(info);
608 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
609 if (callResult.ToBoolean()) {
610 kept->Set(thread, captured, kValue);
611 captured++;
612 }
613 }
614 // es11 9. Let A be ? TypedArraySpeciesCreate(O, « captured »).
615 JSTaggedType args[1] = { JSTaggedValue(captured).GetRawData() };
616 JSHandle<JSObject> newArrObj =
617 TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::SHARED>(thread, thisObj, 1, args);
618 // 15. ReturnIfAbrupt(A).
619 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
620 // 16. Let n be 0.
621 // 17. For each element e of kept
622 // a. Let status be Set(A, ToString(n), e, true ).
623 // b. ReturnIfAbrupt(status).
624 // c. Increase n by 1.
625 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
626 JSMutableHandle<JSTaggedValue> ntKey(thread, JSTaggedValue::Undefined());
627 for (int32_t n = 0; n < captured; n++) {
628 valueHandle.Update(kept->Get(n));
629 ntKey.Update(JSTaggedValue(n));
630 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
631 ntKey.GetTaggedValue(), valueHandle.GetTaggedValue());
632 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
633 }
634 // 18. Return A.
635 return newArrObj.GetTaggedValue();
636 }
637
Find(EcmaRuntimeCallInfo * argv)638 JSTaggedValue BuiltinsSharedTypedArray::Find(EcmaRuntimeCallInfo *argv)
639 {
640 ASSERT(argv);
641 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Find);
642 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
643 JSThread *thread = argv->GetThread();
644 if (!thisHandle->IsSharedTypedArray()) {
645 auto error = ContainerError::BindError(thread, "The find method cannot be bound.");
646 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
647 }
648 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
649 return BuiltinsArray::Find(argv);
650 }
651
FindIndex(EcmaRuntimeCallInfo * argv)652 JSTaggedValue BuiltinsSharedTypedArray::FindIndex(EcmaRuntimeCallInfo *argv)
653 {
654 ASSERT(argv);
655 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, FindIndex);
656 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
657 JSThread *thread = argv->GetThread();
658 if (!thisHandle->IsSharedTypedArray()) {
659 auto error = ContainerError::BindError(thread, "The findIndex method cannot be bound.");
660 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
661 }
662 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
663 return BuiltinsArray::FindIndex(argv);
664 }
665
ForEach(EcmaRuntimeCallInfo * argv)666 JSTaggedValue BuiltinsSharedTypedArray::ForEach(EcmaRuntimeCallInfo *argv)
667 {
668 ASSERT(argv);
669 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ForEach);
670 JSThread *thread = argv->GetThread();
671 [[maybe_unused]] EcmaHandleScope handleScope(thread);
672
673 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
674 if (!thisHandle->IsSharedTypedArray()) {
675 auto error = ContainerError::BindError(thread, "The forEach method cannot be bound.");
676 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
677 }
678 // 1. Let O be ToObject(this value).
679 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
680 // 2. ReturnIfAbrupt(O).
681 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
682 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
683
684 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
685 // 3. Let len be ToLength(Get(O, "length")).
686 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
687 // 4. ReturnIfAbrupt(len).
688 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
689
690 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
691 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
692 if (!callbackFnHandle->IsCallable()) {
693 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
694 }
695
696 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
697 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
698
699 // 7. Let k be 0.
700 // 8. Repeat, while k < len
701 // a. Let Pk be ToString(k).
702 // b. Let kPresent be HasProperty(O, Pk).
703 // c. ReturnIfAbrupt(kPresent).
704 // d. If kPresent is true, then
705 // i. Let kValue be Get(O, Pk).
706 // ii. ReturnIfAbrupt(kValue).
707 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
708 // iv. ReturnIfAbrupt(funcResult).
709 // e. Increase k by 1.
710 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
711 const uint32_t argsLength = 3;
712 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
713 uint32_t k = 0;
714 while (k < len) {
715 JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue();
716 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
717 key.Update(JSTaggedValue(k));
718 EcmaRuntimeCallInfo *info =
719 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
720 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
721 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
722 JSTaggedValue funcResult = JSFunction::Call(info);
723 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
724 k++;
725 }
726
727 // 9. Return undefined.
728 return JSTaggedValue::Undefined();
729 }
730
IndexOf(EcmaRuntimeCallInfo * argv)731 JSTaggedValue BuiltinsSharedTypedArray::IndexOf(EcmaRuntimeCallInfo *argv)
732 {
733 ASSERT(argv);
734 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, IndexOf);
735 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
736 JSThread *thread = argv->GetThread();
737 if (!thisHandle->IsSharedTypedArray()) {
738 auto error = ContainerError::BindError(thread, "The indexOf method cannot be bound.");
739 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
740 }
741 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
742 return BuiltinsArray::IndexOf(argv);
743 }
744
LastIndexOf(EcmaRuntimeCallInfo * argv)745 JSTaggedValue BuiltinsSharedTypedArray::LastIndexOf(EcmaRuntimeCallInfo *argv)
746 {
747 ASSERT(argv);
748 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, LastIndexOf);
749 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
750 JSThread *thread = argv->GetThread();
751 if (!thisHandle->IsSharedTypedArray()) {
752 auto error = ContainerError::BindError(thread, "The lastindexOf method cannot be bound.");
753 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
754 }
755 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
756 return BuiltinsArray::LastIndexOf(argv);
757 }
758
Join(EcmaRuntimeCallInfo * argv)759 JSTaggedValue BuiltinsSharedTypedArray::Join(EcmaRuntimeCallInfo *argv)
760 {
761 ASSERT(argv);
762 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Join);
763 JSThread *thread = argv->GetThread();
764 [[maybe_unused]] EcmaHandleScope handleScope(thread);
765
766 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
767 if (!thisHandle->IsSharedTypedArray()) {
768 auto error = ContainerError::BindError(thread, "The join method cannot be bound.");
769 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
770 }
771 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
772
773 uint32_t length = JSHandle<JSTypedArray>::Cast(thisHandle)->GetArrayLength();
774 JSHandle<JSTaggedValue> sepHandle = GetCallArg(argv, 0);
775 int32_t sep = ',';
776 uint32_t sepLength = 1;
777 JSHandle<EcmaString> sepStringHandle;
778 if (!sepHandle->IsUndefined()) {
779 if (sepHandle->IsString()) {
780 sepStringHandle = JSHandle<EcmaString>::Cast(sepHandle);
781 } else {
782 sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
783 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
784 }
785 if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) {
786 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
787 sep = EcmaStringAccessor(sepStringHandle).Get(0);
788 } else if (EcmaStringAccessor(sepStringHandle).GetLength() == 0) {
789 sep = BuiltinsSharedTypedArray::SeparatorFlag::MINUS_TWO;
790 sepLength = 0;
791 } else {
792 sep = BuiltinsSharedTypedArray::SeparatorFlag::MINUS_ONE;
793 sepLength = EcmaStringAccessor(sepStringHandle).GetLength();
794 }
795 }
796 if (length == 0) {
797 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
798 return globalConst->GetEmptyString();
799 }
800 uint64_t allocateLength = 0;
801 bool isOneByte = (sep != BuiltinsSharedTypedArray::SeparatorFlag::MINUS_ONE) ||
802 EcmaStringAccessor(sepStringHandle).IsUtf8();
803 CVector<JSHandle<EcmaString>> vec;
804 JSMutableHandle<JSTaggedValue> elementHandle(thread, JSTaggedValue::Undefined());
805 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
806 for (uint32_t k = 0; k < length; k++) {
807 JSTaggedValue element = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue().GetTaggedValue();
808 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
809 if (!element.IsUndefinedOrNull() && !element.IsHole()) {
810 if (!element.IsString()) {
811 elementHandle.Update(element);
812 JSHandle<EcmaString> strElement = JSTaggedValue::ToString(thread, elementHandle);
813 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
814 element = strElement.GetTaggedValue();
815 }
816 auto nextStr = EcmaString::Cast(element.GetTaggedObject());
817 JSHandle<EcmaString> nextStrHandle(thread, nextStr);
818 vec.push_back(nextStrHandle);
819 isOneByte = EcmaStringAccessor(nextStr).IsUtf8() ? isOneByte : false;
820 allocateLength += EcmaStringAccessor(nextStr).GetLength();
821 } else {
822 vec.push_back(JSHandle<EcmaString>(globalConst->GetHandledEmptyString()));
823 }
824 }
825 allocateLength += static_cast<uint64_t>(sepLength) * (length - 1);
826 if (allocateLength <= 1) {
827 // sep unused, set isOneByte to default(true)
828 isOneByte = true;
829 }
830 if (allocateLength > EcmaString::MAX_STRING_LENGTH) {
831 THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception());
832 }
833 auto newString = EcmaStringAccessor::CreateLineString(
834 thread->GetEcmaVM(), static_cast<size_t>(allocateLength), isOneByte);
835 int current = 0;
836 DISALLOW_GARBAGE_COLLECTION;
837 for (uint32_t k = 0; k < length; k++) {
838 if (k > 0) {
839 if (sep >= 0) {
840 EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
841 } else if (sep != BuiltinsSharedTypedArray::SeparatorFlag::MINUS_TWO) {
842 EcmaStringAccessor::ReadData(
843 newString, *sepStringHandle, current, allocateLength - static_cast<size_t>(current), sepLength);
844 }
845 current += static_cast<int>(sepLength);
846 }
847 JSHandle<EcmaString> nextStr = vec[k];
848 int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
849 EcmaStringAccessor::ReadData(newString, *nextStr, current,
850 allocateLength - static_cast<size_t>(current), nextLength);
851 current += nextLength;
852 }
853 ASSERT_PRINT(
854 isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
855 return JSTaggedValue(newString);
856 }
857
Keys(EcmaRuntimeCallInfo * argv)858 JSTaggedValue BuiltinsSharedTypedArray::Keys(EcmaRuntimeCallInfo *argv)
859 {
860 ASSERT(argv);
861 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Keys);
862 JSThread *thread = argv->GetThread();
863 [[maybe_unused]] EcmaHandleScope handleScope(thread);
864 // 1. Let O be the this value.
865 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
866 // 2. Let valid be ValidateTypedArray(O).
867 if (!thisHandle->IsSharedTypedArray()) {
868 auto error = ContainerError::BindError(thread, "The keys method cannot be bound.");
869 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
870 }
871 // 3. ReturnIfAbrupt(valid).
872 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
873 JSHandle<JSObject> self(thisHandle);
874 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
875 // 4. Return CreateArrayIterator(O, "key").
876 JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY));
877 return iter.GetTaggedValue();
878 }
879
GetLength(EcmaRuntimeCallInfo * argv)880 JSTaggedValue BuiltinsSharedTypedArray::GetLength(EcmaRuntimeCallInfo *argv)
881 {
882 ASSERT(argv);
883 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetLength);
884 JSThread *thread = argv->GetThread();
885 [[maybe_unused]] EcmaHandleScope handleScope(thread);
886 // 1. Let O be the this value.
887 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
888 // 2. If Type(O) is not Object, throw a TypeError exception.
889 if (!thisHandle->IsECMAObject()) {
890 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
891 }
892 // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
893 if (!thisHandle->IsSharedTypedArray()) {
894 auto error = ContainerError::BindError(thread, "The length property cannot be bound.");
895 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
896 }
897 // 4. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
898 // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
899 JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(thisHandle)->GetViewedArrayBufferOrByteArray();
900 // 6. If IsDetachedBuffer(buffer) is true, return 0.
901 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
902 return JSTaggedValue(0);
903 }
904 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
905 uint32_t length = JSHandle<JSTypedArray>(thisHandle)->GetArrayLength();
906 // 8. Return length.
907 return JSTaggedValue(length);
908 }
909
910 // %TypedArray%.prototype.map ( callbackfn [ , thisArg ] )
Map(EcmaRuntimeCallInfo * argv)911 JSTaggedValue BuiltinsSharedTypedArray::Map(EcmaRuntimeCallInfo *argv)
912 {
913 ASSERT(argv);
914 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Map);
915 JSThread *thread = argv->GetThread();
916 [[maybe_unused]] EcmaHandleScope handleScope(thread);
917 // 1. Let O be the this value.
918 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
919 // 2. Let valid be ValidateTypedArray(O).
920 if (!thisHandle->IsSharedTypedArray()) {
921 auto error = ContainerError::BindError(thread, "The map method cannot be bound.");
922 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
923 }
924 // 3. ReturnIfAbrupt(valid).
925 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
926 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
927
928 JSHandle<JSTypedArray> thisObj(thisHandle);
929 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
930 uint32_t len = thisObj->GetArrayLength();
931 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
932 JSHandle<JSTaggedValue> callbackfnHandle = GetCallArg(argv, 0);
933 if (!callbackfnHandle->IsCallable()) {
934 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
935 }
936 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
937 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
938 // es11 5. Let A be ? TypedArraySpeciesCreate(O, « len »).
939 JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
940 JSHandle<JSObject> newArrObj =
941 TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::SHARED>(thread, thisObj, 1, args); // 1: one arg.
942 // 11. ReturnIfAbrupt(A).
943 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
944
945 // 12. Let k be 0.
946 // 13. Repeat, while k < len
947 // a. Let Pk be ToString(k).
948 // b. Let kValue be Get(O, Pk).
949 // c. ReturnIfAbrupt(kValue).
950 // d. Let mappedValue be Call(callbackfn, T, «kValue, k, O»).
951 // e. ReturnIfAbrupt(mappedValue).
952 // f. Let status be Set(A, Pk, mappedValue, true ).
953 // g. ReturnIfAbrupt(status).
954 // h. Increase k by 1.
955 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
956 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
957 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
958 const uint32_t argsLength = 3;
959 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
960 for (uint32_t k = 0; k < len; k++) {
961 key.Update(JSTaggedValue(k));
962 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
963 key.GetTaggedValue()));
964 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
965 EcmaRuntimeCallInfo *info =
966 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, undefined, argsLength);
967 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
968 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
969 JSTaggedValue callResult = JSFunction::Call(info);
970 mapValue.Update(callResult);
971 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
972 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
973 key.GetTaggedValue(), mapValue.GetTaggedValue());
974 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
975 }
976
977 // 14. Return A.
978 return newArrObj.GetTaggedValue();
979 }
980
Reduce(EcmaRuntimeCallInfo * argv)981 JSTaggedValue BuiltinsSharedTypedArray::Reduce(EcmaRuntimeCallInfo *argv)
982 {
983 ASSERT(argv);
984 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Reduce);
985 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
986 JSThread *thread = argv->GetThread();
987 if (!thisHandle->IsSharedTypedArray()) {
988 auto error = ContainerError::BindError(thread, "The reduce method cannot be bound.");
989 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
990 }
991 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
992 return BuiltinsArray::Reduce(argv);
993 }
994
ReduceRight(EcmaRuntimeCallInfo * argv)995 JSTaggedValue BuiltinsSharedTypedArray::ReduceRight(EcmaRuntimeCallInfo *argv)
996 {
997 ASSERT(argv);
998 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ReduceRight);
999 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1000 JSThread *thread = argv->GetThread();
1001 if (!thisHandle->IsSharedTypedArray()) {
1002 auto error = ContainerError::BindError(thread, "The reduceRight method cannot be bound.");
1003 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1004 }
1005 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1006 return BuiltinsArray::ReduceRight(argv);
1007 }
1008
Reverse(EcmaRuntimeCallInfo * argv)1009 JSTaggedValue BuiltinsSharedTypedArray::Reverse(EcmaRuntimeCallInfo *argv)
1010 {
1011 ASSERT(argv);
1012 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Reverse);
1013 JSThread *thread = argv->GetThread();
1014 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1015
1016 // 1. Let O be ToObject(this value).
1017 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1018 if (!thisHandle->IsSharedTypedArray()) {
1019 auto error = ContainerError::BindError(thread, "The reverse method cannot be bound.");
1020 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1021 }
1022 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1023 // 2. ReturnIfAbrupt(O).
1024 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1025 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray, ModType::WRITE> scope(thread, thisHandle);
1026
1027 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1028 // 3. Let len be O.[[ArrayLength]]
1029 int64_t len = JSHandle<JSTypedArray>::Cast(thisHandle)->GetArrayLength();
1030 // 4. ReturnIfAbrupt(len).
1031 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1032 // 5. Let middle be floor(len/2).
1033 int64_t middle = std::floor(len / 2);
1034 // 6. Let lower be 0.
1035 int64_t lower = 0;
1036
1037 // 7. Repeat, while lower ≠ middle,
1038 // a. Let upper be len - lower - 1.
1039 // b. Let upperP be ! ToString((upper)).
1040 // c. Let lowerP be ! ToString((lower)).
1041 // d. Let lowerValue be ! Get(O, lowerP).
1042 // e. Let upperValue be ! Get(O, upperP).
1043 // f. Perform ! Set(O, lowerP, upperValue, true).
1044 // g. Perform ! Set(O, upperP, lowerValue, true).
1045 // h. Set lower to lower + 1.
1046 JSMutableHandle<JSTaggedValue> lowerP(thread, JSTaggedValue::Undefined());
1047 JSMutableHandle<JSTaggedValue> upperP(thread, JSTaggedValue::Undefined());
1048 JSHandle<JSTaggedValue> lowerValueHandle(thread, JSTaggedValue::Undefined());
1049 JSHandle<JSTaggedValue> upperValueHandle(thread, JSTaggedValue::Undefined());
1050 while (lower != middle) {
1051 int64_t upper = len - lower - 1;
1052 lowerP.Update(JSTaggedValue(lower));
1053 upperP.Update(JSTaggedValue(upper));
1054 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1055 lowerValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, lowerP);
1056 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1057 upperValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, upperP);
1058 JSArray::FastSetPropertyByValue(thread, thisObjVal, lowerP, upperValueHandle);
1059 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1060 JSArray::FastSetPropertyByValue(thread, thisObjVal, upperP, lowerValueHandle);
1061 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1062 lower++;
1063 }
1064
1065 // 8. Return O .
1066 return thisObjHandle.GetTaggedValue();
1067 }
1068
1069 // %TypedArray%.prototype.set ( overloaded [ , offset ])
Set(EcmaRuntimeCallInfo * argv)1070 JSTaggedValue BuiltinsSharedTypedArray::Set(EcmaRuntimeCallInfo *argv)
1071 {
1072 ASSERT(argv);
1073 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Set);
1074 JSThread *thread = argv->GetThread();
1075 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1076 // 1. Assert: array is any ECMAScript language value other than an Object with a [[TypedArrayName]] internal slot.
1077 // If it is such an Object, the definition in 22.2.3.22.2 applies.
1078 // 2. Let target be the this value.
1079 JSHandle<JSTaggedValue> target = GetThis(argv);
1080 // 3. If Type(target) is not Object, throw a TypeError exception.
1081 if (!target->IsECMAObject()) {
1082 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
1083 }
1084 JSHandle<JSTypedArray> targetObj(target);
1085 // 4. If target does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
1086 if (!target->IsSharedTypedArray()) {
1087 auto error = ContainerError::BindError(thread, "The set method cannot be bound.");
1088 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1089 }
1090 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray, ModType::WRITE> scope(thread, target);
1091
1092 // 5. Assert: target has a [[ViewedArrayBuffer]] internal slot.
1093 // 6. Let targetOffset be ToInteger (offset).
1094 const JSHandle<JSTaggedValue> srcOffset = GetCallArg(argv, 1);
1095 uint64_t targetOffset = 0;
1096 if (srcOffset->IsInt()) {
1097 if (srcOffset->GetInt() < 0) {
1098 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1099 JSTaggedValue::Exception());
1100 }
1101 targetOffset = static_cast<uint64_t>(srcOffset->GetInt());
1102 } else {
1103 JSTaggedNumber tTargetOffset = JSTaggedValue::ToInteger(thread, srcOffset);
1104 // 7. ReturnIfAbrupt(targetOffset).
1105 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1106 double rawTargetOffset = tTargetOffset.GetNumber();
1107 // 8. If targetOffset < 0, throw a RangeError exception.
1108 if (rawTargetOffset < 0) {
1109 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1110 JSTaggedValue::Exception());
1111 } else if (rawTargetOffset == base::POSITIVE_INFINITY) {
1112 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset is infinty, which is greater than targetLength.",
1113 JSTaggedValue::Exception());
1114 } else {
1115 targetOffset = static_cast<uint64_t>(rawTargetOffset);
1116 }
1117 }
1118 // 9. Let targetBuffer be the value of target’s [[ViewedArrayBuffer]] internal slot.
1119 JSHandle<JSTaggedValue> targetBuffer(thread, targetObj->GetViewedArrayBufferOrByteArray());
1120 // 10. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1121 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1122 THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1123 JSTaggedValue::Exception());
1124 }
1125 // 11. Let targetLength be the value of target’s [[ArrayLength]] internal slot.
1126 // 12. Let targetName be the String value of target’s [[TypedArrayName]] internal slot.
1127 // 13. Let targetElementSize be the Number value of the Element Size value specified in Table 49 for targetName.
1128 // 14. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1129 // 15. Let targetByteOffset be the value of target’s [[ByteOffset]] internal slot.
1130 uint32_t targetLength = targetObj->GetArrayLength();
1131 DataViewType targetType = TypedArrayHelper::GetType(targetObj);
1132 uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType);
1133 uint32_t targetByteOffset = targetObj->GetByteOffset();
1134
1135 JSHandle<JSTaggedValue> argArray = GetCallArg(argv, 0);
1136 if (!argArray->IsTypedArray() && !argArray->IsSharedTypedArray()) {
1137 if (argArray->IsStableJSArray(thread)) {
1138 uint32_t length = JSHandle<JSArray>::Cast(argArray)->GetArrayLength();
1139 JSHandle<JSObject> argObj(argArray);
1140 uint32_t elemLength = ElementAccessor::GetElementsLength(argObj);
1141 // Load On Demand check
1142 if (elemLength >= length) {
1143 return JSStableArray::FastCopyFromArrayToTypedArray<TypedArrayKind::SHARED>(
1144 thread, targetObj, targetType, targetOffset, length, argObj);
1145 }
1146 }
1147 // 16. Let src be ToObject(array).
1148 JSHandle<JSObject> src = JSTaggedValue::ToObject(thread, argArray);
1149 // 17. ReturnIfAbrupt(src).
1150 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1151 // 18. Let srcLength be ToLength(Get(src, "length")).
1152 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
1153 JSHandle<JSTaggedValue> lenResult(thread,
1154 ObjectFastOperator::FastGetPropertyByValue(thread,
1155 JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(),
1156 lengthKey.GetTaggedValue()));
1157 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1158 JSTaggedNumber tSrcLen = JSTaggedValue::ToLength(thread, lenResult);
1159 // 19. ReturnIfAbrupt(srcLength).
1160 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1161 uint64_t srcLen = static_cast<uint64_t>(tSrcLen.GetNumber());
1162 // 20. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1163 if (srcLen + targetOffset > targetLength) {
1164 THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1165 JSTaggedValue::Exception());
1166 }
1167 // 21. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1168 ASSERT((targetOffset * static_cast<uint64_t>(targetElementSize) +
1169 static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1170 uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset * targetElementSize + targetByteOffset);
1171 // 22. Let k be 0.
1172 // 23. Let limit be targetByteIndex + targetElementSize × srcLength.
1173 uint32_t k = 0;
1174 ASSERT((static_cast<uint64_t>(targetElementSize) * srcLen +
1175 static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1176 uint32_t limit = targetByteIndex + targetElementSize * srcLen;
1177 // 24. Repeat, while targetByteIndex < limit
1178 // a. Let Pk be ToString(k).
1179 // b. If target.[[ContentType]] is BigInt, set value to ? ToBigInt(value).
1180 // c. Otherwise, set value to ? ToNumber(value).
1181 // d. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1182 // e. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, kNumber).
1183 // f. Set k to k + 1.
1184 // g. Set targetByteIndex to targetByteIndex + targetElementSize.
1185 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Hole());
1186 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
1187 JSMutableHandle<JSTaggedValue> kNumberHandle(thread, JSTaggedValue::Hole());
1188 ContentType contentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1189 while (targetByteIndex < limit) {
1190 tKey.Update(JSTaggedValue(k));
1191 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
1192 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1193 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(
1194 thread, JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(), kKey.GetTaggedValue()));
1195 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1196 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1197 THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1198 JSTaggedValue::Exception());
1199 }
1200 if (contentType == ContentType::BigInt) {
1201 kNumberHandle.Update(JSTaggedValue::ToBigInt(thread, kValue));
1202 } else {
1203 kNumberHandle.Update(JSTaggedValue::ToNumber(thread, kValue));
1204 }
1205 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1206 BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(),
1207 targetByteIndex, targetType, kNumberHandle, true);
1208 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1209 k++;
1210 targetByteIndex = targetByteIndex + targetElementSize;
1211 }
1212 // 25. Return undefined.
1213 return JSTaggedValue::Undefined();
1214 }
1215
1216 ASSERT(argArray->IsTypedArray() || argArray->IsSharedTypedArray());
1217 JSHandle<JSTypedArray> typedArray(argArray);
1218 // 12. Let srcBuffer be the value of typedArray’s [[ViewedArrayBuffer]] internal slot.
1219 // 13. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1220 JSTaggedValue srcBuffer = typedArray->GetViewedArrayBufferOrByteArray();
1221 JSHandle<JSTaggedValue> srcBufferHandle(thread, srcBuffer);
1222 if (srcBuffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1223 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
1224 JSTaggedValue::Exception());
1225 }
1226 if (!srcBuffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1227 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
1228 JSTaggedValue::Exception());
1229 }
1230
1231 ContentType objContentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1232 ContentType argArrayContentType = JSHandle<JSTypedArray>::Cast(argArray)->GetContentType();
1233 if (argArrayContentType != objContentType) {
1234 THROW_TYPE_ERROR_AND_RETURN(thread,
1235 "argArrayContentType is not equal objContentType.",
1236 JSTaggedValue::Exception());
1237 }
1238 // 18. Let srcName be the String value of typedArray’s [[TypedArrayName]] internal slot.
1239 // 19. Let srcType be the String value of the Element Type value in Table 49 for srcName .
1240 // 20. Let srcElementSize be the Number value of the Element Size value specified in Table 49 for srcName.
1241 // 21. Let srcLength be the value of typedArray’s [[ArrayLength]] internal slot.
1242 // 22. Let srcByteOffset be the value of typedArray’s [[ByteOffset]] internal slot.
1243 JSHandle<JSTaggedValue> srcName(thread, typedArray->GetTypedArrayName());
1244 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1245 uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType);
1246 uint32_t srcLength = typedArray->GetArrayLength();
1247 uint32_t srcByteOffset = typedArray->GetByteOffset();
1248 // 23. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1249 if (srcLength + targetOffset > targetLength) {
1250 THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1251 JSTaggedValue::Exception());
1252 }
1253 // 24. If SameValue(srcBuffer, targetBuffer) is true, then
1254 // a. Let srcBuffer be CloneArrayBuffer(targetBuffer, srcByteOffset, %ArrayBuffer%).
1255 // b. NOTE: %ArrayBuffer% is used to clone targetBuffer because is it known to not have any observable
1256 // side-effects.
1257 // c. ReturnIfAbrupt(srcBuffer).
1258 // d. Let srcByteIndex be 0.
1259 // 25. Else, let srcByteIndex be srcByteOffset.
1260 uint32_t srcByteIndex = 0;
1261 if (JSTaggedValue::SameValue(srcBufferHandle.GetTaggedValue(), targetBuffer.GetTaggedValue())) {
1262 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1263 srcBuffer =
1264 BuiltinsSendableArrayBuffer::CloneArrayBuffer(thread, targetBuffer, srcByteOffset,
1265 env->GetSBuiltininArrayBufferFunction());
1266 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1267 srcBufferHandle = JSHandle<JSTaggedValue>(thread, srcBuffer);
1268 srcByteIndex = 0;
1269 } else {
1270 srcByteIndex = srcByteOffset;
1271 }
1272 // 26. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1273 ASSERT((targetOffset * static_cast<uint64_t>(targetElementSize) +
1274 static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1275 uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset) * targetElementSize + targetByteOffset;
1276 // 27. Let limit be targetByteIndex + targetElementSize × srcLength.
1277 ASSERT((static_cast<uint64_t>(targetElementSize) * static_cast<uint64_t>(srcLength) +
1278 static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1279 uint32_t limit = targetByteIndex + targetElementSize * srcLength;
1280 uint32_t count = (limit - targetByteIndex) > 0 ? (limit - targetByteIndex) : 0;
1281 // 28. If SameValue(srcType, targetType) is false, then
1282 // a. Repeat, while targetByteIndex < limit
1283 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType).
1284 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, targetType, value).
1285 // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
1286 // iv. Set targetByteIndex to targetByteIndex + targetElementSize.
1287 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
1288 if (srcType != targetType) {
1289 while (targetByteIndex < limit) {
1290 JSTaggedValue taggedData =
1291 BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBufferHandle.GetTaggedValue(),
1292 srcByteIndex, srcType, true);
1293 value.Update(taggedData);
1294 BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
1295 targetType, value, true);
1296 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1297 srcByteIndex = srcByteIndex + srcElementSize;
1298 targetByteIndex = targetByteIndex + targetElementSize;
1299 }
1300 } else if (count > 0) {
1301 // 29. Else,
1302 // a. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that preserves
1303 // the bit-level encoding of the source data.
1304 // b. Repeat, while targetByteIndex < limit
1305 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1306 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1307 // iii. Set srcByteIndex to srcByteIndex + 1.
1308 // iv. Set targetByteIndex to targetByteIndex + 1.
1309 void *srcBuf = nullptr;
1310 if (argArray->IsSharedTypedArray()) {
1311 srcBuf = BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(
1312 srcBufferHandle.GetTaggedValue(), srcByteIndex);
1313 } else {
1314 srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(
1315 srcBufferHandle.GetTaggedValue(), srcByteIndex);
1316 }
1317 void *targetBuf = BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(
1318 targetBuffer.GetTaggedValue(), targetByteIndex);
1319 if (memcpy_s(targetBuf, srcLength * srcElementSize, srcBuf, srcLength * srcElementSize) != EOK) {
1320 LOG_FULL(FATAL) << "memcpy_s failed";
1321 UNREACHABLE();
1322 }
1323 }
1324 // 30. Return undefined.
1325 return JSTaggedValue::Undefined();
1326 }
1327
1328 // %TypedArray%.prototype.slice ( start, end )
Slice(EcmaRuntimeCallInfo * argv)1329 JSTaggedValue BuiltinsSharedTypedArray::Slice(EcmaRuntimeCallInfo *argv)
1330 {
1331 ASSERT(argv);
1332 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Slice);
1333 JSThread *thread = argv->GetThread();
1334 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1335 // 1. Let O be the this value.
1336 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1337 // 2. Let valid be ValidateTypedArray(O).
1338 if (!thisHandle->IsSharedTypedArray()) {
1339 auto error = ContainerError::BindError(thread, "The slice method cannot be bound.");
1340 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1341 }
1342
1343 // 3. ReturnIfAbrupt(valid).
1344 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1345 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1346
1347 JSHandle<JSTypedArray> thisObj(thisHandle);
1348 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
1349 uint32_t len = thisObj->GetArrayLength();
1350
1351 // 5. Let relativeStart be ToInteger(start).
1352 JSTaggedNumber tRelativeStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1353 // 6. ReturnIfAbrupt(relativeStart).
1354 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1355 double relativeStart = tRelativeStart.GetNumber();
1356 // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
1357
1358 uint32_t k = relativeStart < 0 ?
1359 std::max((static_cast<double>(len) + relativeStart), 0.0) :
1360 std::min(relativeStart, static_cast<double>(len));
1361 // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
1362 double relativeEnd = len;
1363 JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1364 if (!end->IsUndefined()) {
1365 JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1366 // 9. ReturnIfAbrupt(relativeEnd).
1367 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1368 relativeEnd = tRelativeEnd.GetNumber();
1369 }
1370
1371 // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
1372
1373 uint32_t final = relativeEnd < 0 ?
1374 std::max((static_cast<double>(len) + relativeEnd), 0.0) :
1375 std::min(relativeEnd, static_cast<double>(len));
1376 // 11. Let count be max(final – k, 0).
1377 uint32_t count = final > k ? (final - k) : 0;
1378 // es11 9. Let A be ? TypedArraySpeciesCreate(O, « count »).
1379 JSTaggedType args[1] = { JSTaggedValue(count).GetRawData() };
1380 JSHandle<JSObject> newArrObj =
1381 TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::SHARED>(thread, thisObj, 1, args);
1382 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1383 // 17. Let srcName be the String value of O’s [[TypedArrayName]] internal slot.
1384 // 18. Let srcType be the String value of the Element Type value in Table 49 for srcName.
1385 JSHandle<JSTaggedValue> srcName(thread, thisObj->GetTypedArrayName());
1386 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1387 // 19. Let targetName be the String value of A’s [[TypedArrayName]] internal slot.
1388 // 20. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1389 JSHandle<JSTaggedValue> targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName());
1390 DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
1391 // 21. If SameValue(srcType, targetType) is false, then
1392 // a. Let n be 0.
1393 // b. Repeat, while k < final
1394 // i. Let Pk be ToString(k).
1395 // ii. Let kValue be Get(O, Pk).
1396 // iii. ReturnIfAbrupt(kValue).
1397 // iv. Let status be Set(A, ToString(n), kValue, true ).
1398 // v. ReturnIfAbrupt(status).
1399 // vi. Increase k by 1.
1400 // vii. Increase n by 1.
1401 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
1402 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
1403 JSMutableHandle<JSTaggedValue> ntKey(thread, JSTaggedValue::Undefined());
1404 if (srcType != targetType) {
1405 uint32_t n = 0;
1406 while (k < final) {
1407 tKey.Update(JSTaggedValue(k));
1408 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
1409 tKey.GetTaggedValue()));
1410 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1411 ntKey.Update(JSTaggedValue(n));
1412 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
1413 ntKey.GetTaggedValue(), kValue.GetTaggedValue());
1414 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1415 n++;
1416 k++;
1417 }
1418 } else if (count > 0) {
1419 // 22. Else if count > 0,
1420 // a. Let srcBuffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1421 // b. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1422 JSTaggedValue srcBuffer = thisObj->GetViewedArrayBufferOrByteArray();
1423 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1424 THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
1425 JSTaggedValue::Exception());
1426 }
1427 // c. Let targetBuffer be the value of A’s [[ViewedArrayBuffer]] internal slot.
1428 JSTaggedValue targetBuffer = JSTypedArray::Cast(*newArrObj)->GetViewedArrayBufferOrByteArray();
1429 // d. Let elementSize be the Number value of the Element Size value specified in Table 49 for srcType.
1430 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(srcType);
1431 // e. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that
1432 // preserves the bit-level encoding of the source data.
1433 // f. Let srcByteOffset be the value of O’s[[ByteOffset]] internal slot.
1434 uint32_t srcByteOffset = thisObj->GetByteOffset();
1435 // h. Let srcByteIndex be (k × elementSize) + srcByteOffset.
1436 uint32_t srcByteIndex = k * elementSize + srcByteOffset;
1437 // g. Let targetByteIndex be A.[[ByteOffset]].
1438 uint32_t targetByteIndex = JSTypedArray::Cast(*newArrObj)->GetByteOffset();
1439 // i. Repeat, while targetByteIndex < count × elementSize
1440 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1441 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1442 // iii. Increase srcByteIndex by 1.
1443 // iv. Increase targetByteIndex by 1.
1444 uint8_t *srcBuf = reinterpret_cast<uint8_t *>(
1445 BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(srcBuffer, srcByteIndex));
1446 uint8_t *targetBuf = reinterpret_cast<uint8_t *>(
1447 BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(targetBuffer, targetByteIndex));
1448 if (srcBuffer != targetBuffer && memmove_s(
1449 targetBuf, elementSize * count, srcBuf, elementSize * count) != EOK) {
1450 LOG_FULL(FATAL) << "memcpy_s failed";
1451 UNREACHABLE();
1452 }
1453 while (srcBuffer == targetBuffer && count > 0) {
1454 count--;
1455 if (memcpy_s(targetBuf, elementSize, srcBuf, elementSize) != EOK) {
1456 LOG_FULL(FATAL) << "memcpy_s failed";
1457 UNREACHABLE();
1458 }
1459 srcBuf += elementSize;
1460 targetBuf += elementSize;
1461 }
1462 }
1463 // 23. Return A.
1464 return newArrObj.GetTaggedValue();
1465 }
1466
Some(EcmaRuntimeCallInfo * argv)1467 JSTaggedValue BuiltinsSharedTypedArray::Some(EcmaRuntimeCallInfo *argv)
1468 {
1469 ASSERT(argv);
1470 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Some);
1471 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1472 JSThread *thread = argv->GetThread();
1473 if (!thisHandle->IsSharedTypedArray()) {
1474 auto error = ContainerError::BindError(thread, "The some method cannot be bound.");
1475 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1476 }
1477 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1478 return BuiltinsArray::Some(argv);
1479 }
1480
Sort(EcmaRuntimeCallInfo * argv)1481 JSTaggedValue BuiltinsSharedTypedArray::Sort(EcmaRuntimeCallInfo *argv)
1482 {
1483 ASSERT(argv);
1484 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Sort);
1485 JSThread *thread = argv->GetThread();
1486 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1487
1488 // 1. Let obj be ToObject(this value).
1489 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1490 if (!thisHandle->IsSharedTypedArray()) {
1491 auto error = ContainerError::BindError(thread, "The sort method cannot be bound.");
1492 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1493 }
1494
1495 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1496 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1497 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray, ModType::WRITE> scope(thread, thisHandle);
1498
1499 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1500 JSHandle<JSTaggedValue> buffer;
1501 buffer = JSHandle<JSTaggedValue>(thread, TypedArrayHelper::ValidateTypedArray(thread, thisHandle));
1502 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1503 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1504
1505 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1506 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
1507 THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
1508 }
1509 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
1510 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
1511 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
1512 JSMutableHandle<JSTaggedValue> key1(thread, JSTaggedValue::Undefined());
1513 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1514 JSMutableHandle<JSTaggedValue> key2(thread, JSTaggedValue::Undefined());
1515 for (uint32_t i = 1; i < len; i++) {
1516 uint32_t beginIndex = 0;
1517 uint32_t endIndex = i;
1518 key.Update(JSTaggedValue(i));
1519 presentValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1520 key.GetTaggedValue()));
1521 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1522 while (beginIndex < endIndex) {
1523 uint32_t middleIndex = beginIndex + (endIndex - beginIndex) / 2; // 2 : half
1524 key1.Update(JSTaggedValue(middleIndex));
1525 middleValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1526 key1.GetTaggedValue()));
1527 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1528 int32_t compareResult = TypedArrayHelper::SortCompare(thread, callbackFnHandle, buffer,
1529 middleValue, presentValue);
1530 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1531 compareResult > 0 ? (endIndex = middleIndex) : (beginIndex = middleIndex + 1);
1532 }
1533
1534 if (endIndex < i) {
1535 for (uint32_t j = i; j > endIndex; j--) {
1536 key2.Update(JSTaggedValue(j - 1));
1537 previousValue.Update(
1538 ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1539 key2.GetTaggedValue()));
1540 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1541 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
1542 previousValue.GetTaggedValue());
1543 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1544 }
1545 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
1546 presentValue.GetTaggedValue());
1547 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1548 }
1549 }
1550 return thisObjHandle.GetTaggedValue();
1551 }
1552
1553 // %TypedArray%.prototype.subarray( [ begin [ , end ] ] )
Subarray(EcmaRuntimeCallInfo * argv)1554 JSTaggedValue BuiltinsSharedTypedArray::Subarray(EcmaRuntimeCallInfo *argv)
1555 {
1556 ASSERT(argv);
1557 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Subarray);
1558 JSThread *thread = argv->GetThread();
1559 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1560 // 1. Let O be the this value.
1561 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1562 // 2. If Type(O) is not Object, throw a TypeError exception.
1563 if (!thisHandle->IsECMAObject()) {
1564 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
1565 }
1566 JSHandle<JSTypedArray> thisObj(thisHandle);
1567 // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
1568 if (!thisHandle->IsSharedTypedArray()) {
1569 auto error = ContainerError::BindError(thread, "The subarray method cannot be bound.");
1570 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1571 }
1572 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1573
1574 // 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
1575 // 6. Let srcLength be the value of O’s [[ArrayLength]] internal slot.
1576 uint32_t srcLength = thisObj->GetArrayLength();
1577 // 7. Let relativeBegin be ToInteger(begin).
1578 JSTaggedNumber tRelativeBegin = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1579 // 8. ReturnIfAbrupt(relativeBegin).
1580 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1581 double relativeBegin = tRelativeBegin.GetNumber();
1582
1583 uint32_t beginIndex = 0;
1584 // 9. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin), 0); else let beginIndex be
1585 // min(relativeBegin, srcLength).
1586 if (relativeBegin < 0) {
1587 double tempBeginIndex = relativeBegin + static_cast<double>(srcLength);
1588 beginIndex = tempBeginIndex > 0 ? static_cast<uint32_t>(tempBeginIndex) : 0;
1589 } else {
1590 beginIndex = relativeBegin < static_cast<double>(srcLength) ?
1591 static_cast<uint32_t>(relativeBegin) : srcLength;
1592 }
1593
1594 // 10. If end is undefined, let relativeEnd be srcLength; else, let relativeEnd be ToInteger(end).
1595 double relativeEnd = srcLength;
1596 JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1597 if (!end->IsUndefined()) {
1598 JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1599 // 11. ReturnIfAbrupt(relativeEnd).
1600 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1601 relativeEnd = tRelativeEnd.GetNumber();
1602 }
1603 // 12. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0); else let endIndex be
1604 // min(relativeEnd, srcLength).
1605 uint32_t endIndex;
1606 if (relativeEnd < 0) {
1607 double tempEndIndex = relativeEnd + static_cast<double>(srcLength);
1608 endIndex = tempEndIndex > 0 ? static_cast<uint32_t>(tempEndIndex) : 0;
1609 } else {
1610 endIndex = relativeEnd < static_cast<double>(srcLength) ?
1611 static_cast<uint32_t>(relativeEnd) : srcLength;
1612 }
1613 // 13. Let newLength be max(endIndex – beginIndex, 0).
1614 uint32_t newLength = endIndex > beginIndex ? (endIndex - beginIndex) : 0;
1615 // 14. Let constructorName be the String value of O’s [[TypedArrayName]] internal slot.
1616 // 15. Let elementSize be the Number value of the Element Size value specified in Table 49 for constructorName.
1617 // 16. Let srcByteOffset be the value of O’s [[ByteOffset]] internal slot.
1618 // 17. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
1619 JSHandle<JSTaggedValue> constructorName(thread, thisObj->GetTypedArrayName());
1620 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName);
1621 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType);
1622 uint32_t srcByteOffset = thisObj->GetByteOffset();
1623 ASSERT((static_cast<uint64_t>(srcByteOffset) + static_cast<uint64_t>(beginIndex) *
1624 static_cast<uint64_t>(elementSize)) <= static_cast<uint64_t>(UINT32_MAX));
1625 uint32_t beginByteOffset = srcByteOffset + beginIndex * elementSize;
1626 JSTaggedValue buffer = JSSharedTypedArray::GetSharedOffHeapBuffer(thread, JSHandle<JSSharedTypedArray>(thisObj));
1627 // 21. Let argumentsList be «buffer, beginByteOffset, newLength».
1628 // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1629 // 22. Return Construct(constructor, argumentsList).
1630 const uint32_t argsLength = 3;
1631 JSTaggedType args[argsLength] = {
1632 buffer.GetRawData(),
1633 JSTaggedValue(beginByteOffset).GetRawData(),
1634 JSTaggedValue(newLength).GetRawData()
1635 };
1636 JSHandle<JSObject> newArr =
1637 TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::SHARED>(thread, thisObj, argsLength, args);
1638 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1639 return newArr.GetTaggedValue();
1640 }
1641
ToLocaleString(EcmaRuntimeCallInfo * argv)1642 JSTaggedValue BuiltinsSharedTypedArray::ToLocaleString(EcmaRuntimeCallInfo *argv)
1643 {
1644 ASSERT(argv);
1645 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ToLocaleString);
1646 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1647 JSThread *thread = argv->GetThread();
1648 if (!thisHandle->IsSharedTypedArray()) {
1649 auto error = ContainerError::BindError(thread, "The toLocaleString method cannot be bound.");
1650 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1651 }
1652 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1653 return BuiltinsArray::ToLocaleString(argv);
1654 }
1655
ToString(EcmaRuntimeCallInfo * argv)1656 JSTaggedValue BuiltinsSharedTypedArray::ToString(EcmaRuntimeCallInfo *argv)
1657 {
1658 ASSERT(argv);
1659 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ToString);
1660 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1661 JSThread *thread = argv->GetThread();
1662 if (!thisHandle->IsSharedTypedArray()) {
1663 auto error = ContainerError::BindError(thread, "The toString method cannot be bound.");
1664 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1665 }
1666 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1667 return BuiltinsArray::ToString(argv);
1668 }
1669
Values(EcmaRuntimeCallInfo * argv)1670 JSTaggedValue BuiltinsSharedTypedArray::Values(EcmaRuntimeCallInfo *argv)
1671 {
1672 ASSERT(argv);
1673 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Values);
1674 JSThread *thread = argv->GetThread();
1675 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1676 // 1. Let O be the this value.
1677 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1678 // 2. Let valid be ValidateTypedArray(O).
1679 if (!thisHandle->IsSharedTypedArray()) {
1680 auto error = ContainerError::BindError(thread, "The values method cannot be bound.");
1681 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1682 }
1683 // 3. ReturnIfAbrupt(valid).
1684 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
1685 JSHandle<JSObject> self(thisHandle);
1686 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1687 // 4. Return CreateArrayIterator(O, "value").
1688 JSHandle<JSSharedArrayIterator> iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE));
1689 return iter.GetTaggedValue();
1690 }
1691
ToStringTag(EcmaRuntimeCallInfo * argv)1692 JSTaggedValue BuiltinsSharedTypedArray::ToStringTag(EcmaRuntimeCallInfo *argv)
1693 {
1694 ASSERT(argv);
1695 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ToStringTag);
1696 JSThread *thread = argv->GetThread();
1697 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1698 // 1. Let O be the this value.
1699 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1700 // 2. If Type(O) is not Object, return undefined.
1701 if (!thisHandle->IsECMAObject()) {
1702 return JSTaggedValue::Undefined();
1703 }
1704 // 3. If O does not have a [[TypedArrayName]] internal slot, return undefined.
1705 if (!thisHandle->IsSharedTypedArray()) {
1706 return JSTaggedValue::Undefined();
1707 }
1708 // 4. Let name be the value of O’s [[TypedArrayName]] internal slot.
1709 JSTaggedValue name = JSHandle<JSTypedArray>::Cast(thisHandle)->GetTypedArrayName();
1710 // 5. Assert: name is a String value.
1711 ASSERT(name.IsString());
1712 // 6. Return name.
1713 return name;
1714 }
1715
At(EcmaRuntimeCallInfo * argv)1716 JSTaggedValue BuiltinsSharedTypedArray::At(EcmaRuntimeCallInfo *argv)
1717 {
1718 ASSERT(argv);
1719 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, At);
1720 JSThread *thread = argv->GetThread();
1721 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1722
1723 // 1. Let O be ToObject(this value).
1724 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1725 // 2. Perform ? ValidateTypedArray(O).
1726 if (!thisHandle->IsSharedTypedArray()) {
1727 auto error = ContainerError::BindError(thread, "The at method cannot be bound.");
1728 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1729 }
1730 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1731 // ReturnIfAbrupt(O).
1732 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1733 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1734
1735 // 3. Let len be O.[[ArrayLength]].
1736 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1737 // ReturnIfAbrupt(len).
1738 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1739
1740 // 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
1741 JSTaggedNumber indexVal = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1742 // ReturnIfAbrupt(indexVal).
1743 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1744 int64_t relativeIndex = indexVal.GetNumber();
1745 int64_t k = 0;
1746 // 5. If relativeIndex ≥ 0, then Let k be relativeIndex.
1747 // 6. Else, Let k be len + relativeIndex.
1748 k = relativeIndex >= 0 ? relativeIndex : static_cast<int64_t>(len) + relativeIndex;
1749 // 7. If k < 0 or k ≥ len, return undefined.
1750 if (k < 0 || k >= len) {
1751 return JSTaggedValue::Undefined();
1752 }
1753 // 8. Return ! Get(O, ! ToString((k))).
1754 JSHandle<JSTaggedValue> kValue = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue();
1755 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1756 return kValue.GetTaggedValue();
1757 }
1758
Includes(EcmaRuntimeCallInfo * argv)1759 JSTaggedValue BuiltinsSharedTypedArray::Includes(EcmaRuntimeCallInfo *argv)
1760 {
1761 ASSERT(argv);
1762 BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Includes);
1763 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1764 JSThread *thread = argv->GetThread();
1765 if (!thisHandle->IsSharedTypedArray()) {
1766 auto error = ContainerError::BindError(thread, "The includes method cannot be bound.");
1767 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
1768 }
1769 [[maybe_unused]] ConcurrentApiScope<JSSharedTypedArray> scope(thread, thisHandle);
1770 return BuiltinsArray::Includes(argv);
1771 }
1772 } // namespace panda::ecmascript::builtins
1773