1 /*
2 * Copyright (c) 2021-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/base/typed_array_helper.h"
17
18 #include "ecmascript/base/typed_array_helper-inl.h"
19 #include "ecmascript/containers/containers_errors.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_function.h"
22 #include "ecmascript/js_object-inl.h"
23 #include "ecmascript/js_stable_array.h"
24 #include "ecmascript/property_detector-inl.h"
25 #include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
26
27 namespace panda::ecmascript::base {
28 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
29 using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer;
30 using ContainerError = containers::ContainerError;
31
32 // es11 22.2.4 The TypedArray Constructors
TypedArrayConstructor(EcmaRuntimeCallInfo * argv,const JSHandle<JSTaggedValue> & constructorName,const DataViewType arrayType)33 JSTaggedValue TypedArrayHelper::TypedArrayConstructor(EcmaRuntimeCallInfo *argv,
34 const JSHandle<JSTaggedValue> &constructorName,
35 const DataViewType arrayType)
36 {
37 ASSERT(argv);
38 JSThread *thread = argv->GetThread();
39 [[maybe_unused]] EcmaHandleScope handleScope(thread);
40 JSHandle<JSTaggedValue> newTarget = BuiltinsBase::GetNewTarget(argv);
41 // 2. If NewTarget is undefined, throw a TypeError exception.
42 if (newTarget->IsUndefined()) {
43 THROW_TYPE_ERROR_AND_RETURN(thread, "The NewTarget is undefined.", JSTaggedValue::Exception());
44 }
45 // 3. Let constructorName be the String value of the Constructor Name value specified in Table 61 for this
46 // TypedArray constructor.
47 // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%").
48 JSHandle<JSTaggedValue> firstArg = BuiltinsBase::GetCallArg(argv, 0);
49 if (!firstArg->IsECMAObject()) {
50 // es11 22.2.4.1 TypedArray ( )
51 uint32_t elementLength = 0;
52 // es11 22.2.4.2 TypedArray ( length )
53 if (!firstArg->IsUndefined()) {
54 JSTaggedNumber index = JSTaggedValue::ToIndex(thread, firstArg);
55 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
56 elementLength = static_cast<uint32_t>(index.GetNumber());
57 }
58 JSHandle<JSObject> obj = TypedArrayHelper::AllocateTypedArray(thread, constructorName, newTarget,
59 elementLength, arrayType);
60 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
61 return obj.GetTaggedValue();
62 }
63
64 JSHandle<JSObject> obj = TypedArrayHelper::AllocateTypedArray(thread, constructorName, newTarget, arrayType);
65 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
66 if (firstArg->IsTypedArray()) {
67 return TypedArrayHelper::CreateFromTypedArray(argv, obj, arrayType);
68 }
69 if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer()) {
70 return TypedArrayHelper::CreateFromArrayBuffer(argv, obj, arrayType);
71 }
72 if (firstArg->IsStableJSArray(thread)) {
73 return TypedArrayHelper::FastCopyElementFromArray(argv, obj, arrayType);
74 }
75 if (firstArg->IsSendableArrayBuffer()) {
76 auto error = ContainerError::BusinessError(thread, containers::ErrorFlag::TYPE_ERROR,
77 "Parameter error. Not support Created from SendableArrayBuffer yet.");
78 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
79 }
80 return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj, arrayType);
81 }
82
83 // es11 22.2.4 The TypedArray Constructors
SharedTypedArrayConstructor(EcmaRuntimeCallInfo * argv,const JSHandle<JSTaggedValue> & constructorName,const DataViewType arrayType)84 JSTaggedValue TypedArrayHelper::SharedTypedArrayConstructor(EcmaRuntimeCallInfo *argv,
85 const JSHandle<JSTaggedValue> &constructorName,
86 const DataViewType arrayType)
87 {
88 ASSERT(argv);
89 JSThread *thread = argv->GetThread();
90 [[maybe_unused]] EcmaHandleScope handleScope(thread);
91 JSHandle<JSTaggedValue> newTarget = BuiltinsBase::GetNewTarget(argv);
92 // 2. If NewTarget is undefined, throw a TypeError exception.
93 if (newTarget->IsUndefined()) {
94 JSTaggedValue error = ContainerError::BusinessError(thread, containers::ErrorFlag::IS_NULL_ERROR,
95 "The ArkTS TypedArray's constructor cannot be directly invoked.");
96 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
97 }
98 // 3. Let constructorName be the String value of the Constructor Name value specified in Table 61 for this
99 // TypedArray constructor.
100 // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%").
101 JSHandle<JSTaggedValue> firstArg = BuiltinsBase::GetCallArg(argv, 0);
102 if (!firstArg->IsECMAObject()) {
103 // es11 22.2.4.1 TypedArray ( )
104 uint32_t elementLength = 0;
105 // es11 22.2.4.2 TypedArray ( length )
106 if (!firstArg->IsUndefined()) {
107 JSTaggedNumber index = JSTaggedValue::ToIndex(thread, firstArg);
108 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
109 elementLength = static_cast<uint32_t>(index.GetNumber());
110 }
111 JSHandle<JSObject> obj = TypedArrayHelper::AllocateSharedTypedArray(thread, constructorName, newTarget,
112 elementLength, arrayType);
113 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
114 return obj.GetTaggedValue();
115 }
116
117 JSHandle<JSObject> obj = TypedArrayHelper::AllocateSharedTypedArray(thread, constructorName, newTarget, arrayType);
118 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
119 if (firstArg->IsTypedArray() || firstArg->IsSharedTypedArray()) {
120 return TypedArrayHelper::CreateSharedFromTypedArray(argv, obj, arrayType);
121 }
122 if (firstArg->IsSendableArrayBuffer()) {
123 return TypedArrayHelper::CreateFromSendableArrayBuffer(argv, obj, arrayType);
124 }
125 if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer()) {
126 auto error = ContainerError::BusinessError(thread, containers::ErrorFlag::TYPE_ERROR,
127 "Parameter error. Only accept sendable value.");
128 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
129 }
130 if (firstArg->IsStableJSArray(thread)) {
131 return TypedArrayHelper::FastCopyElementFromArray<TypedArrayKind::SHARED>(argv, obj, arrayType);
132 }
133 return TypedArrayHelper::CreateFromOrdinaryObject<TypedArrayKind::SHARED>(argv, obj, arrayType);
134 }
135
136 // Fastpath for create a typedarray. Do not need to create an EcmaRuntimeCallInfo.
FastCreateTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & constructorName,uint32_t length,const DataViewType arrayType)137 JSHandle<JSObject> TypedArrayHelper::FastCreateTypedArray(JSThread *thread,
138 const JSHandle<JSTaggedValue> &constructorName,
139 uint32_t length,
140 const DataViewType arrayType)
141 {
142 JSHandle<JSObject> exception(thread, JSTaggedValue::Exception());
143 if (length > JSTypedArray::MAX_TYPED_ARRAY_INDEX) {
144 THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception);
145 }
146
147 // Create TypedArray
148 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
149 JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetConstructorFromType(thread, arrayType);
150 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc,
151 JSHandle<JSTaggedValue>::Cast(typedArrayFunc));
152 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
153 JSTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName);
154
155 // Create ArrayBuffer
156 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
157 uint32_t arrayLength = static_cast<uint32_t>(length);
158 uint64_t byteLength = static_cast<uint64_t>(elementSize) * length;
159 JSHandle<JSTaggedValue> data;
160
161 JSHandle<JSTaggedValue> constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetArrayBufferFunction();
162 data = JSHandle<JSTaggedValue>(thread,
163 BuiltinsArrayBuffer::AllocateArrayBuffer(thread, constructor, byteLength));
164 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception);
165
166 // Assign ArrayBuffer to TypedArray
167 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
168 if (arrayType == DataViewType::BIGINT64 ||
169 arrayType == DataViewType::BIGUINT64) {
170 jsTypedArray->SetContentType(ContentType::BigInt);
171 } else {
172 jsTypedArray->SetContentType(ContentType::Number);
173 }
174 // Set O.[[ViewedArrayBuffer]] to data.
175 // Set O.[[ByteLength]] to byteLength.
176 // Set O.[[ByteOffset]] to 0.
177 // Set O.[[ArrayLength]] to length.
178 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data);
179 jsTypedArray->SetByteLength(byteLength);
180 jsTypedArray->SetByteOffset(0);
181 jsTypedArray->SetArrayLength(arrayLength);
182 // Return O.
183 return obj;
184 }
185
186 template<>
AllocateTypedArrayBuffer(JSThread * thread,const JSHandle<JSObject> & obj,uint64_t length,const DataViewType arrayType)187 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArrayBuffer<TypedArrayKind::NON_SHARED>(
188 JSThread *thread, const JSHandle<JSObject> &obj, uint64_t length, const DataViewType arrayType)
189 {
190 // 1. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
191 // 2. Assert: O.[[ViewedArrayBuffer]] is undefined.
192 // 3. Assert: ! IsNonNegativeInteger(length) is true.
193 JSHandle<JSObject> exception(thread, JSTaggedValue::Exception());
194 if (length > JSTypedArray::MAX_TYPED_ARRAY_INDEX) {
195 THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception);
196 }
197 // 4. Let constructorName be the String value of O.[[TypedArrayName]].
198 // we use type to get size
199 // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
200 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
201 // 6. Let byteLength be elementSize × length.
202 uint32_t arrayLength = static_cast<uint32_t>(length);
203 uint64_t byteLength = static_cast<uint64_t>(elementSize) * length;
204 // 7. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength).
205 JSHandle<JSTaggedValue> data;
206 if (byteLength > JSTypedArray::MAX_ONHEAP_LENGTH) {
207 JSHandle<JSTaggedValue> constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetArrayBufferFunction();
208 data = JSHandle<JSTaggedValue>(thread,
209 BuiltinsArrayBuffer::AllocateArrayBuffer(thread, constructor, byteLength));
210 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
211 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
212 } else {
213 data = JSHandle<JSTaggedValue>(thread,
214 thread->GetEcmaVM()->GetFactory()->NewByteArray(arrayLength, elementSize).GetTaggedValue());
215 JSHandle<JSHClass> onHeapHclass = TypedArrayHelper::GetOnHeapHclassFromType(
216 thread, JSHandle<JSTypedArray>(obj), arrayType);
217 #if ECMASCRIPT_ENABLE_IC
218 JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, obj->GetJSHClass()), onHeapHclass);
219 #endif
220 TaggedObject::Cast(*obj)->SynchronizedSetClass(thread, *onHeapHclass); // notOnHeap->onHeap
221 }
222 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception);
223 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
224 if (arrayType == DataViewType::BIGINT64 ||
225 arrayType == DataViewType::BIGUINT64) {
226 jsTypedArray->SetContentType(ContentType::BigInt);
227 } else {
228 jsTypedArray->SetContentType(ContentType::Number);
229 }
230 // 8. Set O.[[ViewedArrayBuffer]] to data.
231 // 9. Set O.[[ByteLength]] to byteLength.
232 // 10. Set O.[[ByteOffset]] to 0.
233 // 11. Set O.[[ArrayLength]] to length.
234 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data);
235 jsTypedArray->SetByteLength(byteLength);
236 jsTypedArray->SetByteOffset(0);
237 jsTypedArray->SetArrayLength(arrayLength);
238 // 12. Return O.
239 return obj;
240 }
241
242 template<>
AllocateTypedArrayBuffer(JSThread * thread,const JSHandle<JSObject> & obj,uint64_t length,const DataViewType arrayType)243 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArrayBuffer<TypedArrayKind::SHARED>(
244 JSThread *thread, const JSHandle<JSObject> &obj, uint64_t length, const DataViewType arrayType)
245 {
246 // 1. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
247 // 2. Assert: O.[[ViewedArrayBuffer]] is undefined.
248 // 3. Assert: ! IsNonNegativeInteger(length) is true.
249 JSHandle<JSObject> exception(thread, JSTaggedValue::Exception());
250 if (length > JSTypedArray::MAX_TYPED_ARRAY_INDEX) {
251 THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception);
252 }
253 // 4. Let constructorName be the String value of O.[[TypedArrayName]].
254 // we use type to get size
255 // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
256 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
257 // 6. Let byteLength be elementSize × length.
258 uint32_t arrayLength = static_cast<uint32_t>(length);
259 uint64_t byteLength = static_cast<uint64_t>(elementSize) * length;
260 // 7. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength).
261 JSHandle<JSTaggedValue> data;
262 if (byteLength > JSTypedArray::MAX_ONHEAP_LENGTH) {
263 JSHandle<JSTaggedValue> constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetSBuiltininArrayBufferFunction();
264 data = JSHandle<JSTaggedValue>(thread,
265 BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer(thread, constructor, byteLength));
266 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
267 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
268 } else {
269 data = JSHandle<JSTaggedValue>(thread,
270 thread->GetEcmaVM()->GetFactory()->NewByteArray(arrayLength, elementSize, nullptr,
271 MemSpaceType::SHARED_OLD_SPACE).GetTaggedValue());
272 JSHandle<JSHClass> onHeapHclass = TypedArrayHelper::GetSharedOnHeapHclassFromType(
273 thread, JSHandle<JSTypedArray>(obj), arrayType);
274 #if ECMASCRIPT_ENABLE_IC
275 JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, obj->GetJSHClass()), onHeapHclass);
276 #endif
277 TaggedObject::Cast(*obj)->SynchronizedSetClass(thread, *onHeapHclass); // notOnHeap->onHeap
278 }
279 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception);
280 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
281 if (arrayType == DataViewType::BIGINT64 ||
282 arrayType == DataViewType::BIGUINT64) {
283 jsTypedArray->SetContentType(ContentType::BigInt);
284 } else {
285 jsTypedArray->SetContentType(ContentType::Number);
286 }
287 // 8. Set O.[[ViewedArrayBuffer]] to data.
288 // 9. Set O.[[ByteLength]] to byteLength.
289 // 10. Set O.[[ByteOffset]] to 0.
290 // 11. Set O.[[ArrayLength]] to length.
291 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data);
292 jsTypedArray->SetByteLength(byteLength);
293 jsTypedArray->SetByteOffset(0);
294 jsTypedArray->SetArrayLength(arrayLength);
295 // 12. Return O.
296 return obj;
297 }
298
299 template JSTaggedValue TypedArrayHelper::FastCopyElementFromArray<TypedArrayKind::NON_SHARED>(
300 EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const DataViewType arrayType);
301 template JSTaggedValue TypedArrayHelper::FastCopyElementFromArray<TypedArrayKind::SHARED>(
302 EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const DataViewType arrayType);
303
304 template<TypedArrayKind typedArrayKind>
FastCopyElementFromArray(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)305 JSTaggedValue TypedArrayHelper::FastCopyElementFromArray(
306 EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const DataViewType arrayType)
307 {
308 ASSERT(argv);
309 JSThread *thread = argv->GetThread();
310 [[maybe_unused]] EcmaHandleScope handleScope(thread);
311 JSHandle<JSTaggedValue> argArray = BuiltinsBase::GetCallArg(argv, 0);
312 uint32_t len = JSHandle<JSArray>::Cast(argArray)->GetArrayLength();
313 JSHandle<JSObject> argObj(argArray);
314 // load on demand check
315 if (ElementAccessor::GetElementsLength(argObj) < len) {
316 TypedArrayHelper::CreateFromOrdinaryObject<typedArrayKind>(argv, obj, arrayType);
317 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
318 return obj.GetTaggedValue();
319 }
320
321 TypedArrayHelper::AllocateTypedArrayBuffer<typedArrayKind>(thread, obj, len, arrayType);
322 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
323 JSHandle<JSTypedArray> targetObj = JSHandle<JSTypedArray>::Cast(obj);
324
325 JSStableArray::FastCopyFromArrayToTypedArray<typedArrayKind>(
326 thread, targetObj, arrayType, 0, len, argObj);
327 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
328 return JSHandle<JSObject>::Cast(targetObj).GetTaggedValue();
329 }
330
331 template JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject<TypedArrayKind::SHARED>(
332 EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const DataViewType arrayType);
333 template JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject<TypedArrayKind::NON_SHARED>(
334 EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const DataViewType arrayType);
335
336 // es11 22.2.4.4 TypedArray ( object )
337 template <TypedArrayKind typedArrayKind>
CreateFromOrdinaryObject(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)338 JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
339 const DataViewType arrayType)
340 {
341 ASSERT(argv);
342 JSThread *thread = argv->GetThread();
343 [[maybe_unused]] EcmaHandleScope handleScope(thread);
344 EcmaVM *ecmaVm = thread->GetEcmaVM();
345 JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
346 JSHandle<JSTaggedValue> objectArg = BuiltinsBase::GetCallArg(argv, 0);
347 JSHandle<JSObject> object(objectArg);
348 // 5. Let usingIterator be ? GetMethod(object, @@iterator).
349 JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
350 JSHandle<JSTaggedValue> usingIterator =
351 JSObject::GetMethod(thread, JSHandle<JSTaggedValue>::Cast(object), iteratorSymbol);
352 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
353
354 // 6. If usingIterator is not undefined, then
355 if (!usingIterator->IsUndefined()) {
356 CVector<JSHandle<JSTaggedValue>> vec;
357 // a. Let values be ? IterableToList(object, usingIterator).
358 // b. Let len be the number of elements in values.
359 // c. Perform ? AllocateTypedArrayBuffer(O, len).
360 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, objectArg, usingIterator);
361 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
362 JSHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
363 while (!next->IsFalse()) {
364 next = JSIterator::IteratorStep(thread, iterator);
365 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
366 if (!next->IsFalse()) {
367 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
368 vec.push_back(nextValue);
369 }
370 }
371 uint32_t len = static_cast<uint32_t>(vec.size());
372 TypedArrayHelper::AllocateTypedArrayBuffer<typedArrayKind>(thread, obj, len, arrayType);
373 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374 // d. Let k be 0.
375 // e. Repeat, while k < len
376 // i. Let Pk be ! ToString(k).
377 // ii. Let kValue be the first element of values and remove that element from values.
378 // iii. Perform ? Set(O, Pk, kValue, true).
379 // iv. Set k to k + 1.
380 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
381 uint32_t k = 0;
382 while (k < len) {
383 tKey.Update(JSTaggedValue(k));
384 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
385 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
386 JSHandle<JSTaggedValue> kValue = vec[k];
387 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
388 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
389 k++;
390 }
391 // f. Assert: values is now an empty List.
392 // g. Return O.
393 return obj.GetTaggedValue();
394 }
395
396 // 7. NOTE: object is not an Iterable so assume it is already an array-like object.
397 // 8. Let arrayLike be object.
398 // 9. Let len be ? LengthOfArrayLike(arrayLike).
399 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
400 JSTaggedNumber lenTemp =
401 JSTaggedValue::ToLength(thread, JSTaggedValue::GetProperty(thread, objectArg, lengthKey).GetValue());
402 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
403 uint64_t rawLen = lenTemp.GetNumber();
404 // 10. Perform ? AllocateTypedArrayBuffer(O, len).
405 TypedArrayHelper::AllocateTypedArrayBuffer<typedArrayKind>(thread, obj, rawLen, arrayType);
406 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
407 // 11. Let k be 0.
408 // 12. Repeat, while k < len
409 // a. Let Pk be ! ToString(k).
410 // b. Let kValue be ? Get(arrayLike, Pk).
411 // c. Perform ? Set(O, Pk, kValue, true).
412 // d. Set k to k + 1.
413 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
414 uint32_t len = static_cast<uint32_t>(rawLen);
415 uint32_t k = 0;
416 while (k < len) {
417 tKey.Update(JSTaggedValue(k));
418 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
419 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
420 JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, objectArg, kKey).GetValue();
421 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
422 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
423 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
424 k++;
425 }
426 // 13. Return O.
427 return obj.GetTaggedValue();
428 }
429
430 // es11 22.2.4.3 TypedArray ( typedArray )
CreateFromTypedArray(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)431 JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
432 const DataViewType arrayType)
433 {
434 ASSERT(argv);
435 JSThread *thread = argv->GetThread();
436 [[maybe_unused]] EcmaHandleScope handleScope(thread);
437 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
438 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
439 // 5. Let srcArray be typedArray.
440 JSHandle<JSTaggedValue> srcArray = BuiltinsBase::GetCallArg(argv, 0);
441 JSHandle<JSTypedArray> srcObj(srcArray);
442 // 6. Let srcData be srcArray.[[ViewedArrayBuffer]].
443 JSHandle<JSTaggedValue> srcData(thread, JSTypedArray::GetOffHeapBuffer(thread, srcObj));
444 // 7. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
445 if (BuiltinsArrayBuffer::IsDetachedBuffer(srcData.GetTaggedValue())) {
446 THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
447 }
448 // 8. Let elementType be the Element Type value in Table 61 for constructorName.
449 // which is arrayType passed in.
450 // 9. Let elementLength be srcArray.[[ArrayLength]].
451 // 10. Let srcName be the String value of srcArray.[[TypedArrayName]].
452 // 11. Let srcType be the Element Type value in Table 61 for srcName.
453 // 12. Let srcElementSize be the Element Size value specified in Table 61 for srcName.
454 uint32_t elementLength = srcObj->GetArrayLength();
455 JSHandle<JSTaggedValue> srcName(thread, srcObj->GetTypedArrayName());
456 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
457 uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType);
458 // 13. Let srcByteOffset be srcArray.[[ByteOffset]].
459 // 14. Let elementSize be the Element Size value specified in Table 61 for constructorName.
460 // 15. Let byteLength be elementSize × elementLength.
461 uint32_t srcByteOffset = srcObj->GetByteOffset();
462 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
463 // If elementLength is a large number, the multiplication of elementSize and elementLength may exceed
464 // the maximum value of uint32, resulting in data overflow. Therefore, the type of byteLength is uint64_t.
465 uint64_t byteLength = elementSize * static_cast<uint64_t>(elementLength);
466 // 16. If IsSharedArrayBuffer(srcData) is false, then
467 // a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
468
469 JSMutableHandle<JSTaggedValue> data(thread, JSTaggedValue::Undefined());
470 // 18. If elementType is the same as srcType, then
471 // a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor).
472 if (arrayType == srcType) {
473 JSTaggedValue tmp =
474 BuiltinsArrayBuffer::CloneArrayBuffer(thread, srcData, srcByteOffset, globalConst->GetHandledUndefined());
475 data.Update(tmp);
476 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
477 } else {
478 // 19. Else,
479 // a. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength).
480 JSHandle<JSTaggedValue> bufferConstructor =
481 JSObject::SpeciesConstructor(thread, JSHandle<JSObject>(srcData), env->GetArrayBufferFunction());
482 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
483 JSTaggedValue tmp = BuiltinsArrayBuffer::AllocateArrayBuffer(thread, bufferConstructor, byteLength);
484 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
485 data.Update(tmp);
486 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
487 // b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
488 if (BuiltinsArrayBuffer::IsDetachedBuffer(srcData.GetTaggedValue())) {
489 THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
490 }
491 ContentType objContentType = JSHandle<JSTypedArray>::Cast(obj)->GetContentType();
492 ContentType srcArrayContentType = JSHandle<JSTypedArray>::Cast(srcArray)->GetContentType();
493 if (srcArrayContentType != objContentType) {
494 THROW_TYPE_ERROR_AND_RETURN(thread, "srcArrayContentType is not equal objContentType.",
495 JSTaggedValue::Exception());
496 }
497 // d. Let srcByteIndex be srcByteOffset.
498 // e. Let targetByteIndex be 0.
499 uint32_t srcByteIndex = srcByteOffset;
500 uint32_t targetByteIndex = 0;
501 // f. Let count be elementLength.
502 // g. Repeat, while count > 0
503 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
504 for (uint32_t count = elementLength; count > 0; count--) {
505 // i. Let value be GetValueFromBuffer(srcData, srcByteIndex, srcType, true, Unordered).
506 JSTaggedValue taggedData =
507 BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcData.GetTaggedValue(), srcByteIndex, srcType, true);
508 value.Update(taggedData);
509 // ii. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, Unordered).
510 BuiltinsArrayBuffer::SetValueInBuffer(thread, data.GetTaggedValue(),
511 targetByteIndex, arrayType, value, true);
512 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
513 // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
514 // iv. Set targetByteIndex to targetByteIndex + elementSize.
515 // v. Set count to count - 1.
516 srcByteIndex = srcByteIndex + srcElementSize;
517 targetByteIndex = targetByteIndex + elementSize;
518 }
519 }
520 // 19. Set O’s [[ViewedArrayBuffer]] internal slot to data.
521 // 20. Set O’s [[ByteLength]] internal slot to byteLength.
522 // 21. Set O’s [[ByteOffset]] internal slot to 0.
523 // 22. Set O’s [[ArrayLength]] internal slot to elementLength.
524 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
525 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data);
526 jsTypedArray->SetByteLength(byteLength);
527 jsTypedArray->SetByteOffset(0);
528 jsTypedArray->SetArrayLength(elementLength);
529 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
530 // 23. Return O.
531 return obj.GetTaggedValue();
532 }
533
GetTypedArrayBuffer(EcmaRuntimeCallInfo * argv,JSHandle<JSTypedArray> & srcObj,bool isIsSharedTypedArray)534 JSTaggedValue GetTypedArrayBuffer(EcmaRuntimeCallInfo *argv, JSHandle<JSTypedArray> &srcObj,
535 bool isIsSharedTypedArray)
536 {
537 JSThread *thread = argv->GetThread();
538 JSTaggedValue buffer;
539 if (isIsSharedTypedArray) {
540 buffer = JSSharedTypedArray::GetSharedOffHeapBuffer(thread, JSHandle<JSSharedTypedArray>(srcObj));
541 } else {
542 buffer = JSTypedArray::GetOffHeapBuffer(thread, srcObj);
543 }
544 if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
545 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
546 JSTaggedValue::Exception());
547 }
548 if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
549 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
550 JSTaggedValue::Exception());
551 }
552 return buffer;
553 }
554
CheckBufferAndType(JSTaggedValue buffer,JSThread * thread,const JSHandle<JSObject> & obj,JSHandle<JSTaggedValue> srcArray)555 JSTaggedValue CheckBufferAndType(JSTaggedValue buffer, JSThread *thread, const JSHandle<JSObject> &obj,
556 JSHandle<JSTaggedValue> srcArray)
557 {
558 // b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
559 if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
560 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
561 JSTaggedValue::Exception());
562 }
563 if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
564 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
565 JSTaggedValue::Exception());
566 }
567
568 ContentType objContentType = JSHandle<JSTypedArray>::Cast(obj)->GetContentType();
569 ContentType srcArrayContentType = JSHandle<JSTypedArray>::Cast(srcArray)->GetContentType();
570 if (srcArrayContentType != objContentType) {
571 THROW_TYPE_ERROR_AND_RETURN(thread, "srcArrayContentType is not equal objContentType.",
572 JSTaggedValue::Exception());
573 }
574 return JSTaggedValue::True();
575 }
576
SetTypedArrayProperties(JSThread * thread,const JSHandle<JSObject> & obj,JSMutableHandle<JSTaggedValue> & data,const uint64_t byteLength,const uint32_t elementLength)577 void SetTypedArrayProperties(JSThread *thread, const JSHandle<JSObject> &obj, JSMutableHandle<JSTaggedValue> &data,
578 const uint64_t byteLength, const uint32_t elementLength)
579 {
580 // 19. Set O’s [[ViewedArrayBuffer]] internal slot to data.
581 // 20. Set O’s [[ByteLength]] internal slot to byteLength.
582 // 21. Set O’s [[ByteOffset]] internal slot to 0.
583 // 22. Set O’s [[ArrayLength]] internal slot to elementLength.
584 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
585 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data);
586 jsTypedArray->SetByteLength(byteLength);
587 jsTypedArray->SetByteOffset(0);
588 jsTypedArray->SetArrayLength(elementLength);
589 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
590 }
591
CloneAndUpdateArrayBuffer(JSThread * thread,JSHandle<JSTaggedValue> srcData,uint32_t srcByteOffset,JSMutableHandle<JSTaggedValue> & data)592 void CloneAndUpdateArrayBuffer(JSThread *thread, JSHandle<JSTaggedValue> srcData, uint32_t srcByteOffset,
593 JSMutableHandle<JSTaggedValue> &data)
594 {
595 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
596 JSTaggedValue tmp = BuiltinsSendableArrayBuffer::CloneArrayBuffer(thread, srcData, srcByteOffset,
597 globalConst->GetHandledUndefined());
598 data.Update(tmp);
599 }
600
AllocatAndUpdateArrayBuffer(JSThread * thread,uint64_t byteLength,JSMutableHandle<JSTaggedValue> & data)601 JSTaggedValue AllocatAndUpdateArrayBuffer(JSThread *thread, uint64_t byteLength,
602 JSMutableHandle<JSTaggedValue> &data)
603 {
604 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
605 // 19. Else,
606 // a. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength).
607 JSHandle<JSTaggedValue> bufferConstructor = env->GetSBuiltininArrayBufferFunction();
608 JSTaggedValue tmp =
609 BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer(thread, bufferConstructor, byteLength);
610 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
611 data.Update(tmp);
612 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
613 return JSTaggedValue::True();
614 }
615
CreateSharedFromTypedArray(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)616 JSTaggedValue TypedArrayHelper::CreateSharedFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
617 const DataViewType arrayType)
618 {
619 ASSERT(argv);
620 JSThread *thread = argv->GetThread();
621 [[maybe_unused]] EcmaHandleScope handleScope(thread);
622 // 5. Let srcArray be typedArray.
623 JSHandle<JSTaggedValue> srcArray = BuiltinsBase::GetCallArg(argv, 0);
624 JSHandle<JSTypedArray> srcObj(srcArray);
625 JSTaggedValue buffer = GetTypedArrayBuffer(argv, srcObj, srcArray->IsSharedTypedArray());
626 if (buffer == JSTaggedValue::Exception()) {
627 return buffer;
628 }
629 // 6. Let srcData be srcArray.[[ViewedArrayBuffer]].
630 JSHandle<JSTaggedValue> srcData(thread, buffer);
631 // 8. Let elementType be the Element Type value in Table 61 for constructorName.
632 // which is arrayType passed in.
633 // 9. Let elementLength be srcArray.[[ArrayLength]].
634 // 10. Let srcName be the String value of srcArray.[[TypedArrayName]].
635 // 11. Let srcType be the Element Type value in Table 61 for srcName.
636 // 12. Let srcElementSize be the Element Size value specified in Table 61 for srcName.
637 uint32_t elementLength = srcObj->GetArrayLength();
638 JSHandle<JSTaggedValue> srcName(thread, srcObj->GetTypedArrayName());
639 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
640 uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType);
641 // 13. Let srcByteOffset be srcArray.[[ByteOffset]].
642 // 14. Let elementSize be the Element Size value specified in Table 61 for constructorName.
643 // 15. Let byteLength be elementSize × elementLength.
644 uint32_t srcByteOffset = srcObj->GetByteOffset();
645 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
646 // If elementLength is a large number, the multiplication of elementSize and elementLength may exceed
647 // the maximum value of uint32, resulting in data overflow. Therefore, the type of byteLength is uint64_t.
648 uint64_t byteLength = elementSize * static_cast<uint64_t>(elementLength);
649 // 16. If IsSharedArrayBuffer(srcData) is false, then
650 // a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
651 JSMutableHandle<JSTaggedValue> data(thread, JSTaggedValue::Undefined());
652 // 18. If elementType is the same as srcType, then
653 // a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor).
654 if (arrayType == srcType && srcArray->IsSharedTypedArray()) {
655 CloneAndUpdateArrayBuffer(thread, srcData, srcByteOffset, data);
656 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
657 } else {
658 JSTaggedValue allocateResult = AllocatAndUpdateArrayBuffer(thread, byteLength, data);
659 if (allocateResult == JSTaggedValue::Exception()) {
660 return allocateResult;
661 }
662 JSTaggedValue checkResult = CheckBufferAndType(srcData.GetTaggedValue(), thread, obj, srcArray);
663 if (checkResult == JSTaggedValue::Exception()) {
664 return checkResult;
665 }
666 // d. Let srcByteIndex be srcByteOffset.
667 // e. Let targetByteIndex be 0.
668 uint32_t srcByteIndex = srcByteOffset;
669 uint32_t targetByteIndex = 0;
670 // f. Let count be elementLength.
671 // g. Repeat, while count > 0
672 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
673 for (uint32_t count = elementLength; count > 0; count--) {
674 // i. Let value be GetValueFromBuffer(srcData, srcByteIndex, srcType, true, Unordered).
675 JSTaggedValue taggedData = BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcData.GetTaggedValue(),
676 srcByteIndex, srcType, true);
677 value.Update(taggedData);
678 // ii. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, Unordered).
679 BuiltinsArrayBuffer::SetValueInBuffer(thread, data.GetTaggedValue(), targetByteIndex, arrayType, value,
680 true);
681 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
682 // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
683 // iv. Set targetByteIndex to targetByteIndex + elementSize.
684 // v. Set count to count - 1.
685 srcByteIndex = srcByteIndex + srcElementSize;
686 targetByteIndex = targetByteIndex + elementSize;
687 }
688 }
689 SetTypedArrayProperties(thread, obj, data, byteLength, elementLength);
690 // 23. Return O.
691 return obj.GetTaggedValue();
692 }
693
SetArrayBufferProperties(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const uint64_t newByteLength,const uint32_t offset,const uint32_t arrayLength)694 void SetArrayBufferProperties(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj, const uint64_t newByteLength,
695 const uint32_t offset, const uint32_t arrayLength)
696 {
697 JSThread *thread = argv->GetThread();
698 JSHandle<JSTaggedValue> buffer = BuiltinsBase::GetCallArg(argv, 0);
699 // 13. Set O.[[ViewedArrayBuffer]] to buffer.
700 // 14. Set O.[[ByteLength]] to newByteLength.
701 // 15. Set O.[[ByteOffset]] to offset.
702 // 16. Set O.[[ArrayLength]] to newByteLength / elementSize.
703 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
704 jsTypedArray->SetViewedArrayBufferOrByteArray(thread, buffer);
705 jsTypedArray->SetByteLength(newByteLength);
706 jsTypedArray->SetByteOffset(offset);
707 jsTypedArray->SetArrayLength(arrayLength);
708 }
709
710 // es11 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
CreateFromArrayBuffer(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)711 JSTaggedValue TypedArrayHelper::CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
712 const DataViewType arrayType)
713 {
714 ASSERT(argv);
715 JSThread *thread = argv->GetThread();
716 [[maybe_unused]] EcmaHandleScope handleScope(thread);
717 // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
718 // 6. Let offset be ? ToIndex(byteOffset).
719 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
720 JSHandle<JSTaggedValue> byteOffset = BuiltinsBase::GetCallArg(argv, 1);
721 JSTaggedNumber index = JSTaggedValue::ToIndex(thread, byteOffset);
722 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
723 auto offset = static_cast<uint32_t>(index.GetNumber());
724 // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
725 if (offset % elementSize != 0) {
726 THROW_RANGE_ERROR_AND_RETURN(thread, "The offset cannot be an integral multiple of elementSize.",
727 JSTaggedValue::Exception());
728 }
729 // 8. If length is not undefined, then
730 // a. Let newLength be ? ToIndex(length).
731 JSHandle<JSTaggedValue> length = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
732 uint64_t newLength = 0;
733 if (!length->IsUndefined()) {
734 index = JSTaggedValue::ToIndex(thread, length);
735 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
736 newLength = static_cast<uint64_t>(index.GetNumber());
737 }
738 // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
739 JSHandle<JSTaggedValue> buffer = BuiltinsBase::GetCallArg(argv, 0);
740 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
741 THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
742 }
743 // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
744 uint32_t bufferByteLength = JSHandle<JSArrayBuffer>(buffer)->GetArrayBufferByteLength();
745 // 11. If length is undefined, then
746 // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
747 // b. Let newByteLength be bufferByteLength - offset.
748 // c. If newByteLength < 0, throw a RangeError exception.
749 uint64_t newByteLength = 0;
750 if (length->IsUndefined()) {
751 if (bufferByteLength % elementSize != 0) {
752 std::string ctorName = EcmaStringAccessor(
753 JSTaggedValue::ToString(thread, GetConstructorNameFromType(thread, arrayType))).ToStdString();
754 std::string message = "The byte length of " + ctorName + " should be a multiple of " +
755 std::to_string(elementSize);
756 THROW_RANGE_ERROR_AND_RETURN(thread, message.c_str(), JSTaggedValue::Exception());
757 }
758 if (bufferByteLength < offset) {
759 THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is less than 0.", JSTaggedValue::Exception());
760 }
761 newByteLength = bufferByteLength - offset;
762 } else {
763 // 12. Else,
764 // a. Let newByteLength be newLength × elementSize.
765 // b. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
766 newByteLength = newLength * elementSize;
767 if (offset + newByteLength > bufferByteLength) {
768 THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is out of range.", JSTaggedValue::Exception());
769 }
770 }
771 SetArrayBufferProperties(argv, obj, newByteLength, offset, newByteLength / elementSize);
772 // 17. Return O.
773 return obj.GetTaggedValue();
774 }
775
776 // es11 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const DataViewType arrayType)777 JSTaggedValue TypedArrayHelper::CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo *argv,
778 const JSHandle<JSObject> &obj,
779 const DataViewType arrayType)
780 {
781 ASSERT(argv);
782 JSThread *thread = argv->GetThread();
783 [[maybe_unused]] EcmaHandleScope handleScope(thread);
784 // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
785 // 6. Let offset be ? ToIndex(byteOffset).
786 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
787 JSHandle<JSTaggedValue> byteOffset = BuiltinsBase::GetCallArg(argv, 1);
788 JSTaggedNumber index = JSTaggedValue::ToIndex(thread, byteOffset);
789 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
790 auto offset = static_cast<uint32_t>(index.GetNumber());
791 // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
792 if (offset % elementSize != 0) {
793 THROW_RANGE_ERROR_AND_RETURN(thread, "The offset cannot be an integral multiple of elementSize.",
794 JSTaggedValue::Exception());
795 }
796 // 8. If length is not undefined, then
797 // a. Let newLength be ? ToIndex(length).
798 JSHandle<JSTaggedValue> length = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
799 uint64_t newLength = 0;
800 if (!length->IsUndefined()) {
801 index = JSTaggedValue::ToIndex(thread, length);
802 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
803 newLength = static_cast<uint64_t>(index.GetNumber());
804 }
805 // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
806 JSHandle<JSTaggedValue> buffer = BuiltinsBase::GetCallArg(argv, 0);
807 if (BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
808 THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
809 }
810 // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
811 uint32_t bufferByteLength = JSHandle<JSSendableArrayBuffer>(buffer)->GetArrayBufferByteLength();
812 // 11. If length is undefined, then
813 // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
814 // b. Let newByteLength be bufferByteLength - offset.
815 // c. If newByteLength < 0, throw a RangeError exception.
816 uint64_t newByteLength = 0;
817 if (length->IsUndefined()) {
818 if (bufferByteLength % elementSize != 0) {
819 std::string ctorName = EcmaStringAccessor(
820 JSTaggedValue::ToString(thread, GetConstructorNameFromType(thread, arrayType))).ToStdString();
821 std::string message = "The byte length of " + ctorName + " should be a multiple of " +
822 std::to_string(elementSize);
823 THROW_RANGE_ERROR_AND_RETURN(thread, message.c_str(), JSTaggedValue::Exception());
824 }
825 if (bufferByteLength < offset) {
826 THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is less than 0.", JSTaggedValue::Exception());
827 }
828 newByteLength = bufferByteLength - offset;
829 } else {
830 // 12. Else,
831 // a. Let newByteLength be newLength × elementSize.
832 // b. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
833 newByteLength = newLength * elementSize;
834 if (offset + newByteLength > bufferByteLength) {
835 THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is out of range.", JSTaggedValue::Exception());
836 }
837 }
838 SetArrayBufferProperties(argv, obj, newByteLength, offset, newByteLength / elementSize);
839 // 17. Return O.
840 return obj.GetTaggedValue();
841 }
842
843 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto )
AllocateTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget,const DataViewType arrayType)844 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArray(JSThread *thread,
845 const JSHandle<JSTaggedValue> &constructorName,
846 const JSHandle<JSTaggedValue> &newTarget,
847 const DataViewType arrayType)
848 {
849 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
850 // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
851 // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
852 JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetConstructorFromType(thread, arrayType);
853 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
854 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
855 // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
856 // 4. Set obj.[[TypedArrayName]] to constructorName.
857
858 // 5. If constructorName is "BigInt64Array" or "BigUint64Array", set obj.[[ContentType]] to BigInt.
859 // 6. Otherwise, set obj.[[ContentType]] to Number.
860 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
861 if (arrayType == DataViewType::BIGINT64 ||
862 arrayType == DataViewType::BIGUINT64) {
863 jsTypedArray->SetContentType(ContentType::BigInt);
864 } else {
865 jsTypedArray->SetContentType(ContentType::Number);
866 }
867 // 7. If length is not present, then
868 // a. Set obj.[[ByteLength]] to 0.
869 // b. Set obj.[[ByteOffset]] to 0.
870 // c. Set obj.[[ArrayLength]] to 0.
871 jsTypedArray->SetTypedArrayName(thread, constructorName);
872 jsTypedArray->SetByteLength(0);
873 jsTypedArray->SetByteOffset(0);
874 jsTypedArray->SetArrayLength(0);
875 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
876 // 9. Return obj.
877 return obj;
878 }
879
880 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto )
AllocateSharedTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget,const DataViewType arrayType)881 JSHandle<JSObject> TypedArrayHelper::AllocateSharedTypedArray(JSThread *thread,
882 const JSHandle<JSTaggedValue> &constructorName,
883 const JSHandle<JSTaggedValue> &newTarget,
884 const DataViewType arrayType)
885 {
886 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
887 // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
888 // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
889 JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetSharedConstructorFromType(thread, arrayType);
890 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
891 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
892 // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
893 // 4. Set obj.[[TypedArrayName]] to constructorName.
894
895 // 5. If constructorName is "BigInt64Array" or "BigUint64Array", set obj.[[ContentType]] to BigInt.
896 // 6. Otherwise, set obj.[[ContentType]] to Number.
897 JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj);
898 if (arrayType == DataViewType::BIGINT64 ||
899 arrayType == DataViewType::BIGUINT64) {
900 jsTypedArray->SetContentType(ContentType::BigInt);
901 } else {
902 jsTypedArray->SetContentType(ContentType::Number);
903 }
904 // 7. If length is not present, then
905 // a. Set obj.[[ByteLength]] to 0.
906 // b. Set obj.[[ByteOffset]] to 0.
907 // c. Set obj.[[ArrayLength]] to 0.
908 jsTypedArray->SetTypedArrayName(thread, constructorName);
909 jsTypedArray->SetByteLength(0);
910 jsTypedArray->SetByteOffset(0);
911 jsTypedArray->SetArrayLength(0);
912 ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
913 // 9. Return obj.
914 return obj;
915 }
916
917 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto, length )
AllocateTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget,uint32_t length,const DataViewType arrayType)918 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArray(JSThread *thread,
919 const JSHandle<JSTaggedValue> &constructorName,
920 const JSHandle<JSTaggedValue> &newTarget, uint32_t length,
921 const DataViewType arrayType)
922 {
923 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
924 // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
925 // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
926 JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetConstructorFromType(thread, arrayType);
927 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
928 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
929 // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
930 // 4. Set obj.[[TypedArrayName]] to constructorName.
931 JSTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName);
932 // 7. If length is not present, then
933 // 8. Else,
934 // a. Perform ? AllocateTypedArrayBuffer(obj, length).
935 TypedArrayHelper::AllocateTypedArrayBuffer(thread, obj, length, arrayType);
936 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
937 // 9. Return obj.
938 return obj;
939 }
940
941 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto, length )
AllocateSharedTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget,uint32_t length,const DataViewType arrayType)942 JSHandle<JSObject> TypedArrayHelper::AllocateSharedTypedArray(JSThread *thread,
943 const JSHandle<JSTaggedValue> &constructorName,
944 const JSHandle<JSTaggedValue> &newTarget,
945 uint32_t length, const DataViewType arrayType)
946 {
947 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
948 // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
949 // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
950 JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetSharedConstructorFromType(thread, arrayType);
951 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
952 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
953 // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
954 // 4. Set obj.[[TypedArrayName]] to constructorName.
955 JSSharedTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName);
956 // 7. If length is not present, then
957 // 8. Else,
958 // a. Perform ? AllocateTypedArrayBuffer(obj, length).
959 TypedArrayHelper::AllocateTypedArrayBuffer<TypedArrayKind::SHARED>(thread, obj, length, arrayType);
960 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
961 // 9. Return obj.
962 return obj;
963 }
964
965 template JSHandle<JSObject> TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::SHARED>(
966 JSThread *thread, const JSHandle<JSTypedArray> &obj, uint32_t argc, JSTaggedType argv[]);
967 template JSHandle<JSObject> TypedArrayHelper::TypedArraySpeciesCreate<TypedArrayKind::NON_SHARED>(
968 JSThread *thread, const JSHandle<JSTypedArray> &obj, uint32_t argc, JSTaggedType argv[]);
969
970 // es11 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
971 template <TypedArrayKind typedArrayKind>
TypedArraySpeciesCreate(JSThread * thread,const JSHandle<JSTypedArray> & obj,uint32_t argc,JSTaggedType argv[])972 JSHandle<JSObject> TypedArrayHelper::TypedArraySpeciesCreate(JSThread *thread, const JSHandle<JSTypedArray> &obj,
973 uint32_t argc, JSTaggedType argv[])
974 {
975 // 1. Assert: exemplar is an Object that has [[TypedArrayName]] and [[ContentType]] internal slots.
976 // 2. Let defaultConstructor be the intrinsic object listed in column one of Table 61 for
977 // exemplar.[[TypedArrayName]].
978 JSHandle<JSTaggedValue> buffHandle(thread, JSTaggedValue(argv[0]));
979 JSHandle<JSTaggedValue> defaultConstructor =
980 TypedArrayHelper::GetConstructor(thread, JSHandle<JSTaggedValue>(obj));
981 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
982 JSHandle<JSObject> result;
983 JSHandle<JSTaggedValue> proto(thread, obj->GetJSHClass()->GetPrototype());
984 bool isCtrUnchanged = PropertyDetector::IsTypedArraySpeciesProtectDetectorValid(env) &&
985 !TypedArrayHelper::IsAccessorHasChanged(proto) &&
986 !obj->GetJSHClass()->HasConstructor();
987 bool isCtrBylen = buffHandle->IsInt();
988 if (isCtrUnchanged && isCtrBylen) {
989 JSType type = obj->GetJSHClass()->GetObjectType();
990 DataViewType arrayType = GetType(type);
991 uint32_t length = static_cast<uint32_t>(buffHandle->GetInt());
992 // 3. Let result be ? AllocateTypedArray(constructorName, defaultConstructor, length, arrayType).
993 if constexpr (typedArrayKind == TypedArrayKind::NON_SHARED) {
994 JSHandle<JSTaggedValue> constructorName = GetConstructorNameFromType(thread, arrayType);
995 result = TypedArrayHelper::AllocateTypedArray(thread, constructorName,
996 defaultConstructor, length, arrayType);
997 } else {
998 JSHandle<JSTaggedValue> constructorName = GetSharedConstructorNameFromType(thread, arrayType);
999 result = TypedArrayHelper::AllocateSharedTypedArray(thread, constructorName,
1000 defaultConstructor, length, arrayType);
1001 }
1002 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1003 } else {
1004 JSHandle<JSTaggedValue> key = thread->GlobalConstants()->GetHandledConstructorString();
1005 JSHandle<JSTaggedValue> objConstructor =
1006 JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(obj), key, JSHandle<JSTaggedValue>(obj)).GetValue();
1007 // 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
1008 JSHandle<JSTaggedValue> thisConstructor =
1009 JSObject::SlowSpeciesConstructor(thread, objConstructor, defaultConstructor);
1010 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1011 // 4. Let result be ? TypedArrayCreate(constructor, argumentList).
1012 argv[0] = buffHandle.GetTaggedType();
1013 result = TypedArrayHelper::TypedArrayCreate(thread, thisConstructor, argc, argv);
1014 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1015 }
1016 // 5. If result.[[ContentType]] ≠ exemplar.[[ContentType]], throw a TypeError exception.
1017 ContentType objContentType = obj->GetContentType();
1018 ContentType resultContentType = JSHandle<JSTypedArray>::Cast(result)->GetContentType();
1019 if (objContentType != resultContentType) {
1020 JSHandle<JSObject> exception(thread, JSTaggedValue::Exception());
1021 THROW_TYPE_ERROR_AND_RETURN(thread, "resultContentType is not equal objContentType.", exception);
1022 }
1023 return result;
1024 }
1025
1026 // es11 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
TypedArrayCreate(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,uint32_t argc,const JSTaggedType argv[])1027 JSHandle<JSObject> TypedArrayHelper::TypedArrayCreate(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
1028 uint32_t argc, const JSTaggedType argv[])
1029 {
1030 // 1. Let newTypedArray be ? Construct(constructor, argumentList).
1031 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1032 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, argc);
1033 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1034 info->SetCallArg(argc, argv);
1035 JSTaggedValue taggedArray = JSFunction::Construct(info);
1036 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1037 if (!taggedArray.IsECMAObject()) {
1038 THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the Typedarray.",
1039 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1040 }
1041 JSHandle<JSTaggedValue> taggedArrayHandle(thread, taggedArray);
1042 // 2. Perform ? ValidateTypedArray(newTypedArray).
1043 TypedArrayHelper::ValidateTypedArray(thread, taggedArrayHandle);
1044 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1045 JSHandle<JSObject> newTypedArray(taggedArrayHandle);
1046 // 3. If argumentList is a List of a single Number, then
1047 // a. If newTypedArray.[[ArrayLength]] < argumentList[0], throw a TypeError exception.
1048 if (argc == 1) {
1049 if (JSHandle<JSTypedArray>::Cast(newTypedArray)->GetArrayLength() <
1050 JSTaggedValue::ToUint32(thread, info->GetCallArg(0))) {
1051 THROW_TYPE_ERROR_AND_RETURN(thread, "the length of newTypedArray is not a correct value.",
1052 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1053 }
1054 }
1055 // 4. Return newTypedArray.
1056 return newTypedArray;
1057 }
1058
1059 // TypedArrayCreateSameType ( exemplar, argumentList )
TypedArrayCreateSameType(JSThread * thread,const JSHandle<JSTypedArray> & obj,uint32_t argc,JSTaggedType argv[])1060 JSHandle<JSObject> TypedArrayHelper::TypedArrayCreateSameType(JSThread *thread, const JSHandle<JSTypedArray> &obj,
1061 uint32_t argc, JSTaggedType argv[])
1062 {
1063 // 1. Let constructor be the intrinsic object associated with the constructor name exemplar.[[TypedArrayName]]
1064 // in Table 70.
1065 JSHandle<JSTaggedValue> buffHandle(thread, JSTaggedValue(argv[0]));
1066 JSHandle<JSTaggedValue> constructor =
1067 TypedArrayHelper::GetConstructor(thread, JSHandle<JSTaggedValue>(obj));
1068 argv[0] = buffHandle.GetTaggedType();
1069 // 2. Let result be ? TypedArrayCreate(constructor, argumentList).
1070 JSHandle<JSObject> result = TypedArrayHelper::TypedArrayCreate(thread, constructor, argc, argv);
1071 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1072 // 3. Assert: result has [[TypedArrayName]] and [[ContentType]] internal slots.
1073 // 4. Assert: result.[[ContentType]] is exemplar.[[ContentType]].
1074 [[maybe_unused]] ContentType objContentType = obj->GetContentType();
1075 [[maybe_unused]] ContentType resultContentType = JSHandle<JSTypedArray>::Cast(result)->GetContentType();
1076 ASSERT(objContentType == resultContentType);
1077 return result;
1078 }
1079
1080 // es11 22.2.3.5.1 Runtime Semantics: ValidateTypedArray ( O )
ValidateTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & value)1081 JSTaggedValue TypedArrayHelper::ValidateTypedArray(JSThread *thread, const JSHandle<JSTaggedValue> &value)
1082 {
1083 // 1. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
1084 // 2. Assert: O has a [[ViewedArrayBuffer]] internal slot.
1085 if (!value->IsTypedArray() && !value->IsSharedTypedArray()) {
1086 THROW_TYPE_ERROR_AND_RETURN(thread, "The O is not a TypedArray.", JSTaggedValue::Exception());
1087 }
1088 // 3. Let buffer be O.[[ViewedArrayBuffer]].
1089 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
1090 JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(value)->GetViewedArrayBufferOrByteArray();
1091 if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
1092 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
1093 JSTaggedValue::Exception());
1094 }
1095 if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
1096 THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
1097 JSTaggedValue::Exception());
1098 }
1099 // 5. Return buffer.
1100 return buffer;
1101 }
1102
SortCompare(JSThread * thread,const JSHandle<JSTaggedValue> & callbackfnHandle,const JSHandle<JSTaggedValue> & buffer,const JSHandle<JSTaggedValue> & firstValue,const JSHandle<JSTaggedValue> & secondValue)1103 int32_t TypedArrayHelper::SortCompare(JSThread *thread, const JSHandle<JSTaggedValue> &callbackfnHandle,
1104 const JSHandle<JSTaggedValue> &buffer, const JSHandle<JSTaggedValue> &firstValue,
1105 const JSHandle<JSTaggedValue> &secondValue)
1106 {
1107 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
1108 // 1. Assert: Both Type(x) and Type(y) are Number or both are BigInt.
1109 ASSERT((firstValue->IsNumber() && secondValue->IsNumber()) || (firstValue->IsBigInt() && secondValue->IsBigInt()));
1110 // 2. If the argument comparefn is not undefined, then
1111 // a. Let v be Call(comparefn, undefined, «x, y»).
1112 // b. ReturnIfAbrupt(v).
1113 // c. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
1114 // d. If v is NaN, return +0.
1115 // e. Return v.
1116 if (!callbackfnHandle->IsUndefined()) {
1117 const uint32_t argsLength = 2;
1118 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
1119 EcmaRuntimeCallInfo *info =
1120 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackfnHandle, undefined, undefined, argsLength);
1121 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
1122 info->SetCallArg(firstValue.GetTaggedValue(), secondValue.GetTaggedValue());
1123 JSTaggedValue callResult = JSFunction::Call(info);
1124 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
1125 if (buffer->IsSendableArrayBuffer() &&
1126 BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
1127 THROW_TYPE_ERROR_AND_RETURN(thread, "The buffer is detached sendable buffer.", 0);
1128 }
1129 if (!buffer->IsSendableArrayBuffer() &&
1130 BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
1131 THROW_TYPE_ERROR_AND_RETURN(thread, "The buffer is detached buffer.", 0);
1132 }
1133 JSHandle<JSTaggedValue> testResult(thread, callResult);
1134 if (testResult->IsBigInt()) {
1135 JSHandle<BigInt> bigIntResult = JSHandle<BigInt>::Cast(testResult);
1136 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
1137 ComparisonResult compareResult = BigInt::CompareWithNumber(bigIntResult, zero);
1138 if (compareResult == ComparisonResult::LESS) {
1139 return -1;
1140 }
1141 if (compareResult == ComparisonResult::GREAT) {
1142 return 1;
1143 }
1144 return +0;
1145 }
1146 JSTaggedNumber v = JSTaggedValue::ToNumber(thread, testResult);
1147 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
1148 double value = v.GetNumber();
1149 if (std::isnan(value)) {
1150 return +0;
1151 }
1152 return value;
1153 }
1154 if (firstValue->IsNumber()) {
1155 // 3. If x and y are both NaN, return +0.
1156 if (NumberHelper::IsNaN(firstValue.GetTaggedValue())) {
1157 if (NumberHelper::IsNaN(secondValue.GetTaggedValue())) {
1158 return +0;
1159 }
1160 // 4. If x is NaN, return 1.
1161 return 1;
1162 }
1163 // 5. If y is NaN, return -1.
1164 if (NumberHelper::IsNaN(secondValue.GetTaggedValue())) {
1165 return -1;
1166 }
1167 ComparisonResult compareResult = JSTaggedValue::Compare(thread, firstValue, secondValue);
1168 // 6. If x < y, return -1.
1169 // 7. If x > y, return 1.
1170 // 8. If x is -0 and y is +0, return -1.
1171 // 9. If x is +0 and y is -0, return 1.
1172 // 10. Return +0.
1173 if (compareResult == ComparisonResult::LESS) {
1174 return -1;
1175 }
1176 if (compareResult == ComparisonResult::GREAT) {
1177 return 1;
1178 }
1179 JSTaggedNumber xNumber = JSTaggedValue::ToNumber(thread, firstValue);
1180 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
1181 JSTaggedNumber yNumber = JSTaggedValue::ToNumber(thread, secondValue);
1182 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
1183 double eZeroTemp = -0.0;
1184 auto eZero = JSTaggedNumber(eZeroTemp);
1185 double pZeroTemp = +0.0;
1186 auto pZero = JSTaggedNumber(pZeroTemp);
1187 if (JSTaggedNumber::SameValue(xNumber, eZero) && JSTaggedNumber::SameValue(yNumber, pZero)) {
1188 return -1;
1189 }
1190 if (JSTaggedNumber::SameValue(xNumber, pZero) && JSTaggedNumber::SameValue(yNumber, eZero)) {
1191 return 1;
1192 }
1193 } else {
1194 ComparisonResult compareResult = JSTaggedValue::Compare(thread, firstValue, secondValue);
1195 if (compareResult == ComparisonResult::LESS) {
1196 return -1;
1197 }
1198 if (compareResult == ComparisonResult::GREAT) {
1199 return 1;
1200 }
1201 }
1202 return +0;
1203 }
1204
IsNativeArrayIterator(JSThread * thread,const JSHandle<JSTaggedValue> & obj,JSHandle<JSTaggedValue> & iterMethod)1205 bool TypedArrayHelper::IsNativeArrayIterator(JSThread *thread,
1206 const JSHandle<JSTaggedValue> &obj, JSHandle<JSTaggedValue> &iterMethod)
1207 {
1208 if (iterMethod->IsUndefined() || (!obj->IsTypedArray() && !obj->IsArray(thread))) {
1209 return false;
1210 }
1211
1212 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1213 if (!JSTaggedValue::SameValue(iterMethod, env->GetTypedArrayProtoValuesFunction()) &&
1214 !JSTaggedValue::SameValue(iterMethod, env->GetArrayProtoValuesFunction())) {
1215 return false;
1216 }
1217
1218 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, obj, iterMethod);
1219 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1220 JSHandle<JSTaggedValue> nextKey = thread->GlobalConstants()->GetHandledNextString();
1221 JSHandle<JSTaggedValue> iterNext = JSObject::GetMethod(thread, iterator, nextKey);
1222 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1223 if (!iterNext->IsJSFunction()) {
1224 return false;
1225 }
1226 // Array and TypedArray use the same JSArrayIterator.
1227 return JSHandle<JSFunction>::Cast(iterNext)->GetNativePointer() == reinterpret_cast<void *>(JSArrayIterator::Next);
1228 }
1229 } // namespace panda::ecmascript::base
1230