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