• 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/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