1 /*
2 * Copyright (c) 2021-2022 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/builtins/builtins_typedarray.h"
17 #include <cmath>
18 #include "ecmascript/base/typed_array_helper-inl.h"
19 #include "ecmascript/base/typed_array_helper.h"
20 #include "ecmascript/builtins/builtins_array.h"
21 #include "ecmascript/builtins/builtins_arraybuffer.h"
22 #include "ecmascript/ecma_runtime_call_info.h"
23 #include "ecmascript/ecma_string.h"
24 #include "ecmascript/global_env.h"
25 #include "ecmascript/interpreter/interpreter.h"
26 #include "ecmascript/js_array.h"
27 #include "ecmascript/js_array_iterator.h"
28 #include "ecmascript/js_function.h"
29 #include "ecmascript/js_handle.h"
30 #include "ecmascript/js_iterator.h"
31 #include "ecmascript/js_stable_array.h"
32 #include "ecmascript/js_tagged_number.h"
33 #include "ecmascript/js_tagged_value-inl.h"
34 #include "ecmascript/js_typed_array.h"
35 #include "ecmascript/object_factory.h"
36 #include "ecmascript/object_fast_operator-inl.h"
37
38 namespace panda::ecmascript::builtins {
39 using TypedArrayHelper = base::TypedArrayHelper;
40 using BuiltinsArray = builtins::BuiltinsArray;
41 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
42
43 // 22.2.1
TypedArrayBaseConstructor(EcmaRuntimeCallInfo * argv)44 JSTaggedValue BuiltinsTypedArray::TypedArrayBaseConstructor(EcmaRuntimeCallInfo *argv)
45 {
46 ASSERT(argv);
47 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, BaseConstructor);
48 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "TypedArray Constructor cannot be called.",
49 JSTaggedValue::Exception());
50 }
51
Int8ArrayConstructor(EcmaRuntimeCallInfo * argv)52 JSTaggedValue BuiltinsTypedArray::Int8ArrayConstructor(EcmaRuntimeCallInfo *argv)
53 {
54 ASSERT(argv);
55 JSThread *thread = argv->GetThread();
56 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledInt8ArrayString(),
57 DataViewType::INT8);
58 }
59
Uint8ArrayConstructor(EcmaRuntimeCallInfo * argv)60 JSTaggedValue BuiltinsTypedArray::Uint8ArrayConstructor(EcmaRuntimeCallInfo *argv)
61 {
62 ASSERT(argv);
63 JSThread *thread = argv->GetThread();
64 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledUint8ArrayString(),
65 DataViewType::UINT8);
66 }
67
Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo * argv)68 JSTaggedValue BuiltinsTypedArray::Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo *argv)
69 {
70 ASSERT(argv);
71 JSThread *thread = argv->GetThread();
72 return TypedArrayHelper::TypedArrayConstructor(argv,
73 thread->GlobalConstants()->GetHandledUint8ClampedArrayString(),
74 DataViewType::UINT8_CLAMPED);
75 }
76
Int16ArrayConstructor(EcmaRuntimeCallInfo * argv)77 JSTaggedValue BuiltinsTypedArray::Int16ArrayConstructor(EcmaRuntimeCallInfo *argv)
78 {
79 ASSERT(argv);
80 JSThread *thread = argv->GetThread();
81 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledInt16ArrayString(),
82 DataViewType::INT16);
83 }
84
Uint16ArrayConstructor(EcmaRuntimeCallInfo * argv)85 JSTaggedValue BuiltinsTypedArray::Uint16ArrayConstructor(EcmaRuntimeCallInfo *argv)
86 {
87 ASSERT(argv);
88 JSThread *thread = argv->GetThread();
89 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledUint16ArrayString(),
90 DataViewType::UINT16);
91 }
92
Int32ArrayConstructor(EcmaRuntimeCallInfo * argv)93 JSTaggedValue BuiltinsTypedArray::Int32ArrayConstructor(EcmaRuntimeCallInfo *argv)
94 {
95 ASSERT(argv);
96 JSThread *thread = argv->GetThread();
97 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledInt32ArrayString(),
98 DataViewType::INT32);
99 }
100
Uint32ArrayConstructor(EcmaRuntimeCallInfo * argv)101 JSTaggedValue BuiltinsTypedArray::Uint32ArrayConstructor(EcmaRuntimeCallInfo *argv)
102 {
103 ASSERT(argv);
104 JSThread *thread = argv->GetThread();
105 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledUint32ArrayString(),
106 DataViewType::UINT32);
107 }
108
Float32ArrayConstructor(EcmaRuntimeCallInfo * argv)109 JSTaggedValue BuiltinsTypedArray::Float32ArrayConstructor(EcmaRuntimeCallInfo *argv)
110 {
111 ASSERT(argv);
112 JSThread *thread = argv->GetThread();
113 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledFloat32ArrayString(),
114 DataViewType::FLOAT32);
115 }
116
Float64ArrayConstructor(EcmaRuntimeCallInfo * argv)117 JSTaggedValue BuiltinsTypedArray::Float64ArrayConstructor(EcmaRuntimeCallInfo *argv)
118 {
119 ASSERT(argv);
120 JSThread *thread = argv->GetThread();
121 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledFloat64ArrayString(),
122 DataViewType::FLOAT64);
123 }
124
BigInt64ArrayConstructor(EcmaRuntimeCallInfo * argv)125 JSTaggedValue BuiltinsTypedArray::BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv)
126 {
127 ASSERT(argv);
128 JSThread *thread = argv->GetThread();
129 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledBigInt64ArrayString(),
130 DataViewType::BIGINT64);
131 }
132
BigUint64ArrayConstructor(EcmaRuntimeCallInfo * argv)133 JSTaggedValue BuiltinsTypedArray::BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv)
134 {
135 ASSERT(argv);
136 JSThread *thread = argv->GetThread();
137 return TypedArrayHelper::TypedArrayConstructor(argv, thread->GlobalConstants()->GetHandledBigUint64ArrayString(),
138 DataViewType::BIGUINT64);
139 }
140
141 // 22.2.2.1 %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
From(EcmaRuntimeCallInfo * argv)142 JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv)
143 {
144 ASSERT(argv);
145 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, From);
146 JSThread *thread = argv->GetThread();
147 [[maybe_unused]] EcmaHandleScope handleScope(thread);
148 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
149 // 1. Let C be the this value.
150 // 2. If IsConstructor(C) is false, throw a TypeError exception.
151 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
152 if (!thisHandle->IsConstructor()) {
153 THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception());
154 }
155
156 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
157 // 3. If mapfn is undefined, let mapping be false.
158 // 4. Else,
159 // a. If IsCallable(mapfn) is false, throw a TypeError exception.
160 // b. Let mapping be true.
161 bool mapping = false;
162 JSHandle<JSTaggedValue> mapfn = GetCallArg(argv, 1);
163 if (!mapfn->IsUndefined()) {
164 if (!mapfn->IsCallable()) {
165 THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception());
166 }
167 mapping = true;
168 }
169
170 // 5. Let usingIterator be ? GetMethod(source, @@iterator).
171 JSHandle<JSTaggedValue> source = GetCallArg(argv, 0);
172 JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
173 JSHandle<JSTaggedValue> usingIterator = JSObject::GetMethod(thread, source, iteratorSymbol);
174 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
175 JSHandle<JSTaggedValue> arrIter = JSObject::GetMethod(thread, env->GetArrayProtoValuesFunction(), iteratorSymbol);
176 JSHandle<JSTaggedValue> typedArrIter = JSObject::GetMethod(thread, env->GetTypedArrayPrototype(), iteratorSymbol);
177 bool isArrIter = JSTaggedValue::SameValue(usingIterator, arrIter);
178 bool isTypedArrIter = JSTaggedValue::SameValue(usingIterator, typedArrIter);
179 // 6. If usingIterator is not undefined, then
180 // a. Let values be ? IterableToList(source, usingIterator).
181 // b. Let len be the number of elements in values.
182 // c. Let targetObj be ? TypedArrayCreate(C, « len »).
183 if (!usingIterator->IsUndefined() && !(isArrIter || isTypedArrIter)) {
184 CVector<JSHandle<JSTaggedValue>> vec;
185 JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, source, usingIterator);
186 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
187 JSHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
188 while (!next->IsFalse()) {
189 next = JSIterator::IteratorStep(thread, iterator);
190 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191 if (!next->IsFalse()) {
192 JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
193 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue());
194 vec.push_back(nextValue);
195 }
196 }
197 uint32_t len = vec.size();
198 JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
199 JSHandle<JSObject> targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
200 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
201 // d. Let k be 0.
202 // e. Repeat, while k < len
203 // i. Let Pk be ! ToString(k).
204 // ii. Let kValue be the first element of values and remove that element from values.
205 // iii. If mapping is true, then
206 // 1. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
207 // iv. Else, let mappedValue be kValue.
208 // v. Perform ? Set(targetObj, Pk, mappedValue, true).
209 // vi. Set k to k + 1.
210 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
211 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
212 const int32_t argsLength = 2;
213 uint32_t k = 0;
214 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
215 while (k < len) {
216 tKey.Update(JSTaggedValue(k));
217 JSHandle<JSTaggedValue> kValue = vec[k];
218 if (mapping) {
219 EcmaRuntimeCallInfo *info =
220 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
221 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
222 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue());
223 JSTaggedValue callResult = JSFunction::Call(info);
224 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
225 mapValue.Update(callResult);
226 } else {
227 mapValue.Update(kValue.GetTaggedValue());
228 }
229 ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k,
230 mapValue.GetTaggedValue());
231 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
232 k++;
233 }
234 // f. Assert: values is now an empty List.
235 // g. Return targetObj.
236 return targetObj.GetTaggedValue();
237 }
238
239 // 7. NOTE: source is not an Iterable so assume it is already an array-like object.
240 // 8. Let arrayLike be ! ToObject(source).
241 JSHandle<JSObject> arrayLikeObj = JSTaggedValue::ToObject(thread, source);
242 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
243 JSHandle<JSTaggedValue> arrayLike(arrayLikeObj);
244 // 9. Let len be ? LengthOfArrayLike(arrayLike).
245 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
246 JSHandle<JSTaggedValue> lenResult = JSTaggedValue::GetProperty(thread, arrayLike, lengthKey).GetValue();
247 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
248 JSTaggedNumber tLen = JSTaggedValue::ToLength(thread, lenResult);
249 // 6. ReturnIfAbrupt(relativeTarget).
250 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
251 int64_t len = tLen.GetNumber();
252
253 // 10. Let targetObj be ? TypedArrayCreate(C, « len »).
254 JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
255 JSHandle<JSObject> targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
256 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
257 // 11. Let k be 0.
258 // 12. Repeat, while k < len
259 // a. Let Pk be ! ToString(k).
260 // b. Let kValue be ? Get(arrayLike, Pk).
261 // c. If mapping is true, then
262 // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
263 // d. Else, let mappedValue be kValue.
264 // e. Perform ? Set(targetObj, Pk, mappedValue, true).
265 // f. Set k to k + 1.
266 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
267 const int32_t argsLength = 2;
268 int64_t k = 0;
269 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
270 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
271 JSHandle<JSTaggedValue> mapValue;
272 while (k < len) {
273 tKey.Update(JSTaggedValue(k));
274 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, arrayLike.GetTaggedValue(),
275 tKey.GetTaggedValue()));
276 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
277 if (mapping) {
278 EcmaRuntimeCallInfo *info =
279 EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength);
280 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
281 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue());
282 JSTaggedValue callResult = JSFunction::Call(info);
283 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
284 mapValue = JSHandle<JSTaggedValue>(thread, callResult);
285 } else {
286 mapValue = kValue;
287 }
288 ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k, mapValue.GetTaggedValue());
289 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
290 k++;
291 }
292 // 13. Return targetObj.
293 return targetObj.GetTaggedValue();
294 }
295
296 // 22.2.2.2 %TypedArray%.of ( ...items )
Of(EcmaRuntimeCallInfo * argv)297 JSTaggedValue BuiltinsTypedArray::Of(EcmaRuntimeCallInfo *argv)
298 {
299 ASSERT(argv);
300 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Of);
301 JSThread *thread = argv->GetThread();
302 [[maybe_unused]] EcmaHandleScope handleScope(thread);
303 // 1. Let len be the actual number of arguments passed to this function.
304 uint32_t len = argv->GetArgsNumber();
305 // 2. Let items be the List of arguments passed to this function.
306 // 3. Let C be the this value.
307 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
308 // 4. If IsConstructor(C) is false, throw a TypeError exception.
309 if (!thisHandle->IsConstructor()) {
310 THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception());
311 }
312 // 5. Let newObj be TypedArrayCreate(C, « len »).
313 JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
314 JSHandle<JSObject> newObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args);
315 // 6. ReturnIfAbrupt(newObj).
316 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
317 // 7. Let k be 0.
318 // 8. Repeat, while k < len
319 // a. Let kValue be items[k].
320 // b. Let Pk be ! ToString(k).
321 // c. Perform ? Set(newObj, Pk, kValue, true).
322 // d. ReturnIfAbrupt(status).
323 // e. Set k to k + 1.
324 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
325 uint32_t k = 0;
326 while (k < len) {
327 tKey.Update(JSTaggedValue(k));
328 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
329 JSHandle<JSTaggedValue> kValue = GetCallArg(argv, k);
330 JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(newObj), kKey, kValue, true);
331 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
332 k++;
333 }
334 // 9. Return newObj.
335 return newObj.GetTaggedValue();
336 }
337
338 // 22.2.2.4
Species(EcmaRuntimeCallInfo * argv)339 JSTaggedValue BuiltinsTypedArray::Species(EcmaRuntimeCallInfo *argv)
340 {
341 ASSERT(argv);
342 // 1. Return the this value.
343 return GetThis(argv).GetTaggedValue();
344 }
345
346 // prototype
347 // 22.2.3.1 get %TypedArray%.prototype.buffer
GetBuffer(EcmaRuntimeCallInfo * argv)348 JSTaggedValue BuiltinsTypedArray::GetBuffer(EcmaRuntimeCallInfo *argv)
349 {
350 ASSERT(argv);
351 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, GetBuffer);
352 JSThread *thread = argv->GetThread();
353 [[maybe_unused]] EcmaHandleScope handleScope(thread);
354 // 1. Let O be the this value.
355 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
356 // 2. If Type(O) is not Object, throw a TypeError exception.
357 if (!thisHandle->IsECMAObject()) {
358 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
359 }
360 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
361 if (!thisHandle->IsTypedArray()) {
362 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
363 JSTaggedValue::Exception());
364 }
365 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
366 JSHandle<JSTypedArray> typedArray = JSHandle<JSTypedArray>::Cast(thisHandle);
367 JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, typedArray);
368 // 5. Return buffer.
369 return buffer;
370 }
371
372 // 22.2.3.2
GetByteLength(EcmaRuntimeCallInfo * argv)373 JSTaggedValue BuiltinsTypedArray::GetByteLength(EcmaRuntimeCallInfo *argv)
374 {
375 ASSERT(argv);
376 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, GetByteLength);
377 JSThread *thread = argv->GetThread();
378 [[maybe_unused]] EcmaHandleScope handleScope(thread);
379 // 1. Let O be the this value.
380 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
381 // 2. If Type(O) is not Object, throw a TypeError exception.
382 if (!thisHandle->IsECMAObject()) {
383 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
384 }
385 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
386 if (!thisHandle->IsTypedArray()) {
387 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
388 JSTaggedValue::Exception());
389 }
390 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
391 JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
392 JSTaggedValue buffer = typeArrayObj->GetViewedArrayBuffer();
393 // 5. If IsDetachedBuffer(buffer) is true, return 0.
394 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
395 return JSTaggedValue(0);
396 }
397 // 6. Let size be the value of O’s [[ByteLength]] internal slot.
398 // 7. Return size.
399 return JSTaggedValue(typeArrayObj->GetByteLength());
400 }
401
402 // 22.2.3.3
GetByteOffset(EcmaRuntimeCallInfo * argv)403 JSTaggedValue BuiltinsTypedArray::GetByteOffset(EcmaRuntimeCallInfo *argv)
404 {
405 ASSERT(argv);
406 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, GetByteOffset);
407 JSThread *thread = argv->GetThread();
408 [[maybe_unused]] EcmaHandleScope handleScope(thread);
409 // 1. Let O be the this value.
410 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
411 // 2. If Type(O) is not Object, throw a TypeError exception.
412 if (!thisHandle->IsECMAObject()) {
413 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
414 }
415 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
416 if (!thisHandle->IsTypedArray()) {
417 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
418 JSTaggedValue::Exception());
419 }
420 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
421 JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
422 JSTaggedValue buffer = typeArrayObj->GetViewedArrayBuffer();
423 // 5. If IsDetachedBuffer(buffer) is true, return 0.
424 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
425 return JSTaggedValue(0);
426 }
427 // 6. Let offset be the value of O’s [[ByteOffset]] internal slot.
428 uint32_t offset = typeArrayObj->GetByteOffset();
429 // 7. Return offset.
430 return JSTaggedValue(offset);
431 }
432
433 // 22.2.3.5
CopyWithin(EcmaRuntimeCallInfo * argv)434 JSTaggedValue BuiltinsTypedArray::CopyWithin(EcmaRuntimeCallInfo *argv)
435 {
436 ASSERT(argv);
437 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, CopyWithin);
438 if (!GetThis(argv)->IsTypedArray()) {
439 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
440 }
441 return BuiltinsArray::CopyWithin(argv);
442 }
443
444 // 22.2.3.6
Entries(EcmaRuntimeCallInfo * argv)445 JSTaggedValue BuiltinsTypedArray::Entries(EcmaRuntimeCallInfo *argv)
446 {
447 ASSERT(argv);
448 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Entries);
449 JSThread *thread = argv->GetThread();
450 [[maybe_unused]] EcmaHandleScope handleScope(thread);
451 // 1. Let O be the this value.
452 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
453 // 2. Let valid be ValidateTypedArray(O).
454 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
455 // 3. ReturnIfAbrupt(valid).
456 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
457 JSHandle<JSObject> self(thisHandle);
458 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
459 // 4. Return CreateArrayIterator(O, "key+value").
460 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::KEY_AND_VALUE));
461 return iter.GetTaggedValue();
462 }
463
464 // 22.2.3.7
Every(EcmaRuntimeCallInfo * argv)465 JSTaggedValue BuiltinsTypedArray::Every(EcmaRuntimeCallInfo *argv)
466 {
467 ASSERT(argv);
468 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Every);
469 JSThread *thread = argv->GetThread();
470 [[maybe_unused]] EcmaHandleScope handleScope(thread);
471
472 // 1. Let O be ToObject(this value).
473 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
474 if (!thisHandle->IsTypedArray()) {
475 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
476 }
477 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
478 // 2. ReturnIfAbrupt(O).
479 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
480 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
481
482 // 3. Let len be ToLength(Get(O, "length")).
483 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
484 // 4. ReturnIfAbrupt(len).
485 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
486
487 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
488 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
489 if (!callbackFnHandle->IsCallable()) {
490 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
491 }
492
493 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
494 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
495
496 // 7. Let k be 0.
497 // 8. Repeat, while k < len
498 // a. Let Pk be ToString(k).
499 // b. Let kPresent be HasProperty(O, Pk).
500 // c. ReturnIfAbrupt(kPresent).
501 // d. If kPresent is true, then
502 // i. Let kValue be Get(O, Pk).
503 // ii. ReturnIfAbrupt(kValue).
504 // iii. Let testResult be ToBoolean(Call(callbackfn, T, «kValue, k, O»)).
505 // iv. ReturnIfAbrupt(testResult).
506 // v. If testResult is false, return false.
507 // e. Increase k by 1.
508 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
509 const int32_t argsLength = 3;
510 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
511 uint32_t k = 0;
512 while (k < len) {
513 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
514 JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue();
515 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
516 key.Update(JSTaggedValue(k));
517 EcmaRuntimeCallInfo *info =
518 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
519 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
520 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
521 JSTaggedValue callResult = JSFunction::Call(info);
522 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
523 bool boolResult = callResult.ToBoolean();
524 if (!boolResult) {
525 return GetTaggedBoolean(false);
526 }
527 k++;
528 }
529
530 // 9. Return true.
531 return GetTaggedBoolean(true);
532 }
533
534 // 22.2.3.8
Fill(EcmaRuntimeCallInfo * argv)535 JSTaggedValue BuiltinsTypedArray::Fill(EcmaRuntimeCallInfo *argv)
536 {
537 ASSERT(argv);
538 if (!GetThis(argv)->IsTypedArray()) {
539 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
540 }
541 return BuiltinsArray::Fill(argv);
542 }
543
544 // 22.2.3.9 %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] )
Filter(EcmaRuntimeCallInfo * argv)545 JSTaggedValue BuiltinsTypedArray::Filter(EcmaRuntimeCallInfo *argv)
546 {
547 ASSERT(argv);
548 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Filter);
549 JSThread *thread = argv->GetThread();
550 [[maybe_unused]] EcmaHandleScope handleScope(thread);
551 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
552 // 1. Let O be the this value.
553 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
554 // 2. Let valid be ValidateTypedArray(O).
555 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
556 // 3. ReturnIfAbrupt(valid).
557 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
558
559 JSHandle<JSTypedArray> thisObj(thisHandle);
560 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
561 uint32_t len = thisObj->GetArrayLength();
562 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
563 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
564 if (!callbackFnHandle->IsCallable()) {
565 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
566 }
567 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
568 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
569
570 // 10. Let kept be a new empty List.
571 JSHandle<TaggedArray> kept(factory->NewTaggedArray(len));
572
573 // 11. Let k be 0.
574 // 12. Let captured be 0.
575 // 13. Repeat, while k < len
576 // a. Let Pk be ToString(k).
577 // b. Let kValue be Get(O, Pk).
578 // c. ReturnIfAbrupt(kValue).
579 // d. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)).
580 // e. ReturnIfAbrupt(selected).
581 // f. If selected is true, then
582 // i. Append kValue to the end of kept.
583 // ii. Increase captured by 1.
584 // g. Increase k by 1.
585 int32_t captured = 0;
586 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
587 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
588 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
589 for (uint32_t k = 0; k < len; k++) {
590 tKey.Update(JSTaggedValue(k));
591 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
592 tKey.GetTaggedValue()));
593 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
594 EcmaRuntimeCallInfo *info =
595 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle,
596 undefined, 3); // 3: «kValue, k, O»
597 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
598 info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue(), thisHandle.GetTaggedValue());
599 JSTaggedValue callResult = JSFunction::Call(info);
600 bool testResult = callResult.ToBoolean();
601 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
602 if (testResult) {
603 kept->Set(thread, captured, kValue);
604 captured++;
605 }
606 }
607 // es11 9. Let A be ? TypedArraySpeciesCreate(O, « captured »).
608 JSTaggedType args[1] = {JSTaggedValue(captured).GetRawData()};
609 JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args);
610 // 15. ReturnIfAbrupt(A).
611 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
612 // 16. Let n be 0.
613 // 17. For each element e of kept
614 // a. Let status be Set(A, ToString(n), e, true ).
615 // b. ReturnIfAbrupt(status).
616 // c. Increase n by 1.
617 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
618 JSMutableHandle<JSTaggedValue> ntKey(thread, JSTaggedValue::Undefined());
619 for (int32_t n = 0; n < captured; n++) {
620 valueHandle.Update(kept->Get(n));
621 ntKey.Update(JSTaggedValue(n));
622 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
623 ntKey.GetTaggedValue(), valueHandle.GetTaggedValue());
624 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
625 }
626 // 18. Return A.
627 return newArrObj.GetTaggedValue();
628 }
629
630 // 22.2.3.10
Find(EcmaRuntimeCallInfo * argv)631 JSTaggedValue BuiltinsTypedArray::Find(EcmaRuntimeCallInfo *argv)
632 {
633 ASSERT(argv);
634 if (!GetThis(argv)->IsTypedArray()) {
635 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
636 }
637 return BuiltinsArray::Find(argv);
638 }
639
640 // 22.2.3.11
FindIndex(EcmaRuntimeCallInfo * argv)641 JSTaggedValue BuiltinsTypedArray::FindIndex(EcmaRuntimeCallInfo *argv)
642 {
643 ASSERT(argv);
644 if (!GetThis(argv)->IsTypedArray()) {
645 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
646 }
647 return BuiltinsArray::FindIndex(argv);
648 }
649
650 // 22.2.3.12
ForEach(EcmaRuntimeCallInfo * argv)651 JSTaggedValue BuiltinsTypedArray::ForEach(EcmaRuntimeCallInfo *argv)
652 {
653 ASSERT(argv);
654 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ForEach);
655 JSThread *thread = argv->GetThread();
656 [[maybe_unused]] EcmaHandleScope handleScope(thread);
657
658 // 1. Let O be ToObject(this value).
659 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
660 if (!thisHandle->IsTypedArray()) {
661 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
662 }
663 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
664 // 2. ReturnIfAbrupt(O).
665 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
666 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
667
668 // 3. Let len be ToLength(Get(O, "length")).
669 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
670 // 4. ReturnIfAbrupt(len).
671 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
672
673 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
674 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
675 if (!callbackFnHandle->IsCallable()) {
676 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
677 }
678
679 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
680 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
681
682 // 7. Let k be 0.
683 // 8. Repeat, while k < len
684 // a. Let Pk be ToString(k).
685 // b. Let kPresent be HasProperty(O, Pk).
686 // c. ReturnIfAbrupt(kPresent).
687 // d. If kPresent is true, then
688 // i. Let kValue be Get(O, Pk).
689 // ii. ReturnIfAbrupt(kValue).
690 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
691 // iv. ReturnIfAbrupt(funcResult).
692 // e. Increase k by 1.
693 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
694 const int32_t argsLength = 3;
695 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
696 uint32_t k = 0;
697 while (k < len) {
698 JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue();
699 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
700 key.Update(JSTaggedValue(k));
701 EcmaRuntimeCallInfo *info =
702 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
703 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
704 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue());
705 JSTaggedValue funcResult = JSFunction::Call(info);
706 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
707 k++;
708 }
709
710 // 9. Return undefined.
711 return JSTaggedValue::Undefined();
712 }
713
714 // 22.2.3.13
IndexOf(EcmaRuntimeCallInfo * argv)715 JSTaggedValue BuiltinsTypedArray::IndexOf(EcmaRuntimeCallInfo *argv)
716 {
717 ASSERT(argv);
718 if (!GetThis(argv)->IsTypedArray()) {
719 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
720 }
721 return BuiltinsArray::IndexOf(argv);
722 }
723
724 // 22.2.3.14
Join(EcmaRuntimeCallInfo * argv)725 JSTaggedValue BuiltinsTypedArray::Join(EcmaRuntimeCallInfo *argv)
726 {
727 ASSERT(argv);
728 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Join);
729 JSThread *thread = argv->GetThread();
730 [[maybe_unused]] EcmaHandleScope handleScope(thread);
731
732 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
733
734 if (!thisHandle->IsTypedArray()) {
735 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
736 }
737
738 uint32_t length = JSHandle<JSTypedArray>::Cast(thisHandle)->GetArrayLength();
739
740 JSHandle<JSTaggedValue> sepHandle = GetCallArg(argv, 0);
741 int sep = ',';
742 uint32_t sepLength = 1;
743 JSHandle<EcmaString> sepStringHandle;
744 if (!sepHandle->IsUndefined()) {
745 if (sepHandle->IsString()) {
746 sepStringHandle = JSHandle<EcmaString>::Cast(sepHandle);
747 } else {
748 sepStringHandle = JSTaggedValue::ToString(thread, sepHandle);
749 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
750 }
751 if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) {
752 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
753 sep = EcmaStringAccessor(sepStringHandle).Get(0);
754 } else if (EcmaStringAccessor(sepStringHandle).GetLength() == 0) {
755 sep = BuiltinsTypedArray::SeparatorFlag::MINUS_TWO;
756 sepLength = 0;
757 } else {
758 sep = BuiltinsTypedArray::SeparatorFlag::MINUS_ONE;
759 sepLength = EcmaStringAccessor(sepStringHandle).GetLength();
760 }
761 }
762 if (length == 0) {
763 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
764 return globalConst->GetEmptyString();
765 }
766 size_t allocateLength = 0;
767 bool isOneByte = (sep != BuiltinsTypedArray::SeparatorFlag::MINUS_ONE) ||
768 EcmaStringAccessor(sepStringHandle).IsUtf8();
769 CVector<JSHandle<EcmaString>> vec;
770 JSMutableHandle<JSTaggedValue> elementHandle(thread, JSTaggedValue::Undefined());
771 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
772 for (uint32_t k = 0; k < length; k++) {
773 JSTaggedValue element = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue().GetTaggedValue();
774 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
775 if (!element.IsUndefinedOrNull() && !element.IsHole()) {
776 if (!element.IsString()) {
777 elementHandle.Update(element);
778 JSHandle<EcmaString> strElement = JSTaggedValue::ToString(thread, elementHandle);
779 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
780 element = strElement.GetTaggedValue();
781 }
782 auto nextStr = EcmaString::Cast(element.GetTaggedObject());
783 JSHandle<EcmaString> nextStrHandle(thread, nextStr);
784 vec.push_back(nextStrHandle);
785 isOneByte = EcmaStringAccessor(nextStr).IsUtf8() ? isOneByte : false;
786 allocateLength += EcmaStringAccessor(nextStr).GetLength();
787 } else {
788 vec.push_back(JSHandle<EcmaString>(globalConst->GetHandledEmptyString()));
789 }
790 }
791 allocateLength += sepLength * (length - 1);
792 auto newString = EcmaStringAccessor::AllocStringObject(thread->GetEcmaVM(), allocateLength, isOneByte);
793 int current = 0;
794 DISALLOW_GARBAGE_COLLECTION;
795 for (uint32_t k = 0; k < length; k++) {
796 if (k > 0) {
797 if (sep >= 0) {
798 EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
799 } else if (sep != BuiltinsTypedArray::SeparatorFlag::MINUS_TWO) {
800 EcmaStringAccessor::ReadData(
801 newString, *sepStringHandle, current, allocateLength - static_cast<size_t>(current), sepLength);
802 }
803 current += static_cast<int>(sepLength);
804 }
805 JSHandle<EcmaString> nextStr = vec[k];
806 int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
807 EcmaStringAccessor::ReadData(newString, *nextStr, current,
808 allocateLength - static_cast<size_t>(current), nextLength);
809 current += nextLength;
810 }
811 ASSERT_PRINT(
812 isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
813 return JSTaggedValue(newString);
814 }
815
816 // 22.2.3.15
Keys(EcmaRuntimeCallInfo * argv)817 JSTaggedValue BuiltinsTypedArray::Keys(EcmaRuntimeCallInfo *argv)
818 {
819 ASSERT(argv);
820 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Keys);
821 JSThread *thread = argv->GetThread();
822 [[maybe_unused]] EcmaHandleScope handleScope(thread);
823 // 1. Let O be the this value.
824 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
825 // 2. Let valid be ValidateTypedArray(O).
826 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
827 // 3. ReturnIfAbrupt(valid).
828 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
829 JSHandle<JSObject> self(thisHandle);
830 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
831 // 4. Return CreateArrayIterator(O, "key").
832 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::KEY));
833 return iter.GetTaggedValue();
834 }
835
836 // 22.2.3.16
LastIndexOf(EcmaRuntimeCallInfo * argv)837 JSTaggedValue BuiltinsTypedArray::LastIndexOf(EcmaRuntimeCallInfo *argv)
838 {
839 ASSERT(argv);
840 if (!GetThis(argv)->IsTypedArray()) {
841 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
842 }
843 return BuiltinsArray::LastIndexOf(argv);
844 }
845
846 // 22.2.3.17
GetLength(EcmaRuntimeCallInfo * argv)847 JSTaggedValue BuiltinsTypedArray::GetLength(EcmaRuntimeCallInfo *argv)
848 {
849 ASSERT(argv);
850 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, GetLength);
851 JSThread *thread = argv->GetThread();
852 [[maybe_unused]] EcmaHandleScope handleScope(thread);
853 // 1. Let O be the this value.
854 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
855 // 2. If Type(O) is not Object, throw a TypeError exception.
856 if (!thisHandle->IsECMAObject()) {
857 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
858 }
859 // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
860 if (!thisHandle->IsTypedArray()) {
861 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
862 JSTaggedValue::Exception());
863 }
864 // 4. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
865 // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
866 JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(thisHandle)->GetViewedArrayBuffer();
867 // 6. If IsDetachedBuffer(buffer) is true, return 0.
868 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
869 return JSTaggedValue(0);
870 }
871 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
872 uint32_t length = JSHandle<JSTypedArray>(thisHandle)->GetArrayLength();
873 // 8. Return length.
874 return JSTaggedValue(length);
875 }
876
877 // 22.2.3.18 %TypedArray%.prototype.map ( callbackfn [ , thisArg ] )
Map(EcmaRuntimeCallInfo * argv)878 JSTaggedValue BuiltinsTypedArray::Map(EcmaRuntimeCallInfo *argv)
879 {
880 ASSERT(argv);
881 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Map);
882 JSThread *thread = argv->GetThread();
883 [[maybe_unused]] EcmaHandleScope handleScope(thread);
884 // 1. Let O be the this value.
885 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
886 // 2. Let valid be ValidateTypedArray(O).
887 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
888 // 3. ReturnIfAbrupt(valid).
889 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
890
891 JSHandle<JSTypedArray> thisObj(thisHandle);
892 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
893 uint32_t len = thisObj->GetArrayLength();
894 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
895 JSHandle<JSTaggedValue> callbackfnHandle = GetCallArg(argv, 0);
896 if (!callbackfnHandle->IsCallable()) {
897 THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
898 }
899 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
900 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
901 // es11 5. Let A be ? TypedArraySpeciesCreate(O, « len »).
902 JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
903 JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args); // 1: one arg.
904 // 11. ReturnIfAbrupt(A).
905 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
906
907 // 12. Let k be 0.
908 // 13. Repeat, while k < len
909 // a. Let Pk be ToString(k).
910 // b. Let kValue be Get(O, Pk).
911 // c. ReturnIfAbrupt(kValue).
912 // d. Let mappedValue be Call(callbackfn, T, «kValue, k, O»).
913 // e. ReturnIfAbrupt(mappedValue).
914 // f. Let status be Set(A, Pk, mappedValue, true ).
915 // g. ReturnIfAbrupt(status).
916 // h. Increase k by 1.
917 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
918 JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
919 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
920 const int32_t argsLength = 3;
921 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
922 for (uint32_t k = 0; k < len; k++) {
923 key.Update(JSTaggedValue(k));
924 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
925 key.GetTaggedValue()));
926 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
927 EcmaRuntimeCallInfo *info =
928 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, undefined, argsLength);
929 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
930 info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
931 JSTaggedValue callResult = JSFunction::Call(info);
932 mapValue.Update(callResult);
933 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
934 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
935 key.GetTaggedValue(), mapValue.GetTaggedValue());
936 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
937 }
938
939 // 14. Return A.
940 return newArrObj.GetTaggedValue();
941 }
942
943 // 22.2.3.19
Reduce(EcmaRuntimeCallInfo * argv)944 JSTaggedValue BuiltinsTypedArray::Reduce(EcmaRuntimeCallInfo *argv)
945 {
946 ASSERT(argv);
947 if (!GetThis(argv)->IsTypedArray()) {
948 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
949 }
950 return BuiltinsArray::Reduce(argv);
951 }
952
953 // 22.2.3.20
ReduceRight(EcmaRuntimeCallInfo * argv)954 JSTaggedValue BuiltinsTypedArray::ReduceRight(EcmaRuntimeCallInfo *argv)
955 {
956 ASSERT(argv);
957 if (!GetThis(argv)->IsTypedArray()) {
958 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
959 }
960 return BuiltinsArray::ReduceRight(argv);
961 }
962
963 // 22.2.3.21
Reverse(EcmaRuntimeCallInfo * argv)964 JSTaggedValue BuiltinsTypedArray::Reverse(EcmaRuntimeCallInfo *argv)
965 {
966 ASSERT(argv);
967 if (!GetThis(argv)->IsTypedArray()) {
968 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
969 }
970 return BuiltinsArray::Reverse(argv);
971 }
972
973 // 22.2.3.22 %TypedArray%.prototype.set ( overloaded [ , offset ])
Set(EcmaRuntimeCallInfo * argv)974 JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
975 {
976 ASSERT(argv);
977 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Set);
978 JSThread *thread = argv->GetThread();
979 [[maybe_unused]] EcmaHandleScope handleScope(thread);
980 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
981 // 1. Assert: array is any ECMAScript language value other than an Object with a [[TypedArrayName]] internal slot.
982 // If it is such an Object, the definition in 22.2.3.22.2 applies.
983 // 2. Let target be the this value.
984 JSHandle<JSTaggedValue> target = GetThis(argv);
985 // 3. If Type(target) is not Object, throw a TypeError exception.
986 if (!target->IsECMAObject()) {
987 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
988 }
989 JSHandle<JSTypedArray> targetObj(target);
990 // 4. If target does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
991 if (!target->IsTypedArray()) {
992 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
993 JSTaggedValue::Exception());
994 }
995
996 // 5. Assert: target has a [[ViewedArrayBuffer]] internal slot.
997 // 6. Let targetOffset be ToInteger (offset).
998 const JSHandle<JSTaggedValue> srcOffset = GetCallArg(argv, 1);
999 uint32_t targetOffset = 0;
1000 if (srcOffset->IsInt()) {
1001 if (srcOffset->GetInt() < 0) {
1002 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1003 JSTaggedValue::Exception());
1004 }
1005 targetOffset = static_cast<uint32_t>(srcOffset->GetInt());
1006 } else {
1007 JSTaggedNumber tTargetOffset = JSTaggedValue::ToInteger(thread, srcOffset);
1008 // 7. ReturnIfAbrupt(targetOffset).
1009 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1010 double rawTargetOffset = tTargetOffset.GetNumber();
1011 // 8. If targetOffset < 0, throw a RangeError exception.
1012 if (rawTargetOffset < 0) {
1013 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1014 JSTaggedValue::Exception());
1015 } else if (rawTargetOffset == base::POSITIVE_INFINITY) {
1016 THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset is infinty, which is greater than targetLength.",
1017 JSTaggedValue::Exception());
1018 } else {
1019 targetOffset = static_cast<uint32_t>(rawTargetOffset);
1020 }
1021 }
1022 // 9. Let targetBuffer be the value of target’s [[ViewedArrayBuffer]] internal slot.
1023 JSHandle<JSTaggedValue> targetBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, targetObj));
1024 // 10. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1025 if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1026 THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1027 JSTaggedValue::Exception());
1028 }
1029 // 11. Let targetLength be the value of target’s [[ArrayLength]] internal slot.
1030 // 12. Let targetName be the String value of target’s [[TypedArrayName]] internal slot.
1031 // 13. Let targetElementSize be the Number value of the Element Size value specified in Table 49 for targetName.
1032 // 14. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1033 // 15. Let targetByteOffset be the value of target’s [[ByteOffset]] internal slot.
1034 uint32_t targetLength = targetObj->GetArrayLength();
1035 DataViewType targetType = TypedArrayHelper::GetType(targetObj);
1036 uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType);
1037 uint32_t targetByteOffset = targetObj->GetByteOffset();
1038
1039 JSHandle<JSTaggedValue> argArray = GetCallArg(argv, 0);
1040
1041 // 22.2.3.22.1 %TypedArray%.prototype.set (array [ , offset ] )
1042 if (!argArray->IsTypedArray()) {
1043 if (argArray->IsStableJSArray(thread)) {
1044 uint32_t length = JSHandle<JSArray>::Cast(argArray)->GetArrayLength();
1045 JSHandle<TaggedArray> elements(thread, JSHandle<JSArray>::Cast(argArray)->GetElements());
1046 uint32_t elemLength = elements->GetLength();
1047 // Load On Demand check
1048 if (elemLength >= length) {
1049 return JSStableArray::FastCopyFromArrayToTypedArray(thread, targetObj, targetType,
1050 targetOffset, length, elements);
1051 }
1052 }
1053 // 16. Let src be ToObject(array).
1054 JSHandle<JSObject> src = JSTaggedValue::ToObject(thread, argArray);
1055 // 17. ReturnIfAbrupt(src).
1056 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1057 // 18. Let srcLength be ToLength(Get(src, "length")).
1058 JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
1059 JSHandle<JSTaggedValue> lenResult(thread,
1060 ObjectFastOperator::FastGetPropertyByValue(thread,
1061 JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(),
1062 lengthKey.GetTaggedValue()));
1063 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1064 JSTaggedNumber tSrcLen = JSTaggedValue::ToLength(thread, lenResult);
1065 // 19. ReturnIfAbrupt(srcLength).
1066 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1067 uint64_t srcLen = static_cast<uint64_t>(tSrcLen.GetNumber());
1068 // 20. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1069 if (srcLen + targetOffset > targetLength) {
1070 THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1071 JSTaggedValue::Exception());
1072 }
1073 // 21. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1074 ASSERT((static_cast<uint64_t>(targetOffset) * static_cast<uint64_t>(targetElementSize) +
1075 static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1076 uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset * targetElementSize + targetByteOffset);
1077 // 22. Let k be 0.
1078 // 23. Let limit be targetByteIndex + targetElementSize × srcLength.
1079 uint32_t k = 0;
1080 ASSERT((static_cast<uint64_t>(targetElementSize) * srcLen +
1081 static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1082 uint32_t limit = targetByteIndex + targetElementSize * srcLen;
1083 // 24. Repeat, while targetByteIndex < limit
1084 // a. Let Pk be ToString(k).
1085 // b. If target.[[ContentType]] is BigInt, set value to ? ToBigInt(value).
1086 // c. Otherwise, set value to ? ToNumber(value).
1087 // d. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1088 // e. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, kNumber).
1089 // f. Set k to k + 1.
1090 // g. Set targetByteIndex to targetByteIndex + targetElementSize.
1091 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Hole());
1092 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
1093 JSMutableHandle<JSTaggedValue> kNumberHandle(thread, JSTaggedValue::Hole());
1094 ContentType contentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1095 while (targetByteIndex < limit) {
1096 tKey.Update(JSTaggedValue(k));
1097 JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
1098 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(
1099 thread, JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(), kKey.GetTaggedValue()));
1100 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1101 if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1102 THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1103 JSTaggedValue::Exception());
1104 }
1105 if (contentType == ContentType::BigInt) {
1106 kNumberHandle.Update(JSTaggedValue::ToBigInt(thread, kValue));
1107 } else {
1108 kNumberHandle.Update(JSTaggedValue::ToNumber(thread, kValue));
1109 }
1110 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1111 BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
1112 targetType, kNumberHandle, true);
1113 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1114 k++;
1115 targetByteIndex = targetByteIndex + targetElementSize;
1116 }
1117 // 25. Return undefined.
1118 return JSTaggedValue::Undefined();
1119 }
1120
1121 // 22.2.3.22.2 %TypedArray%.prototype.set(typedArray [, offset ] )
1122 JSHandle<JSTypedArray> typedArray(argArray);
1123 // 12. Let srcBuffer be the value of typedArray’s [[ViewedArrayBuffer]] internal slot.
1124 // 13. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1125 JSTaggedValue srcBuffer = typedArray->GetViewedArrayBuffer();
1126 JSHandle<JSTaggedValue> srcBufferHandle = JSHandle<JSTaggedValue>(thread, srcBuffer);
1127 if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1128 THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of typedArray is detached buffer.",
1129 JSTaggedValue::Exception());
1130 }
1131
1132 ContentType objContentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1133 ContentType argArrayContentType = JSHandle<JSTypedArray>::Cast(argArray)->GetContentType();
1134 if (argArrayContentType != objContentType) {
1135 THROW_TYPE_ERROR_AND_RETURN(thread,
1136 "argArrayContentType is not equal objContentType.",
1137 JSTaggedValue::Exception());
1138 }
1139 // 18. Let srcName be the String value of typedArray’s [[TypedArrayName]] internal slot.
1140 // 19. Let srcType be the String value of the Element Type value in Table 49 for srcName .
1141 // 20. Let srcElementSize be the Number value of the Element Size value specified in Table 49 for srcName.
1142 // 21. Let srcLength be the value of typedArray’s [[ArrayLength]] internal slot.
1143 // 22. Let srcByteOffset be the value of typedArray’s [[ByteOffset]] internal slot.
1144 JSHandle<JSTaggedValue> srcName(thread, typedArray->GetTypedArrayName());
1145 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1146 uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType);
1147 uint32_t srcLength = typedArray->GetArrayLength();
1148 uint32_t srcByteOffset = typedArray->GetByteOffset();
1149 // 23. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1150 if (srcLength + targetOffset > targetLength) {
1151 THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1152 JSTaggedValue::Exception());
1153 }
1154 // 24. If SameValue(srcBuffer, targetBuffer) is true, then
1155 // a. Let srcBuffer be CloneArrayBuffer(targetBuffer, srcByteOffset, %ArrayBuffer%).
1156 // b. NOTE: %ArrayBuffer% is used to clone targetBuffer because is it known to not have any observable
1157 // side-effects.
1158 // c. ReturnIfAbrupt(srcBuffer).
1159 // d. Let srcByteIndex be 0.
1160 // 25. Else, let srcByteIndex be srcByteOffset.
1161 uint32_t srcByteIndex = 0;
1162 if (JSTaggedValue::SameValue(srcBufferHandle.GetTaggedValue(), targetBuffer.GetTaggedValue())) {
1163 srcBuffer =
1164 BuiltinsArrayBuffer::CloneArrayBuffer(thread, targetBuffer, srcByteOffset, env->GetArrayBufferFunction());
1165 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1166 srcBufferHandle = JSHandle<JSTaggedValue>(thread, srcBuffer);
1167 srcByteIndex = 0;
1168 } else {
1169 srcByteIndex = srcByteOffset;
1170 }
1171 // 26. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1172 ASSERT((static_cast<uint64_t>(targetOffset) * static_cast<uint64_t>(targetElementSize) +
1173 static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1174 uint32_t targetByteIndex = targetOffset * targetElementSize + targetByteOffset;
1175 // 27. Let limit be targetByteIndex + targetElementSize × srcLength.
1176 ASSERT((static_cast<uint64_t>(targetElementSize) * static_cast<uint64_t>(srcLength) +
1177 static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1178 uint32_t limit = targetByteIndex + targetElementSize * srcLength;
1179 uint32_t count = (limit - targetByteIndex) > 0 ? (limit - targetByteIndex) : 0;
1180 // 28. If SameValue(srcType, targetType) is false, then
1181 // a. Repeat, while targetByteIndex < limit
1182 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType).
1183 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, targetType, value).
1184 // iii. Set srcByteIndex to srcByteIndex + srcElementSize.
1185 // iv. Set targetByteIndex to targetByteIndex + targetElementSize.
1186 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
1187 if (srcType != targetType) {
1188 while (targetByteIndex < limit) {
1189 JSTaggedValue taggedData =
1190 BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBufferHandle.GetTaggedValue(),
1191 srcByteIndex, srcType, true);
1192 value.Update(taggedData);
1193 BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
1194 targetType, value, true);
1195 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1196 srcByteIndex = srcByteIndex + srcElementSize;
1197 targetByteIndex = targetByteIndex + targetElementSize;
1198 }
1199 } else if (count > 0) {
1200 // 29. Else,
1201 // a. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that preserves
1202 // the bit-level encoding of the source data.
1203 // b. Repeat, while targetByteIndex < limit
1204 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1205 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1206 // iii. Set srcByteIndex to srcByteIndex + 1.
1207 // iv. Set targetByteIndex to targetByteIndex + 1.
1208 void *srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBufferHandle.GetTaggedValue(), srcByteIndex);
1209 void *targetBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer.GetTaggedValue(), targetByteIndex);
1210 if (memcpy_s(targetBuf, srcLength * srcElementSize, srcBuf, srcLength * srcElementSize) != EOK) {
1211 LOG_FULL(FATAL) << "memcpy_s failed";
1212 UNREACHABLE();
1213 }
1214 }
1215 // 30. Return undefined.
1216 return JSTaggedValue::Undefined();
1217 } // namespace panda::ecmascript::builtins
1218
1219 // 22.2.3.23 %TypedArray%.prototype.slice ( start, end )
Slice(EcmaRuntimeCallInfo * argv)1220 JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv)
1221 {
1222 ASSERT(argv);
1223 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Slice);
1224 JSThread *thread = argv->GetThread();
1225 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1226 // 1. Let O be the this value.
1227 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1228 // 2. Let valid be ValidateTypedArray(O).
1229 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1230 // 3. ReturnIfAbrupt(valid).
1231 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1232
1233 JSHandle<JSTypedArray> thisObj(thisHandle);
1234 // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
1235 uint32_t len = thisObj->GetArrayLength();
1236
1237 // 5. Let relativeStart be ToInteger(start).
1238 JSTaggedNumber tRelativeStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1239 // 6. ReturnIfAbrupt(relativeStart).
1240 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1241 double relativeStart = tRelativeStart.GetNumber();
1242 // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
1243
1244 uint32_t k = relativeStart < 0 ?
1245 std::max((static_cast<double>(len) + relativeStart), 0.0) :
1246 std::min(relativeStart, static_cast<double>(len));
1247 // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
1248 double relativeEnd = len;
1249 JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1250 if (!end->IsUndefined()) {
1251 JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1252 // 9. ReturnIfAbrupt(relativeEnd).
1253 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1254 relativeEnd = tRelativeEnd.GetNumber();
1255 }
1256
1257 // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
1258
1259 uint32_t final = relativeEnd < 0 ?
1260 std::max((static_cast<double>(len) + relativeEnd), 0.0) :
1261 std::min(relativeEnd, static_cast<double>(len));
1262 // 11. Let count be max(final – k, 0).
1263 uint32_t count = final > k ? (final - k) : 0;
1264 // es11 9. Let A be ? TypedArraySpeciesCreate(O, « count »).
1265 JSTaggedType args[1] = {JSTaggedValue(count).GetRawData()};
1266 JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args);
1267 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1268 // 17. Let srcName be the String value of O’s [[TypedArrayName]] internal slot.
1269 // 18. Let srcType be the String value of the Element Type value in Table 49 for srcName.
1270 JSHandle<JSTaggedValue> srcName(thread, thisObj->GetTypedArrayName());
1271 DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1272 // 19. Let targetName be the String value of A’s [[TypedArrayName]] internal slot.
1273 // 20. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1274 JSHandle<JSTaggedValue> targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName());
1275 DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
1276 // 21. If SameValue(srcType, targetType) is false, then
1277 // a. Let n be 0.
1278 // b. Repeat, while k < final
1279 // i. Let Pk be ToString(k).
1280 // ii. Let kValue be Get(O, Pk).
1281 // iii. ReturnIfAbrupt(kValue).
1282 // iv. Let status be Set(A, ToString(n), kValue, true ).
1283 // v. ReturnIfAbrupt(status).
1284 // vi. Increase k by 1.
1285 // vii. Increase n by 1.
1286 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
1287 JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
1288 JSMutableHandle<JSTaggedValue> ntKey(thread, JSTaggedValue::Undefined());
1289 if (srcType != targetType) {
1290 uint32_t n = 0;
1291 while (k < final) {
1292 tKey.Update(JSTaggedValue(k));
1293 kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
1294 tKey.GetTaggedValue()));
1295 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1296 ntKey.Update(JSTaggedValue(n));
1297 ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
1298 ntKey.GetTaggedValue(), kValue.GetTaggedValue());
1299 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1300 n++;
1301 k++;
1302 }
1303 } else if (count > 0) {
1304 // 22. Else if count > 0,
1305 // a. Let srcBuffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1306 // b. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1307 JSTaggedValue srcBuffer = thisObj->GetViewedArrayBuffer();
1308 if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1309 THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
1310 JSTaggedValue::Exception());
1311 }
1312 // c. Let targetBuffer be the value of A’s [[ViewedArrayBuffer]] internal slot.
1313 JSTaggedValue targetBuffer = JSTypedArray::Cast(*newArrObj)->GetViewedArrayBuffer();
1314 // d. Let elementSize be the Number value of the Element Size value specified in Table 49 for srcType.
1315 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(srcType);
1316 // e. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that
1317 // preserves the bit-level encoding of the source data. f. Let srcByteOffset be the value of O’s
1318 // [[ByteOffset]] internal slot.
1319 uint32_t srcByteOffset = thisObj->GetByteOffset();
1320 // g. Let targetByteIndex be 0.
1321 // h. Let srcByteIndex be (k × elementSize) + srcByteOffset.
1322 uint32_t srcByteIndex = k * elementSize + srcByteOffset;
1323 // i. Repeat, while targetByteIndex < count × elementSize
1324 // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1325 // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1326 // iii. Increase srcByteIndex by 1.
1327 // iv. Increase targetByteIndex by 1.
1328 void *srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBuffer, srcByteIndex);
1329 void *targetBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer);
1330 if (memcpy_s(targetBuf, count * elementSize, srcBuf, count * elementSize) != EOK) {
1331 LOG_FULL(FATAL) << "memcpy_s failed";
1332 UNREACHABLE();
1333 }
1334 }
1335 // 23. Return A.
1336 return newArrObj.GetTaggedValue();
1337 }
1338
1339 // 22.2.3.24
Some(EcmaRuntimeCallInfo * argv)1340 JSTaggedValue BuiltinsTypedArray::Some(EcmaRuntimeCallInfo *argv)
1341 {
1342 ASSERT(argv);
1343 if (!GetThis(argv)->IsTypedArray()) {
1344 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1345 }
1346 return BuiltinsArray::Some(argv);
1347 }
1348
1349 // 22.2.3.25
Sort(EcmaRuntimeCallInfo * argv)1350 JSTaggedValue BuiltinsTypedArray::Sort(EcmaRuntimeCallInfo *argv)
1351 {
1352 ASSERT(argv);
1353 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Sort);
1354 JSThread *thread = argv->GetThread();
1355 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1356
1357 // 1. Let obj be ToObject(this value).
1358 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1359 if (!thisHandle->IsTypedArray()) {
1360 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1361 }
1362
1363 JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1364 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1365 JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1366
1367 JSHandle<JSTaggedValue> buffer;
1368 buffer = JSHandle<JSTaggedValue>(thread, TypedArrayHelper::ValidateTypedArray(thread, thisHandle));
1369 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1370 uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1371
1372 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1373 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
1374 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
1375 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
1376 JSMutableHandle<JSTaggedValue> key1(thread, JSTaggedValue::Undefined());
1377 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1378 JSMutableHandle<JSTaggedValue> key2(thread, JSTaggedValue::Undefined());
1379 for (uint32_t i = 1; i < len; i++) {
1380 uint32_t beginIndex = 0;
1381 uint32_t endIndex = i;
1382 key.Update(JSTaggedValue(i));
1383 presentValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1384 key.GetTaggedValue()));
1385 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1386 while (beginIndex < endIndex) {
1387 uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
1388 key1.Update(JSTaggedValue(middleIndex));
1389 middleValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1390 key1.GetTaggedValue()));
1391 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1392 int32_t compareResult = TypedArrayHelper::SortCompare(thread, callbackFnHandle, buffer,
1393 middleValue, presentValue);
1394 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1395 compareResult > 0 ? (endIndex = middleIndex) : (beginIndex = middleIndex + 1);
1396 }
1397
1398 if (endIndex < i) {
1399 for (uint32_t j = i; j > endIndex; j--) {
1400 key2.Update(JSTaggedValue(j - 1));
1401 previousValue.Update(
1402 ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1403 key2.GetTaggedValue()));
1404 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1405 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
1406 previousValue.GetTaggedValue());
1407 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1408 }
1409 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
1410 presentValue.GetTaggedValue());
1411 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1412 }
1413 }
1414 return thisObjHandle.GetTaggedValue();
1415 }
1416
1417 // 22.2.3.26 %TypedArray%.prototype.subarray( [ begin [ , end ] ] )
Subarray(EcmaRuntimeCallInfo * argv)1418 JSTaggedValue BuiltinsTypedArray::Subarray(EcmaRuntimeCallInfo *argv)
1419 {
1420 ASSERT(argv);
1421 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Subarray);
1422 JSThread *thread = argv->GetThread();
1423 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1424 // 1. Let O be the this value.
1425 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1426 // 2. If Type(O) is not Object, throw a TypeError exception.
1427 if (!thisHandle->IsECMAObject()) {
1428 THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
1429 }
1430 JSHandle<JSTypedArray> thisObj(thisHandle);
1431 // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
1432 if (!thisHandle->IsTypedArray()) {
1433 THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
1434 JSTaggedValue::Exception());
1435 }
1436 // 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
1437 // 6. Let srcLength be the value of O’s [[ArrayLength]] internal slot.
1438 uint32_t srcLength = thisObj->GetArrayLength();
1439 // 7. Let relativeBegin be ToInteger(begin).
1440 JSTaggedNumber tRelativeBegin = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1441 // 8. ReturnIfAbrupt(relativeBegin).
1442 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1443 double relativeBegin = tRelativeBegin.GetNumber();
1444
1445 uint32_t beginIndex = 0;
1446 // 9. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin), 0); else let beginIndex be
1447 // min(relativeBegin, srcLength).
1448 if (relativeBegin < 0) {
1449 double tempBeginIndex = relativeBegin + static_cast<double>(srcLength);
1450 beginIndex = tempBeginIndex > 0 ? static_cast<uint32_t>(tempBeginIndex) : 0;
1451 } else {
1452 beginIndex = relativeBegin < static_cast<double>(srcLength) ?
1453 static_cast<uint32_t>(relativeBegin) : srcLength;
1454 }
1455
1456 // 10. If end is undefined, let relativeEnd be srcLength; else, let relativeEnd be ToInteger(end).
1457 double relativeEnd = srcLength;
1458 JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1459 if (!end->IsUndefined()) {
1460 JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1461 // 11. ReturnIfAbrupt(relativeEnd).
1462 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1463 relativeEnd = tRelativeEnd.GetNumber();
1464 }
1465 // 12. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0); else let endIndex be
1466 // min(relativeEnd, srcLength).
1467 uint32_t endIndex;
1468 if (relativeEnd < 0) {
1469 double tempEndIndex = relativeEnd + static_cast<double>(srcLength);
1470 endIndex = tempEndIndex > 0 ? static_cast<uint32_t>(tempEndIndex) : 0;
1471 } else {
1472 endIndex = relativeEnd < static_cast<double>(srcLength) ?
1473 static_cast<uint32_t>(relativeEnd) : srcLength;
1474 }
1475 // 13. Let newLength be max(endIndex – beginIndex, 0).
1476 uint32_t newLength = endIndex > beginIndex ? (endIndex - beginIndex) : 0;
1477 // 14. Let constructorName be the String value of O’s [[TypedArrayName]] internal slot.
1478 // 15. Let elementSize be the Number value of the Element Size value specified in Table 49 for constructorName.
1479 // 16. Let srcByteOffset be the value of O’s [[ByteOffset]] internal slot.
1480 // 17. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
1481 JSHandle<JSTaggedValue> constructorName(thread, thisObj->GetTypedArrayName());
1482 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName);
1483 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType);
1484 uint32_t srcByteOffset = thisObj->GetByteOffset();
1485 ASSERT((static_cast<uint64_t>(srcByteOffset) + static_cast<uint64_t>(beginIndex) *
1486 static_cast<uint64_t>(elementSize)) <= static_cast<uint64_t>(UINT32_MAX));
1487 uint32_t beginByteOffset = srcByteOffset + beginIndex * elementSize;
1488 JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, thisObj);
1489 // 21. Let argumentsList be «buffer, beginByteOffset, newLength».
1490 // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1491 // 22. Return Construct(constructor, argumentsList).
1492 const int32_t argsLength = 3;
1493 JSTaggedType args[argsLength] = {
1494 buffer.GetRawData(),
1495 JSTaggedValue(beginByteOffset).GetRawData(),
1496 JSTaggedValue(newLength).GetRawData()
1497 };
1498 JSHandle<JSObject> newArr = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, argsLength, args);
1499 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1500 return newArr.GetTaggedValue();
1501 }
1502
1503 // 22.2.3.27
ToLocaleString(EcmaRuntimeCallInfo * argv)1504 JSTaggedValue BuiltinsTypedArray::ToLocaleString(EcmaRuntimeCallInfo *argv)
1505 {
1506 ASSERT(argv);
1507 if (!GetThis(argv)->IsTypedArray()) {
1508 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1509 }
1510 return BuiltinsArray::ToLocaleString(argv);
1511 }
1512
1513 // 22.2.3.28
ToString(EcmaRuntimeCallInfo * argv)1514 JSTaggedValue BuiltinsTypedArray::ToString(EcmaRuntimeCallInfo *argv)
1515 {
1516 ASSERT(argv);
1517 if (!GetThis(argv)->IsTypedArray()) {
1518 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1519 }
1520 return BuiltinsArray::ToString(argv);
1521 }
1522
1523 // 22.2.3.29
Values(EcmaRuntimeCallInfo * argv)1524 JSTaggedValue BuiltinsTypedArray::Values(EcmaRuntimeCallInfo *argv)
1525 {
1526 ASSERT(argv);
1527 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Values);
1528 JSThread *thread = argv->GetThread();
1529 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1530 // 1. Let O be the this value.
1531 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1532 // 2. Let valid be ValidateTypedArray(O).
1533 TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1534 // 3. ReturnIfAbrupt(valid).
1535 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
1536 JSHandle<JSObject> self(thisHandle);
1537 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1538 // 4. Return CreateArrayIterator(O, "value").
1539 JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::VALUE));
1540 return iter.GetTaggedValue();
1541 }
1542
1543 // 22.2.3.31
ToStringTag(EcmaRuntimeCallInfo * argv)1544 JSTaggedValue BuiltinsTypedArray::ToStringTag(EcmaRuntimeCallInfo *argv)
1545 {
1546 ASSERT(argv);
1547 BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ToStringTag);
1548 JSThread *thread = argv->GetThread();
1549 [[maybe_unused]] EcmaHandleScope handleScope(thread);
1550 // 1. Let O be the this value.
1551 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1552 // 2. If Type(O) is not Object, return undefined.
1553 if (!thisHandle->IsECMAObject()) {
1554 return JSTaggedValue::Undefined();
1555 }
1556 // 3. If O does not have a [[TypedArrayName]] internal slot, return undefined.
1557 if (!thisHandle->IsTypedArray()) {
1558 return JSTaggedValue::Undefined();
1559 }
1560 // 4. Let name be the value of O’s [[TypedArrayName]] internal slot.
1561 JSTaggedValue name = JSHandle<JSTypedArray>::Cast(thisHandle)->GetTypedArrayName();
1562 // 5. Assert: name is a String value.
1563 ASSERT(name.IsString());
1564 // 6. Return name.
1565 return name;
1566 }
1567
1568 // es12 23.2.3.13
Includes(EcmaRuntimeCallInfo * argv)1569 JSTaggedValue BuiltinsTypedArray::Includes(EcmaRuntimeCallInfo *argv)
1570 {
1571 ASSERT(argv);
1572 if (!GetThis(argv)->IsTypedArray()) {
1573 THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1574 }
1575 return BuiltinsArray::Includes(argv);
1576 }
1577 } // namespace panda::ecmascript::builtins
1578