• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "ecmascript/base/builtins_base.h"
18 #include "ecmascript/base/error_helper.h"
19 #include "ecmascript/base/error_type.h"
20 #include "ecmascript/base/typed_array_helper-inl.h"
21 #include "ecmascript/builtins/builtins_arraybuffer.h"
22 #include "ecmascript/ecma_macros.h"
23 #include "ecmascript/ecma_vm.h"
24 #include "ecmascript/global_env.h"
25 #include "ecmascript/internal_call_params.h"
26 #include "ecmascript/js_array_iterator.h"
27 #include "ecmascript/js_arraybuffer.h"
28 #include "ecmascript/js_hclass.h"
29 #include "ecmascript/js_object-inl.h"
30 #include "ecmascript/js_tagged_value-inl.h"
31 #include "ecmascript/js_tagged_value.h"
32 #include "ecmascript/js_typed_array.h"
33 #include "ecmascript/object_factory.h"
34 
35 namespace panda::ecmascript::base {
36 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
37 
38 // es11 22.2.4 The TypedArray Constructors
TypedArrayConstructor(EcmaRuntimeCallInfo * argv,const JSHandle<JSTaggedValue> & constructorName)39 JSTaggedValue TypedArrayHelper::TypedArrayConstructor(EcmaRuntimeCallInfo *argv,
40                                                       const JSHandle<JSTaggedValue> &constructorName)
41 {
42     ASSERT(argv);
43     JSThread *thread = argv->GetThread();
44     [[maybe_unused]] EcmaHandleScope handleScope(thread);
45     EcmaVM *ecmaVm = thread->GetEcmaVM();
46     JSHandle<JSTaggedValue> newTarget = BuiltinsBase::GetNewTarget(argv);
47     // 2. If NewTarget is undefined, throw a TypeError exception.
48     if (newTarget->IsUndefined()) {
49         THROW_TYPE_ERROR_AND_RETURN(thread, "The NewTarget is undefined.", JSTaggedValue::Exception());
50     }
51     // 3. Let constructorName be the String value of the Constructor Name value specified in Table 61 for this
52     // TypedArray constructor.
53     // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%").
54     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
55     JSHandle<JSTaggedValue> firstArg = BuiltinsBase::GetCallArg(argv, 0);
56     if (!firstArg->IsECMAObject()) {
57         // es11 22.2.4.1 TypedArray ( )
58         int32_t elementLength = 0;
59         // es11 22.2.4.2 TypedArray ( length )
60         if (!firstArg->IsUndefined()) {
61             JSTaggedNumber index = JSTaggedValue::ToIndex(thread, firstArg);
62             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
63             elementLength = static_cast<int32_t>(index.GetNumber());
64         }
65         JSHandle<JSObject> obj =
66             TypedArrayHelper::AllocateTypedArray(factory, ecmaVm, constructorName, newTarget, elementLength);
67         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
68         return obj.GetTaggedValue();
69     }
70     JSHandle<JSObject> obj = TypedArrayHelper::AllocateTypedArray(factory, ecmaVm, constructorName, newTarget);
71     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
72     if (firstArg->IsTypedArray()) {
73         return TypedArrayHelper::CreateFromTypedArray(argv, obj, constructorName);
74     }
75     if (firstArg->IsArrayBuffer()) {
76         return TypedArrayHelper::CreateFromArrayBuffer(argv, obj, constructorName);
77     }
78     return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj);
79 }
80 
81 // es11 22.2.4.4 TypedArray ( object )
CreateFromOrdinaryObject(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj)82 JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj)
83 {
84     ASSERT(argv);
85     JSThread *thread = argv->GetThread();
86     [[maybe_unused]] EcmaHandleScope handleScope(thread);
87     EcmaVM *ecmaVm = thread->GetEcmaVM();
88     JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
89     JSHandle<JSTaggedValue> objectArg = BuiltinsBase::GetCallArg(argv, 0);
90     JSHandle<JSObject> object(objectArg);
91     // 5. Let usingIterator be ? GetMethod(object, @@iterator).
92     JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
93     JSHandle<JSTaggedValue> usingIterator =
94         JSObject::GetMethod(thread, JSHandle<JSTaggedValue>::Cast(object), iteratorSymbol);
95     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
96 
97     // 6. If usingIterator is not undefined, then
98     if (!usingIterator->IsUndefined()) {
99         CVector<JSHandle<JSTaggedValue>> vec;
100         // a. Let values be ? IterableToList(object, usingIterator).
101         // b. Let len be the number of elements in values.
102         // c. Perform ? AllocateTypedArrayBuffer(O, len).
103         JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, objectArg, usingIterator);
104         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
105         JSHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
106         while (!next->IsFalse()) {
107             next = JSIterator::IteratorStep(thread, iterator);
108             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
109             if (!next->IsFalse()) {
110                 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
111                 vec.push_back(nextValue);
112             }
113         }
114         int32_t len = vec.size();
115         TypedArrayHelper::AllocateTypedArrayBuffer(thread, ecmaVm, obj, len);
116         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
117         // d. Let k be 0.
118         // e. Repeat, while k < len
119         //   i. Let Pk be ! ToString(k).
120         //   ii. Let kValue be the first element of values and remove that element from values.
121         //   iii. Perform ? Set(O, Pk, kValue, true).
122         //   iv. Set k to k + 1.
123         JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
124         double k = 0;
125         while (k < len) {
126             tKey.Update(JSTaggedValue(k));
127             JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
128             JSHandle<JSTaggedValue> kValue = vec[k];
129             JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
130             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
131             k++;
132         }
133         // f. Assert: values is now an empty List.
134         // g. Return O.
135         return obj.GetTaggedValue();
136     }
137 
138     // 7. NOTE: object is not an Iterable so assume it is already an array-like object.
139     // 8. Let arrayLike be object.
140     // 9. Let len be ? LengthOfArrayLike(arrayLike).
141     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
142     JSTaggedNumber lenTemp =
143         JSTaggedValue::ToLength(thread, JSObject::GetProperty(thread, objectArg, lengthKey).GetValue());
144     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
145     double len = lenTemp.GetNumber();
146     // 10. Perform ? AllocateTypedArrayBuffer(O, len).
147     TypedArrayHelper::AllocateTypedArrayBuffer(thread, ecmaVm, obj, len);
148     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
149     // 11. Let k be 0.
150     // 12. Repeat, while k < len
151     //   a. Let Pk be ! ToString(k).
152     //   b. Let kValue be ? Get(arrayLike, Pk).
153     //   c. Perform ? Set(O, Pk, kValue, true).
154     //   d. Set k to k + 1.
155     JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
156     double k = 0;
157     while (k < len) {
158         tKey.Update(JSTaggedValue(k));
159         JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
160         JSHandle<JSTaggedValue> kValue = JSObject::GetProperty(thread, objectArg, kKey).GetValue();
161         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
162         JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
163         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
164         k++;
165     }
166     // 13. Return O.
167     return obj.GetTaggedValue();
168 }
169 
170 // es11 22.2.4.3 TypedArray ( typedArray )
CreateFromTypedArray(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & constructorName)171 JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
172                                                      const JSHandle<JSTaggedValue> &constructorName)
173 {
174     ASSERT(argv);
175     JSThread *thread = argv->GetThread();
176     [[maybe_unused]] EcmaHandleScope handleScope(thread);
177     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
178     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
179     // 5. Let srcArray be typedArray.
180     JSHandle<JSTaggedValue> srcArray = BuiltinsBase::GetCallArg(argv, 0);
181     JSHandle<JSObject> srcObj(srcArray);
182     // 6. Let srcData be srcArray.[[ViewedArrayBuffer]].
183     JSHandle<JSTaggedValue> srcData(thread, JSTypedArray::Cast(*srcObj)->GetViewedArrayBuffer());
184     // 7. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
185     if (BuiltinsArrayBuffer::IsDetachedBuffer(srcData.GetTaggedValue())) {
186         THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
187     }
188     // 8. Let elementType be the Element Type value in Table 61 for constructorName.
189     DataViewType elementType = TypedArrayHelper::GetTypeFromName(thread, constructorName);
190     // 9. Let elementLength be srcArray.[[ArrayLength]].
191     // 10. Let srcName be the String value of srcArray.[[TypedArrayName]].
192     // 11. Let srcType be the Element Type value in Table 61 for srcName.
193     // 12. Let srcElementSize be the Element Size value specified in Table 61 for srcName.
194     int32_t elementLength = TypedArrayHelper::GetArrayLength(thread, srcObj);
195     JSHandle<JSTaggedValue> srcName(thread, JSTypedArray::Cast(*srcObj)->GetTypedArrayName());
196     DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
197     int32_t srcElementSize = TypedArrayHelper::GetSizeFromName(thread, srcName);
198     // 13. Let srcByteOffset be srcArray.[[ByteOffset]].
199     // 14. Let elementSize be the Element Size value specified in Table 61 for constructorName.
200     // 15. Let byteLength be elementSize × elementLength.
201     int32_t srcByteOffset = TypedArrayHelper::GetByteOffset(thread, srcObj);
202     int32_t elementSize = TypedArrayHelper::GetSizeFromName(thread, constructorName);
203     int32_t byteLength = elementSize * elementLength;
204     // 16. If IsSharedArrayBuffer(srcData) is false, then
205     //   a. Let bufferConstructor be ? SpeciesConstructor(srcData, %ArrayBuffer%).
206 
207     JSTaggedValue data;
208     // 18. If elementType is the same as srcType, then
209     //   a. Let data be ? CloneArrayBuffer(srcData, srcByteOffset, byteLength, bufferConstructor).
210     if (elementType == srcType) {
211         data =
212             BuiltinsArrayBuffer::CloneArrayBuffer(thread, srcData, srcByteOffset, globalConst->GetHandledUndefined());
213         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
214     } else {
215         // 19. Else,
216         //   a. Let data be ? AllocateArrayBuffer(bufferConstructor, byteLength).
217         JSHandle<JSTaggedValue> bufferConstructor =
218             JSObject::SpeciesConstructor(thread, JSHandle<JSObject>(srcData), env->GetArrayBufferFunction());
219         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
220         data = BuiltinsArrayBuffer::AllocateArrayBuffer(thread, bufferConstructor, byteLength);
221         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
222         //   b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
223         if (BuiltinsArrayBuffer::IsDetachedBuffer(srcData.GetTaggedValue())) {
224             THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
225         }
226         //   d. Let srcByteIndex be srcByteOffset.
227         //   e. Let targetByteIndex be 0.
228         int32_t srcByteIndex = srcByteOffset;
229         int32_t targetByteIndex = 0;
230         //   f. Let count be elementLength.
231         //   g. Repeat, while count > 0
232         JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
233         for (int32_t count = elementLength; count > 0; count--) {
234             // i. Let value be GetValueFromBuffer(srcData, srcByteIndex, srcType, true, Unordered).
235             JSTaggedValue taggedData =
236                 BuiltinsArrayBuffer::GetValueFromBuffer(srcData.GetTaggedValue(), srcByteIndex, srcType, true);
237             value.Update(taggedData);
238             JSTaggedNumber numVal = JSTaggedValue::ToNumber(thread, value);
239             // ii. Perform SetValueInBuffer(data, targetByteIndex, elementType, value, true, Unordered).
240             BuiltinsArrayBuffer::SetValueInBuffer(data, targetByteIndex, elementType, numVal, true);
241             // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
242             // iv. Set targetByteIndex to targetByteIndex + elementSize.
243             // v. Set count to count - 1.
244             srcByteIndex = srcByteIndex + srcElementSize;
245             targetByteIndex = targetByteIndex + elementSize;
246         }
247     }
248     // 19. Set O’s [[ViewedArrayBuffer]] internal slot to data.
249     // 20. Set O’s [[ByteLength]] internal slot to byteLength.
250     // 21. Set O’s [[ByteOffset]] internal slot to 0.
251     // 22. Set O’s [[ArrayLength]] internal slot to elementLength.
252     JSTypedArray::Cast(*obj)->SetViewedArrayBuffer(thread, data);
253     JSTypedArray::Cast(*obj)->SetByteLength(thread, JSTaggedValue(byteLength));
254     JSTypedArray::Cast(*obj)->SetByteOffset(thread, JSTaggedValue(0));
255     JSTypedArray::Cast(*obj)->SetArrayLength(thread, JSTaggedValue(elementLength));
256     // 23. Return O.
257     return obj.GetTaggedValue();
258 }
259 
260 // es11 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
CreateFromArrayBuffer(EcmaRuntimeCallInfo * argv,const JSHandle<JSObject> & obj,const JSHandle<JSTaggedValue> & constructorName)261 JSTaggedValue TypedArrayHelper::CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
262                                                       const JSHandle<JSTaggedValue> &constructorName)
263 {
264     ASSERT(argv);
265     JSThread *thread = argv->GetThread();
266     [[maybe_unused]] EcmaHandleScope handleScope(thread);
267     // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
268     // 6. Let offset be ? ToIndex(byteOffset).
269     int32_t elementSize = TypedArrayHelper::GetSizeFromName(thread, constructorName);
270     JSHandle<JSTaggedValue> byteOffset = BuiltinsBase::GetCallArg(argv, 1);
271     JSTaggedNumber index = JSTaggedValue::ToIndex(thread, byteOffset);
272     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
273     auto offset = static_cast<int32_t>(index.GetNumber());
274     // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
275     if (offset % elementSize != 0) {
276         THROW_RANGE_ERROR_AND_RETURN(thread, "The offset cannot be an integral multiple of elementSize.",
277                                      JSTaggedValue::Exception());
278     }
279     // 8. If length is not undefined, then
280     //   a. Let newLength be ? ToIndex(length).
281     JSHandle<JSTaggedValue> length = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
282     int32_t newLength = 0;
283     if (!length->IsUndefined()) {
284         index = JSTaggedValue::ToIndex(thread, length);
285         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
286         newLength = static_cast<int32_t>(index.GetNumber());
287     }
288     // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
289     JSHandle<JSTaggedValue> buffer = BuiltinsBase::GetCallArg(argv, 0);
290     if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
291         THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
292     }
293     // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
294     uint32_t bufferByteLength = JSHandle<JSArrayBuffer>(buffer)->GetArrayBufferByteLength();
295     // 11. If length is undefined, then
296     //   a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
297     //   b. Let newByteLength be bufferByteLength - offset.
298     //   c. If newByteLength < 0, throw a RangeError exception.
299     int32_t newByteLength;
300     if (length->IsUndefined()) {
301         if (bufferByteLength % elementSize != 0) {
302             THROW_RANGE_ERROR_AND_RETURN(thread, "The bufferByteLength cannot be an integral multiple of elementSize.",
303                                          JSTaggedValue::Exception());
304         }
305         newByteLength = bufferByteLength - offset;
306         if (newByteLength < 0) {
307             THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is less than 0.", JSTaggedValue::Exception());
308         }
309     } else {
310         // 12. Else,
311         //   a. Let newByteLength be newLength × elementSize.
312         //   b. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
313         newByteLength = newLength * elementSize;
314         if (static_cast<uint32_t>(offset + newByteLength) > bufferByteLength) {
315             THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is out of range.", JSTaggedValue::Exception());
316         }
317     }
318     // 13. Set O.[[ViewedArrayBuffer]] to buffer.
319     // 14. Set O.[[ByteLength]] to newByteLength.
320     // 15. Set O.[[ByteOffset]] to offset.
321     // 16. Set O.[[ArrayLength]] to newByteLength / elementSize.
322     JSTypedArray::Cast(*obj)->SetViewedArrayBuffer(thread, buffer);
323     JSTypedArray::Cast(*obj)->SetByteLength(thread, JSTaggedValue(newByteLength));
324     JSTypedArray::Cast(*obj)->SetByteOffset(thread, JSTaggedValue(offset));
325     JSTypedArray::Cast(*obj)->SetArrayLength(thread, JSTaggedValue(newByteLength / elementSize));
326     // 17. Return O.
327     return obj.GetTaggedValue();
328 }
329 
330 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto )
AllocateTypedArray(ObjectFactory * factory,EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget)331 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArray(ObjectFactory *factory, EcmaVM *ecmaVm,
332                                                         const JSHandle<JSTaggedValue> &constructorName,
333                                                         const JSHandle<JSTaggedValue> &newTarget)
334 {
335     JSThread *thread = ecmaVm->GetJSThread();
336     // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
337     // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
338     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
339     JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetConstructorFromName(thread, constructorName);
340     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
341     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
342     // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
343     // 4. Set obj.[[TypedArrayName]] to constructorName.
344     // 7. If length is not present, then
345     //   a. Set obj.[[ByteLength]] to 0.
346     //   b. Set obj.[[ByteOffset]] to 0.
347     //   c. Set obj.[[ArrayLength]] to 0.
348     JSTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName);
349     JSTypedArray::Cast(*obj)->SetByteLength(thread, JSTaggedValue(0));
350     JSTypedArray::Cast(*obj)->SetByteOffset(thread, JSTaggedValue(0));
351     JSTypedArray::Cast(*obj)->SetArrayLength(thread, JSTaggedValue(0));
352     // 9. Return obj.
353     return obj;
354 }  // namespace panda::ecmascript::base
355 
356 // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto, length )
AllocateTypedArray(ObjectFactory * factory,EcmaVM * ecmaVm,const JSHandle<JSTaggedValue> & constructorName,const JSHandle<JSTaggedValue> & newTarget,int32_t length)357 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArray(ObjectFactory *factory, EcmaVM *ecmaVm,
358                                                         const JSHandle<JSTaggedValue> &constructorName,
359                                                         const JSHandle<JSTaggedValue> &newTarget, int32_t length)
360 {
361     JSThread *thread = ecmaVm->GetJSThread();
362     // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto).
363     // 2. Let obj be ! IntegerIndexedObjectCreate(proto).
364     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
365     JSHandle<JSFunction> typedArrayFunc = TypedArrayHelper::GetConstructorFromName(thread, constructorName);
366     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget);
367     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
368     // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined.
369     // 4. Set obj.[[TypedArrayName]] to constructorName.
370     JSTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName);
371     // 7. If length is not present, then
372     // 8. Else,
373     //   a. Perform ? AllocateTypedArrayBuffer(obj, length).
374     TypedArrayHelper::AllocateTypedArrayBuffer(thread, ecmaVm, obj, length);
375     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
376     // 9. Return obj.
377     return obj;
378 }
379 
380 // es11 22.2.4.2.2 Runtime Semantics: AllocateTypedArrayBuffer ( O, length )
AllocateTypedArrayBuffer(JSThread * thread,EcmaVM * ecmaVm,const JSHandle<JSObject> & obj,double length)381 JSHandle<JSObject> TypedArrayHelper::AllocateTypedArrayBuffer(JSThread *thread, EcmaVM *ecmaVm,
382                                                               const JSHandle<JSObject> &obj, double length)
383 {
384     JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
385     // 1. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
386     // 2. Assert: O.[[ViewedArrayBuffer]] is undefined.
387     // 3. Assert: ! IsNonNegativeInteger(length) is true.
388     ASSERT(JSTaggedValue(length).IsInteger());
389     ASSERT(length >= 0);
390     JSHandle<JSObject> exception(thread, JSTaggedValue::Exception());
391     if (length > JSTypedArray::MAX_TYPED_ARRAY_INDEX) {
392         THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception);
393     }
394     // 4. Let constructorName be the String value of O.[[TypedArrayName]].
395     JSHandle<JSTaggedValue> constructorName(thread, JSTypedArray::Cast(*obj)->GetTypedArrayName());
396     // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
397     int32_t elementSize = TypedArrayHelper::GetSizeFromName(thread, constructorName);
398     // 6. Let byteLength be elementSize × length.
399     double byteLength = elementSize * length;
400     // 7. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength).
401     JSHandle<JSTaggedValue> constructor = env->GetArrayBufferFunction();
402     JSTaggedValue data = BuiltinsArrayBuffer::AllocateArrayBuffer(thread, constructor, byteLength);
403     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception);
404     // 8. Set O.[[ViewedArrayBuffer]] to data.
405     // 9. Set O.[[ByteLength]] to byteLength.
406     // 10. Set O.[[ByteOffset]] to 0.
407     // 11. Set O.[[ArrayLength]] to length.
408     JSTypedArray::Cast(*obj)->SetViewedArrayBuffer(thread, data);
409     JSTypedArray::Cast(*obj)->SetByteLength(thread, JSTaggedValue(byteLength));
410     JSTypedArray::Cast(*obj)->SetByteOffset(thread, JSTaggedValue(0));
411     JSTypedArray::Cast(*obj)->SetArrayLength(thread, JSTaggedValue(length));
412     // 12. Return O.
413     return obj;
414 }
415 
416 // es11 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
TypedArraySpeciesCreate(JSThread * thread,const JSHandle<JSObject> & obj,uint32_t argc,const JSTaggedType argv[])417 JSHandle<JSObject> TypedArrayHelper::TypedArraySpeciesCreate(JSThread *thread, const JSHandle<JSObject> &obj,
418                                                              uint32_t argc, const JSTaggedType argv[])
419 {
420     // 1. Assert: exemplar is an Object that has [[TypedArrayName]] and [[ContentType]] internal slots.
421     // 2. Let defaultConstructor be the intrinsic object listed in column one of Table 61 for
422     // exemplar.[[TypedArrayName]].
423     JSHandle<JSTaggedValue> defaultConstructor = TypedArrayHelper::GetConstructor(thread, JSHandle<JSTaggedValue>(obj));
424     // 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
425     JSHandle<JSTaggedValue> thisConstructor = JSObject::SpeciesConstructor(thread, obj, defaultConstructor);
426     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
427     // 4. Let result be ? TypedArrayCreate(constructor, argumentList).
428     return TypedArrayHelper::TypedArrayCreate(thread, thisConstructor, argc, argv);
429 }
430 
431 // es11 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
TypedArrayCreate(JSThread * thread,const JSHandle<JSTaggedValue> & constructor,uint32_t argc,const JSTaggedType argv[])432 JSHandle<JSObject> TypedArrayHelper::TypedArrayCreate(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
433                                                       uint32_t argc, const JSTaggedType argv[])
434 {
435     // 1. Let newTypedArray be ? Construct(constructor, argumentList).
436     JSTaggedValue taggedArray = JSFunction::Construct(thread, constructor, argc, argv,
437                                                       JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
438     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
439     if (!taggedArray.IsECMAObject()) {
440         THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the Typedarray.",
441                                     JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
442     }
443     JSHandle<JSTaggedValue> taggedArrayHandle(thread, taggedArray);
444     // 2. Perform ? ValidateTypedArray(newTypedArray).
445     TypedArrayHelper::ValidateTypedArray(thread, taggedArrayHandle);
446     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
447     JSHandle<JSObject> newTypedArray(taggedArrayHandle);
448     // 3. If argumentList is a List of a single Number, then
449     //   a. If newTypedArray.[[ArrayLength]] < argumentList[0], throw a TypeError exception.
450     if (argc == 1) {
451         if (TypedArrayHelper::GetArrayLength(thread, newTypedArray) <
452             JSTaggedValue::ToInt32(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(argv[0])))) {
453             THROW_TYPE_ERROR_AND_RETURN(thread, "the length of newTypedArray is not a correct value.",
454                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
455         }
456     }
457     // 4. Return newTypedArray.
458     return newTypedArray;
459 }
460 
461 // es11 22.2.3.5.1 Runtime Semantics: ValidateTypedArray ( O )
ValidateTypedArray(JSThread * thread,const JSHandle<JSTaggedValue> & value)462 JSTaggedValue TypedArrayHelper::ValidateTypedArray(JSThread *thread, const JSHandle<JSTaggedValue> &value)
463 {
464     // 1. Perform ? RequireInternalSlot(O, [[TypedArrayName]]).
465     // 2. Assert: O has a [[ViewedArrayBuffer]] internal slot.
466     if (!value->IsTypedArray()) {
467         THROW_TYPE_ERROR_AND_RETURN(thread, "The O is not a TypedArray.", JSTaggedValue::Exception());
468     }
469     // 3. Let buffer be O.[[ViewedArrayBuffer]].
470     // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
471     JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(value)->GetViewedArrayBuffer();
472     if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
473         THROW_TYPE_ERROR_AND_RETURN(thread, "The ViewedArrayBuffer of O is detached buffer.",
474                                     JSTaggedValue::Exception());
475     }
476     // 5. Return buffer.
477     return buffer;
478 }
479 
SortCompare(JSThread * thread,const JSHandle<JSTaggedValue> & callbackfnHandle,const JSHandle<JSTaggedValue> & buffer,const JSHandle<JSTaggedValue> & firstValue,const JSHandle<JSTaggedValue> & secondValue)480 int32_t TypedArrayHelper::SortCompare(JSThread *thread, const JSHandle<JSTaggedValue> &callbackfnHandle,
481                                       const JSHandle<JSTaggedValue> &buffer, const JSHandle<JSTaggedValue> &firstValue,
482                                       const JSHandle<JSTaggedValue> &secondValue)
483 {
484     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
485     // 1. Assert: Both Type(x) and Type(y) is Number.
486     ASSERT(firstValue->IsNumber() && secondValue->IsNumber());
487     // 2. If the argument comparefn is not undefined, then
488     //   a. Let v be Call(comparefn, undefined, «x, y»).
489     //   b. ReturnIfAbrupt(v).
490     //   c. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
491     //   d. If v is NaN, return +0.
492     //   e. Return v.
493     if (!callbackfnHandle->IsUndefined()) {
494         JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
495         InternalCallParams *arguments = thread->GetInternalCallParams();
496         arguments->MakeArgv(firstValue, secondValue);
497         JSTaggedValue callResult =
498             JSFunction::Call(thread, callbackfnHandle, thisArgHandle, 2, arguments->GetArgv());  // 2: two args
499         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
500         if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
501             THROW_TYPE_ERROR_AND_RETURN(thread, "The buffer is detached buffer.", 0);
502         }
503         JSHandle<JSTaggedValue> testResult(thread, callResult);
504         JSTaggedNumber v = JSTaggedValue::ToNumber(thread, testResult);
505         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
506         double value = v.GetNumber();
507         if (std::isnan(value)) {
508             return +0;
509         }
510         return value;
511     }
512     // 3. If x and y are both NaN, return +0.
513     if (NumberHelper::IsNaN(firstValue.GetTaggedValue())) {
514         if (NumberHelper::IsNaN(secondValue.GetTaggedValue())) {
515             return +0;
516         }
517         // 4. If x is NaN, return 1.
518         return 1;
519     }
520     // 5. If y is NaN, return -1.
521     if (NumberHelper::IsNaN(secondValue.GetTaggedValue())) {
522         return -1;
523     }
524     ComparisonResult compareResult = JSTaggedValue::Compare(thread, firstValue, secondValue);
525     // 6. If x < y, return -1.
526     // 7. If x > y, return 1.
527     // 8. If x is -0 and y is +0, return -1.
528     // 9. If x is +0 and y is -0, return 1.
529     // 10. Return +0.
530     if (compareResult == ComparisonResult::LESS) {
531         return -1;
532     }
533     if (compareResult == ComparisonResult::GREAT) {
534         return 1;
535     }
536     JSTaggedNumber xNumber = JSTaggedValue::ToNumber(thread, firstValue);
537     JSTaggedNumber yNumber = JSTaggedValue::ToNumber(thread, secondValue);
538     double eZeroTemp = -0.0;
539     auto eZero = JSTaggedNumber(eZeroTemp);
540     double pZeroTemp = +0.0;
541     auto pZero = JSTaggedNumber(pZeroTemp);
542     if (JSTaggedNumber::SameValue(xNumber, eZero) && JSTaggedNumber::SameValue(yNumber, pZero)) {
543         return -1;
544     }
545     if (JSTaggedNumber::SameValue(xNumber, pZero) && JSTaggedNumber::SameValue(yNumber, eZero)) {
546         return 1;
547     }
548     return +0;
549 }
550 }  // namespace panda::ecmascript::base
551