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