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