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