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