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