• 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     if (allocateLength <= 1) {
811         // sep unused, set isOneByte to default(true)
812         isOneByte = true;
813     }
814     auto newString = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), allocateLength, isOneByte);
815     int current = 0;
816     DISALLOW_GARBAGE_COLLECTION;
817     for (uint32_t k = 0; k < length; k++) {
818         if (k > 0) {
819             if (sep >= 0) {
820                 EcmaStringAccessor(newString).Set(current, static_cast<uint16_t>(sep));
821             } else if (sep != BuiltinsTypedArray::SeparatorFlag::MINUS_TWO) {
822                 EcmaStringAccessor::ReadData(
823                     newString, *sepStringHandle, current, allocateLength - static_cast<size_t>(current), sepLength);
824             }
825             current += static_cast<int>(sepLength);
826         }
827         JSHandle<EcmaString> nextStr = vec[k];
828         int nextLength = static_cast<int>(EcmaStringAccessor(nextStr).GetLength());
829         EcmaStringAccessor::ReadData(newString, *nextStr, current,
830             allocateLength - static_cast<size_t>(current), nextLength);
831         current += nextLength;
832     }
833     ASSERT_PRINT(
834         isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!");
835     return JSTaggedValue(newString);
836 }
837 
838 // 22.2.3.15
Keys(EcmaRuntimeCallInfo * argv)839 JSTaggedValue BuiltinsTypedArray::Keys(EcmaRuntimeCallInfo *argv)
840 {
841     ASSERT(argv);
842     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Keys);
843     JSThread *thread = argv->GetThread();
844     [[maybe_unused]] EcmaHandleScope handleScope(thread);
845     // 1. Let O be the this value.
846     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
847     // 2. Let valid be ValidateTypedArray(O).
848     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
849     // 3. ReturnIfAbrupt(valid).
850     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
851     JSHandle<JSObject> self(thisHandle);
852     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
853     // 4. Return CreateArrayIterator(O, "key").
854     JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::KEY));
855     return iter.GetTaggedValue();
856 }
857 
858 // 22.2.3.16
LastIndexOf(EcmaRuntimeCallInfo * argv)859 JSTaggedValue BuiltinsTypedArray::LastIndexOf(EcmaRuntimeCallInfo *argv)
860 {
861     ASSERT(argv);
862     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, LastIndexOf);
863     if (!GetThis(argv)->IsTypedArray()) {
864         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
865     }
866     return BuiltinsArray::LastIndexOf(argv);
867 }
868 
869 // 22.2.3.17
GetLength(EcmaRuntimeCallInfo * argv)870 JSTaggedValue BuiltinsTypedArray::GetLength(EcmaRuntimeCallInfo *argv)
871 {
872     ASSERT(argv);
873     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, GetLength);
874     JSThread *thread = argv->GetThread();
875     [[maybe_unused]] EcmaHandleScope handleScope(thread);
876     // 1. Let O be the this value.
877     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
878     // 2. If Type(O) is not Object, throw a TypeError exception.
879     if (!thisHandle->IsECMAObject()) {
880         THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
881     }
882     // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
883     if (!thisHandle->IsTypedArray()) {
884         THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
885                                     JSTaggedValue::Exception());
886     }
887     // 4. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
888     // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
889     JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(thisHandle)->GetViewedArrayBufferOrByteArray();
890     // 6. If IsDetachedBuffer(buffer) is true, return 0.
891     if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
892         return JSTaggedValue(0);
893     }
894     // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
895     uint32_t length = JSHandle<JSTypedArray>(thisHandle)->GetArrayLength();
896     // 8. Return length.
897     return JSTaggedValue(length);
898 }
899 
900 // 22.2.3.18 %TypedArray%.prototype.map ( callbackfn [ , thisArg ] )
Map(EcmaRuntimeCallInfo * argv)901 JSTaggedValue BuiltinsTypedArray::Map(EcmaRuntimeCallInfo *argv)
902 {
903     ASSERT(argv);
904     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Map);
905     JSThread *thread = argv->GetThread();
906     [[maybe_unused]] EcmaHandleScope handleScope(thread);
907     // 1. Let O be the this value.
908     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
909     // 2. Let valid be ValidateTypedArray(O).
910     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
911     // 3. ReturnIfAbrupt(valid).
912     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
913 
914     JSHandle<JSTypedArray> thisObj(thisHandle);
915     // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
916     uint32_t len = thisObj->GetArrayLength();
917     // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
918     JSHandle<JSTaggedValue> callbackfnHandle = GetCallArg(argv, 0);
919     if (!callbackfnHandle->IsCallable()) {
920         THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception());
921     }
922     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
923     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
924     // es11 5. Let A be ? TypedArraySpeciesCreate(O, « len »).
925     JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
926     JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args); // 1: one arg.
927     // 11. ReturnIfAbrupt(A).
928     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
929 
930     // 12. Let k be 0.
931     // 13. Repeat, while k < len
932     //   a. Let Pk be ToString(k).
933     //   b. Let kValue be Get(O, Pk).
934     //   c. ReturnIfAbrupt(kValue).
935     //   d. Let mappedValue be Call(callbackfn, T, «kValue, k, O»).
936     //   e. ReturnIfAbrupt(mappedValue).
937     //   f. Let status be Set(A, Pk, mappedValue, true ).
938     //   g. ReturnIfAbrupt(status).
939     //   h. Increase k by 1.
940     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
941     JSMutableHandle<JSTaggedValue> mapValue(thread, JSTaggedValue::Undefined());
942     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
943     const uint32_t argsLength = 3;
944     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
945     for (uint32_t k = 0; k < len; k++) {
946         key.Update(JSTaggedValue(k));
947         kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
948                                                                  key.GetTaggedValue()));
949         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
950         EcmaRuntimeCallInfo *info =
951             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, undefined, argsLength);
952         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
953         info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
954         JSTaggedValue callResult = JSFunction::Call(info);
955         mapValue.Update(callResult);
956         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
957         ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
958                                                    key.GetTaggedValue(), mapValue.GetTaggedValue());
959         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
960     }
961 
962     // 14. Return A.
963     return newArrObj.GetTaggedValue();
964 }
965 
966 // 22.2.3.19
Reduce(EcmaRuntimeCallInfo * argv)967 JSTaggedValue BuiltinsTypedArray::Reduce(EcmaRuntimeCallInfo *argv)
968 {
969     ASSERT(argv);
970     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Reduce);
971     if (!GetThis(argv)->IsTypedArray()) {
972         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
973     }
974     return BuiltinsArray::Reduce(argv);
975 }
976 
977 // 22.2.3.20
ReduceRight(EcmaRuntimeCallInfo * argv)978 JSTaggedValue BuiltinsTypedArray::ReduceRight(EcmaRuntimeCallInfo *argv)
979 {
980     ASSERT(argv);
981     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ReduceRight);
982     if (!GetThis(argv)->IsTypedArray()) {
983         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
984     }
985     return BuiltinsArray::ReduceRight(argv);
986 }
987 
988 // 22.2.3.21
Reverse(EcmaRuntimeCallInfo * argv)989 JSTaggedValue BuiltinsTypedArray::Reverse(EcmaRuntimeCallInfo *argv)
990 {
991     ASSERT(argv);
992     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Reverse);
993     if (!GetThis(argv)->IsTypedArray()) {
994         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
995     }
996     return BuiltinsArray::Reverse(argv);
997 }
998 
999 // 22.2.3.22 %TypedArray%.prototype.set ( overloaded [ , offset ])
Set(EcmaRuntimeCallInfo * argv)1000 JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
1001 {
1002     ASSERT(argv);
1003     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Set);
1004     JSThread *thread = argv->GetThread();
1005     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1006     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1007     // 1. Assert: array is any ECMAScript language value other than an Object with a [[TypedArrayName]] internal slot.
1008     // If it is such an Object, the definition in 22.2.3.22.2 applies.
1009     // 2. Let target be the this value.
1010     JSHandle<JSTaggedValue> target = GetThis(argv);
1011     // 3. If Type(target) is not Object, throw a TypeError exception.
1012     if (!target->IsECMAObject()) {
1013         THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
1014     }
1015     JSHandle<JSTypedArray> targetObj(target);
1016     // 4. If target does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
1017     if (!target->IsTypedArray()) {
1018         THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
1019                                     JSTaggedValue::Exception());
1020     }
1021 
1022     // 5. Assert: target has a [[ViewedArrayBuffer]] internal slot.
1023     // 6. Let targetOffset be ToInteger (offset).
1024     const JSHandle<JSTaggedValue> srcOffset = GetCallArg(argv, 1);
1025     uint64_t targetOffset = 0;
1026     if (srcOffset->IsInt()) {
1027         if (srcOffset->GetInt() < 0) {
1028             THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1029                                          JSTaggedValue::Exception());
1030         }
1031         targetOffset = static_cast<uint64_t>(srcOffset->GetInt());
1032     } else {
1033         JSTaggedNumber tTargetOffset = JSTaggedValue::ToInteger(thread, srcOffset);
1034         // 7. ReturnIfAbrupt(targetOffset).
1035         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1036         double rawTargetOffset = tTargetOffset.GetNumber();
1037         // 8. If targetOffset < 0, throw a RangeError exception.
1038         if (rawTargetOffset < 0) {
1039             THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.",
1040                                          JSTaggedValue::Exception());
1041         } else if (rawTargetOffset == base::POSITIVE_INFINITY) {
1042             THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset is infinty, which is greater than targetLength.",
1043                                          JSTaggedValue::Exception());
1044         } else {
1045             targetOffset = static_cast<uint64_t>(rawTargetOffset);
1046         }
1047     }
1048     // 9. Let targetBuffer be the value of target’s [[ViewedArrayBuffer]] internal slot.
1049     JSHandle<JSTaggedValue> targetBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, targetObj));
1050     // 10. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1051     if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1052         THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1053                                     JSTaggedValue::Exception());
1054     }
1055     // 11. Let targetLength be the value of target’s [[ArrayLength]] internal slot.
1056     // 12. Let targetName be the String value of target’s [[TypedArrayName]] internal slot.
1057     // 13. Let targetElementSize be the Number value of the Element Size value specified in Table 49 for targetName.
1058     // 14. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1059     // 15. Let targetByteOffset be the value of target’s [[ByteOffset]] internal slot.
1060     uint32_t targetLength = targetObj->GetArrayLength();
1061     DataViewType targetType = TypedArrayHelper::GetType(targetObj);
1062     uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType);
1063     uint32_t targetByteOffset = targetObj->GetByteOffset();
1064 
1065     JSHandle<JSTaggedValue> argArray = GetCallArg(argv, 0);
1066 
1067     // 22.2.3.22.1 %TypedArray%.prototype.set (array [ , offset ] )
1068     if (!argArray->IsTypedArray()) {
1069         if (argArray->IsStableJSArray(thread)) {
1070             uint32_t length = JSHandle<JSArray>::Cast(argArray)->GetArrayLength();
1071             JSHandle<TaggedArray> elements(thread, JSHandle<JSArray>::Cast(argArray)->GetElements());
1072             uint32_t elemLength = elements->GetLength();
1073             // Load On Demand check
1074             if (elemLength >= length) {
1075                 return JSStableArray::FastCopyFromArrayToTypedArray(thread, targetObj, targetType,
1076                                                                     targetOffset, length, elements);
1077             }
1078         }
1079         // 16. Let src be ToObject(array).
1080         JSHandle<JSObject> src = JSTaggedValue::ToObject(thread, argArray);
1081         // 17. ReturnIfAbrupt(src).
1082         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1083         // 18. Let srcLength be ToLength(Get(src, "length")).
1084         JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
1085         JSHandle<JSTaggedValue> lenResult(thread,
1086             ObjectFastOperator::FastGetPropertyByValue(thread,
1087                                                        JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(),
1088                                                        lengthKey.GetTaggedValue()));
1089         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1090         JSTaggedNumber tSrcLen = JSTaggedValue::ToLength(thread, lenResult);
1091         // 19. ReturnIfAbrupt(srcLength).
1092         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1093         uint64_t srcLen = static_cast<uint64_t>(tSrcLen.GetNumber());
1094         // 20. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1095         if (srcLen + targetOffset > targetLength) {
1096             THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1097                                          JSTaggedValue::Exception());
1098         }
1099         // 21. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1100         ASSERT((targetOffset * static_cast<uint64_t>(targetElementSize) +
1101             static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1102         uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset * targetElementSize + targetByteOffset);
1103         // 22. Let k be 0.
1104         // 23. Let limit be targetByteIndex + targetElementSize × srcLength.
1105         uint32_t k = 0;
1106         ASSERT((static_cast<uint64_t>(targetElementSize) * srcLen +
1107             static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1108         uint32_t limit = targetByteIndex + targetElementSize * srcLen;
1109         // 24. Repeat, while targetByteIndex < limit
1110         //   a. Let Pk be ToString(k).
1111         //   b. If target.[[ContentType]] is BigInt, set value to ? ToBigInt(value).
1112         //   c. Otherwise, set value to ? ToNumber(value).
1113         //   d. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
1114         //   e. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, kNumber).
1115         //   f. Set k to k + 1.
1116         //   g. Set targetByteIndex to targetByteIndex + targetElementSize.
1117         JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Hole());
1118         JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Hole());
1119         JSMutableHandle<JSTaggedValue> kNumberHandle(thread, JSTaggedValue::Hole());
1120         ContentType contentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1121         while (targetByteIndex < limit) {
1122             tKey.Update(JSTaggedValue(k));
1123             JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
1124             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1125             kValue.Update(ObjectFastOperator::FastGetPropertyByValue(
1126                 thread, JSHandle<JSTaggedValue>::Cast(src).GetTaggedValue(), kKey.GetTaggedValue()));
1127             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1128             if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) {
1129                 THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.",
1130                                             JSTaggedValue::Exception());
1131             }
1132             if (contentType == ContentType::BigInt) {
1133                 kNumberHandle.Update(JSTaggedValue::ToBigInt(thread, kValue));
1134             } else {
1135                 kNumberHandle.Update(JSTaggedValue::ToNumber(thread, kValue));
1136             }
1137             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1138             BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
1139                                                   targetType, kNumberHandle, true);
1140             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1141             k++;
1142             targetByteIndex = targetByteIndex + targetElementSize;
1143         }
1144         // 25. Return undefined.
1145         return JSTaggedValue::Undefined();
1146     }
1147 
1148     // 22.2.3.22.2 %TypedArray%.prototype.set(typedArray [, offset ] )
1149     JSHandle<JSTypedArray> typedArray(argArray);
1150     // 12. Let srcBuffer be the value of typedArray’s [[ViewedArrayBuffer]] internal slot.
1151     // 13. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1152     JSTaggedValue srcBuffer = typedArray->GetViewedArrayBufferOrByteArray();
1153     JSHandle<JSTaggedValue> srcBufferHandle(thread, srcBuffer);
1154     if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1155         THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of typedArray is detached buffer.",
1156                                     JSTaggedValue::Exception());
1157     }
1158 
1159     ContentType objContentType = JSHandle<JSTypedArray>::Cast(target)->GetContentType();
1160     ContentType argArrayContentType = JSHandle<JSTypedArray>::Cast(argArray)->GetContentType();
1161     if (argArrayContentType != objContentType) {
1162         THROW_TYPE_ERROR_AND_RETURN(thread,
1163                                     "argArrayContentType is not equal objContentType.",
1164                                     JSTaggedValue::Exception());
1165     }
1166     // 18. Let srcName be the String value of typedArray’s [[TypedArrayName]] internal slot.
1167     // 19. Let srcType be the String value of the Element Type value in Table 49 for srcName .
1168     // 20. Let srcElementSize be the Number value of the Element Size value specified in Table 49 for srcName.
1169     // 21. Let srcLength be the value of typedArray’s [[ArrayLength]] internal slot.
1170     // 22. Let srcByteOffset be the value of typedArray’s [[ByteOffset]] internal slot.
1171     JSHandle<JSTaggedValue> srcName(thread, typedArray->GetTypedArrayName());
1172     DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1173     uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType);
1174     uint32_t srcLength = typedArray->GetArrayLength();
1175     uint32_t srcByteOffset = typedArray->GetByteOffset();
1176     // 23. If srcLength + targetOffset > targetLength, throw a RangeError exception.
1177     if (srcLength + targetOffset > targetLength) {
1178         THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.",
1179                                      JSTaggedValue::Exception());
1180     }
1181     // 24. If SameValue(srcBuffer, targetBuffer) is true, then
1182     //   a. Let srcBuffer be CloneArrayBuffer(targetBuffer, srcByteOffset, %ArrayBuffer%).
1183     //   b. NOTE: %ArrayBuffer% is used to clone targetBuffer because is it known to not have any observable
1184     //      side-effects.
1185     //   c. ReturnIfAbrupt(srcBuffer).
1186     //   d. Let srcByteIndex be 0.
1187     // 25. Else, let srcByteIndex be srcByteOffset.
1188     uint32_t srcByteIndex = 0;
1189     if (JSTaggedValue::SameValue(srcBufferHandle.GetTaggedValue(), targetBuffer.GetTaggedValue())) {
1190         srcBuffer =
1191             BuiltinsArrayBuffer::CloneArrayBuffer(thread, targetBuffer, srcByteOffset, env->GetArrayBufferFunction());
1192         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1193         srcBufferHandle = JSHandle<JSTaggedValue>(thread, srcBuffer);
1194         srcByteIndex = 0;
1195     } else {
1196         srcByteIndex = srcByteOffset;
1197     }
1198     // 26. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
1199     ASSERT((targetOffset * static_cast<uint64_t>(targetElementSize) +
1200             static_cast<uint64_t>(targetByteOffset)) <= static_cast<uint64_t>(UINT32_MAX));
1201     uint32_t targetByteIndex = static_cast<uint32_t>(targetOffset) * targetElementSize + targetByteOffset;
1202     // 27. Let limit be targetByteIndex + targetElementSize × srcLength.
1203     ASSERT((static_cast<uint64_t>(targetElementSize) * static_cast<uint64_t>(srcLength) +
1204             static_cast<uint64_t>(targetByteIndex)) <= static_cast<uint64_t>(UINT32_MAX));
1205     uint32_t limit = targetByteIndex + targetElementSize * srcLength;
1206     uint32_t count = (limit - targetByteIndex) > 0 ? (limit - targetByteIndex) : 0;
1207     // 28. If SameValue(srcType, targetType) is false, then
1208     //   a. Repeat, while targetByteIndex < limit
1209     //     i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType).
1210     //     ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, targetType, value).
1211     //     iii. Set srcByteIndex to srcByteIndex + srcElementSize.
1212     //     iv. Set targetByteIndex to targetByteIndex + targetElementSize.
1213     JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
1214     if (srcType != targetType) {
1215         while (targetByteIndex < limit) {
1216             JSTaggedValue taggedData =
1217                 BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBufferHandle.GetTaggedValue(),
1218                                                         srcByteIndex, srcType, true);
1219             value.Update(taggedData);
1220             BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex,
1221                                                   targetType, value, true);
1222             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1223             srcByteIndex = srcByteIndex + srcElementSize;
1224             targetByteIndex = targetByteIndex + targetElementSize;
1225         }
1226     } else if (count > 0) {
1227         // 29. Else,
1228         //   a. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that preserves
1229         //   the bit-level encoding of the source data.
1230         //   b. Repeat, while targetByteIndex < limit
1231         //     i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1232         //     ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1233         //     iii. Set srcByteIndex to srcByteIndex + 1.
1234         //     iv. Set targetByteIndex to targetByteIndex + 1.
1235         void *srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBufferHandle.GetTaggedValue(), srcByteIndex);
1236         void *targetBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer.GetTaggedValue(), targetByteIndex);
1237         if (memcpy_s(targetBuf, srcLength * srcElementSize, srcBuf, srcLength * srcElementSize) != EOK) {
1238             LOG_FULL(FATAL) << "memcpy_s failed";
1239             UNREACHABLE();
1240         }
1241     }
1242     // 30. Return undefined.
1243     return JSTaggedValue::Undefined();
1244 }  // namespace panda::ecmascript::builtins
1245 
1246 // 22.2.3.23 %TypedArray%.prototype.slice ( start, end )
Slice(EcmaRuntimeCallInfo * argv)1247 JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv)
1248 {
1249     ASSERT(argv);
1250     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Slice);
1251     JSThread *thread = argv->GetThread();
1252     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1253     // 1. Let O be the this value.
1254     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1255     // 2. Let valid be ValidateTypedArray(O).
1256     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1257     // 3. ReturnIfAbrupt(valid).
1258     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1259 
1260     JSHandle<JSTypedArray> thisObj(thisHandle);
1261     // 4. Let len be the value of O’s [[ArrayLength]] internal slot.
1262     uint32_t len = thisObj->GetArrayLength();
1263 
1264     // 5. Let relativeStart be ToInteger(start).
1265     JSTaggedNumber tRelativeStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1266     // 6. ReturnIfAbrupt(relativeStart).
1267     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1268     double relativeStart = tRelativeStart.GetNumber();
1269     // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
1270 
1271     uint32_t k = relativeStart < 0 ?
1272                     std::max((static_cast<double>(len) + relativeStart), 0.0) :
1273                     std::min(relativeStart, static_cast<double>(len));
1274     // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
1275     double relativeEnd = len;
1276     JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1277     if (!end->IsUndefined()) {
1278         JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1279         // 9. ReturnIfAbrupt(relativeEnd).
1280         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1281         relativeEnd = tRelativeEnd.GetNumber();
1282     }
1283 
1284     // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
1285 
1286     uint32_t final = relativeEnd < 0 ?
1287                         std::max((static_cast<double>(len) + relativeEnd), 0.0) :
1288                         std::min(relativeEnd, static_cast<double>(len));
1289     // 11. Let count be max(final – k, 0).
1290     uint32_t count = final > k ? (final - k) : 0;
1291     // es11 9. Let A be ? TypedArraySpeciesCreate(O, « count »).
1292     JSTaggedType args[1] = {JSTaggedValue(count).GetRawData()};
1293     JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args);
1294     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1295     // 17. Let srcName be the String value of O’s [[TypedArrayName]] internal slot.
1296     // 18. Let srcType be the String value of the Element Type value in Table 49 for srcName.
1297     JSHandle<JSTaggedValue> srcName(thread, thisObj->GetTypedArrayName());
1298     DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
1299     // 19. Let targetName be the String value of A’s [[TypedArrayName]] internal slot.
1300     // 20. Let targetType be the String value of the Element Type value in Table 49 for targetName.
1301     JSHandle<JSTaggedValue> targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName());
1302     DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
1303     // 21. If SameValue(srcType, targetType) is false, then
1304     //   a. Let n be 0.
1305     //   b. Repeat, while k < final
1306     //     i. Let Pk be ToString(k).
1307     //     ii. Let kValue be Get(O, Pk).
1308     //     iii. ReturnIfAbrupt(kValue).
1309     //     iv. Let status be Set(A, ToString(n), kValue, true ).
1310     //     v. ReturnIfAbrupt(status).
1311     //     vi. Increase k by 1.
1312     //     vii. Increase n by 1.
1313     JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
1314     JSMutableHandle<JSTaggedValue> kValue(thread, JSTaggedValue::Undefined());
1315     JSMutableHandle<JSTaggedValue> ntKey(thread, JSTaggedValue::Undefined());
1316     if (srcType != targetType) {
1317         uint32_t n = 0;
1318         while (k < final) {
1319             tKey.Update(JSTaggedValue(k));
1320             kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(),
1321                                                                      tKey.GetTaggedValue()));
1322             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1323             ntKey.Update(JSTaggedValue(n));
1324             ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
1325                                                        ntKey.GetTaggedValue(), kValue.GetTaggedValue());
1326             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1327             n++;
1328             k++;
1329         }
1330     } else if (count > 0) {
1331         // 22. Else if count > 0,
1332         //   a. Let srcBuffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1333         //   b. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
1334         JSTaggedValue srcBuffer = thisObj->GetViewedArrayBufferOrByteArray();
1335         if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) {
1336             THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
1337                                         JSTaggedValue::Exception());
1338         }
1339         //   c. Let targetBuffer be the value of A’s [[ViewedArrayBuffer]] internal slot.
1340         JSTaggedValue targetBuffer = JSTypedArray::Cast(*newArrObj)->GetViewedArrayBufferOrByteArray();
1341         //   d. Let elementSize be the Number value of the Element Size value specified in Table 49 for srcType.
1342         uint32_t elementSize = TypedArrayHelper::GetSizeFromType(srcType);
1343         //   e. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that
1344         //   preserves the bit-level encoding of the source data. f. Let srcByteOffset be the value of O’s
1345         //   [[ByteOffset]] internal slot.
1346         uint32_t srcByteOffset = thisObj->GetByteOffset();
1347         //   g. Let targetByteIndex be 0.
1348         //   h. Let srcByteIndex be (k × elementSize) + srcByteOffset.
1349         uint32_t srcByteIndex = k * elementSize + srcByteOffset;
1350         //   i. Repeat, while targetByteIndex < count × elementSize
1351         //     i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8").
1352         //     ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value).
1353         //     iii. Increase srcByteIndex by 1.
1354         //     iv. Increase targetByteIndex by 1.
1355         void *srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBuffer, srcByteIndex);
1356         void *targetBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer);
1357         if (memcpy_s(targetBuf, count * elementSize, srcBuf, count * elementSize) != EOK) {
1358             LOG_FULL(FATAL) << "memcpy_s failed";
1359             UNREACHABLE();
1360         }
1361     }
1362     // 23. Return A.
1363     return newArrObj.GetTaggedValue();
1364 }
1365 
1366 // 22.2.3.24
Some(EcmaRuntimeCallInfo * argv)1367 JSTaggedValue BuiltinsTypedArray::Some(EcmaRuntimeCallInfo *argv)
1368 {
1369     ASSERT(argv);
1370     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Some);
1371     if (!GetThis(argv)->IsTypedArray()) {
1372         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1373     }
1374     return BuiltinsArray::Some(argv);
1375 }
1376 
1377 // 22.2.3.25
Sort(EcmaRuntimeCallInfo * argv)1378 JSTaggedValue BuiltinsTypedArray::Sort(EcmaRuntimeCallInfo *argv)
1379 {
1380     ASSERT(argv);
1381     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Sort);
1382     JSThread *thread = argv->GetThread();
1383     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1384 
1385     // 1. Let obj be ToObject(this value).
1386     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1387     if (!thisHandle->IsTypedArray()) {
1388         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1389     }
1390 
1391     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1392     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1393     JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
1394 
1395     JSHandle<JSTaggedValue> buffer;
1396     buffer = JSHandle<JSTaggedValue>(thread, TypedArrayHelper::ValidateTypedArray(thread, thisHandle));
1397     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1398     uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1399 
1400     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
1401     JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
1402     JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
1403     JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
1404     JSMutableHandle<JSTaggedValue> key1(thread, JSTaggedValue::Undefined());
1405     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1406     JSMutableHandle<JSTaggedValue> key2(thread, JSTaggedValue::Undefined());
1407     for (uint32_t i = 1; i < len; i++) {
1408         uint32_t beginIndex = 0;
1409         uint32_t endIndex = i;
1410         key.Update(JSTaggedValue(i));
1411         presentValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1412                                                                        key.GetTaggedValue()));
1413         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1414         while (beginIndex < endIndex) {
1415             uint32_t middleIndex = beginIndex + (endIndex - beginIndex) / 2;  // 2 : half
1416             key1.Update(JSTaggedValue(middleIndex));
1417             middleValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1418                                                                           key1.GetTaggedValue()));
1419             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1420             int32_t compareResult = TypedArrayHelper::SortCompare(thread, callbackFnHandle, buffer,
1421                                                                   middleValue, presentValue);
1422             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1423             compareResult > 0 ? (endIndex = middleIndex) : (beginIndex = middleIndex + 1);
1424         }
1425 
1426         if (endIndex < i) {
1427             for (uint32_t j = i; j > endIndex; j--) {
1428                 key2.Update(JSTaggedValue(j - 1));
1429                 previousValue.Update(
1430                     ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(),
1431                                                                key2.GetTaggedValue()));
1432                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1433                 ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
1434                                                            previousValue.GetTaggedValue());
1435                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1436             }
1437             ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
1438                                                        presentValue.GetTaggedValue());
1439             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1440         }
1441     }
1442     return thisObjHandle.GetTaggedValue();
1443 }
1444 
1445 // 22.2.3.26 %TypedArray%.prototype.subarray( [ begin [ , end ] ] )
Subarray(EcmaRuntimeCallInfo * argv)1446 JSTaggedValue BuiltinsTypedArray::Subarray(EcmaRuntimeCallInfo *argv)
1447 {
1448     ASSERT(argv);
1449     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Subarray);
1450     JSThread *thread = argv->GetThread();
1451     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1452     // 1. Let O be the this value.
1453     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1454     // 2. If Type(O) is not Object, throw a TypeError exception.
1455     if (!thisHandle->IsECMAObject()) {
1456         THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
1457     }
1458     JSHandle<JSTypedArray> thisObj(thisHandle);
1459     // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
1460     if (!thisHandle->IsTypedArray()) {
1461         THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
1462                                     JSTaggedValue::Exception());
1463     }
1464     // 4. Assert: O has a [[ViewedArrayBuffer]] internal slot.
1465     // 6. Let srcLength be the value of O’s [[ArrayLength]] internal slot.
1466     uint32_t srcLength = thisObj->GetArrayLength();
1467     // 7. Let relativeBegin be ToInteger(begin).
1468     JSTaggedNumber tRelativeBegin = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1469     // 8. ReturnIfAbrupt(relativeBegin).
1470     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1471     double relativeBegin = tRelativeBegin.GetNumber();
1472 
1473     uint32_t beginIndex = 0;
1474     // 9. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin), 0); else let beginIndex be
1475     // min(relativeBegin, srcLength).
1476     if (relativeBegin < 0) {
1477         double tempBeginIndex = relativeBegin + static_cast<double>(srcLength);
1478         beginIndex = tempBeginIndex > 0 ? static_cast<uint32_t>(tempBeginIndex) : 0;
1479     } else {
1480         beginIndex = relativeBegin < static_cast<double>(srcLength) ?
1481                         static_cast<uint32_t>(relativeBegin) : srcLength;
1482     }
1483 
1484     // 10. If end is undefined, let relativeEnd be srcLength; else, let relativeEnd be ToInteger(end).
1485     double relativeEnd = srcLength;
1486     JSHandle<JSTaggedValue> end = GetCallArg(argv, 1);
1487     if (!end->IsUndefined()) {
1488         JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end);
1489         // 11. ReturnIfAbrupt(relativeEnd).
1490         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1491         relativeEnd = tRelativeEnd.GetNumber();
1492     }
1493     // 12. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0); else let endIndex be
1494     // min(relativeEnd, srcLength).
1495     uint32_t endIndex;
1496     if (relativeEnd < 0) {
1497         double tempEndIndex = relativeEnd + static_cast<double>(srcLength);
1498         endIndex = tempEndIndex > 0 ? static_cast<uint32_t>(tempEndIndex) : 0;
1499     } else {
1500         endIndex = relativeEnd < static_cast<double>(srcLength) ?
1501                         static_cast<uint32_t>(relativeEnd) : srcLength;
1502     }
1503     // 13. Let newLength be max(endIndex – beginIndex, 0).
1504     uint32_t newLength = endIndex > beginIndex ? (endIndex - beginIndex) : 0;
1505     // 14. Let constructorName be the String value of O’s [[TypedArrayName]] internal slot.
1506     // 15. Let elementSize be the Number value of the Element Size value specified in Table 49 for constructorName.
1507     // 16. Let srcByteOffset be the value of O’s [[ByteOffset]] internal slot.
1508     // 17. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
1509     JSHandle<JSTaggedValue> constructorName(thread, thisObj->GetTypedArrayName());
1510     DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName);
1511     uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType);
1512     uint32_t srcByteOffset = thisObj->GetByteOffset();
1513     ASSERT((static_cast<uint64_t>(srcByteOffset) + static_cast<uint64_t>(beginIndex) *
1514             static_cast<uint64_t>(elementSize)) <= static_cast<uint64_t>(UINT32_MAX));
1515     uint32_t beginByteOffset = srcByteOffset + beginIndex * elementSize;
1516     JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, thisObj);
1517     // 21. Let argumentsList be «buffer, beginByteOffset, newLength».
1518     // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
1519     // 22. Return Construct(constructor, argumentsList).
1520     const uint32_t argsLength = 3;
1521     JSTaggedType args[argsLength] = {
1522         buffer.GetRawData(),
1523         JSTaggedValue(beginByteOffset).GetRawData(),
1524         JSTaggedValue(newLength).GetRawData()
1525     };
1526     JSHandle<JSObject> newArr = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, argsLength, args);
1527     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1528     return newArr.GetTaggedValue();
1529 }
1530 
1531 // 22.2.3.27
ToLocaleString(EcmaRuntimeCallInfo * argv)1532 JSTaggedValue BuiltinsTypedArray::ToLocaleString(EcmaRuntimeCallInfo *argv)
1533 {
1534     ASSERT(argv);
1535     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ToLocaleString);
1536     if (!GetThis(argv)->IsTypedArray()) {
1537         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1538     }
1539     return BuiltinsArray::ToLocaleString(argv);
1540 }
1541 
1542 // 22.2.3.28
ToString(EcmaRuntimeCallInfo * argv)1543 JSTaggedValue BuiltinsTypedArray::ToString(EcmaRuntimeCallInfo *argv)
1544 {
1545     ASSERT(argv);
1546     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ToString);
1547     if (!GetThis(argv)->IsTypedArray()) {
1548         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1549     }
1550     return BuiltinsArray::ToString(argv);
1551 }
1552 
1553 // 22.2.3.29
Values(EcmaRuntimeCallInfo * argv)1554 JSTaggedValue BuiltinsTypedArray::Values(EcmaRuntimeCallInfo *argv)
1555 {
1556     ASSERT(argv);
1557     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Values);
1558     JSThread *thread = argv->GetThread();
1559     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1560     // 1. Let O be the this value.
1561     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1562     // 2. Let valid be ValidateTypedArray(O).
1563     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1564     // 3. ReturnIfAbrupt(valid).
1565     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread());
1566     JSHandle<JSObject> self(thisHandle);
1567     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1568     // 4. Return CreateArrayIterator(O, "value").
1569     JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(self, IterationKind::VALUE));
1570     return iter.GetTaggedValue();
1571 }
1572 
1573 // 22.2.3.31
ToStringTag(EcmaRuntimeCallInfo * argv)1574 JSTaggedValue BuiltinsTypedArray::ToStringTag(EcmaRuntimeCallInfo *argv)
1575 {
1576     ASSERT(argv);
1577     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ToStringTag);
1578     JSThread *thread = argv->GetThread();
1579     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1580     // 1. Let O be the this value.
1581     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1582     // 2. If Type(O) is not Object, return undefined.
1583     if (!thisHandle->IsECMAObject()) {
1584         return JSTaggedValue::Undefined();
1585     }
1586     // 3. If O does not have a [[TypedArrayName]] internal slot, return undefined.
1587     if (!thisHandle->IsTypedArray()) {
1588         return JSTaggedValue::Undefined();
1589     }
1590     // 4. Let name be the value of O’s [[TypedArrayName]] internal slot.
1591     JSTaggedValue name = JSHandle<JSTypedArray>::Cast(thisHandle)->GetTypedArrayName();
1592     // 5. Assert: name is a String value.
1593     ASSERT(name.IsString());
1594     // 6. Return name.
1595     return name;
1596 }
1597 
1598 // 23.2.3.1
At(EcmaRuntimeCallInfo * argv)1599 JSTaggedValue BuiltinsTypedArray::At(EcmaRuntimeCallInfo *argv)
1600 {
1601     ASSERT(argv);
1602     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, At);
1603     JSThread *thread = argv->GetThread();
1604     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1605 
1606     // 1. Let O be ToObject(this value).
1607     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1608     // 2. Perform ? ValidateTypedArray(O).
1609     if (!thisHandle->IsTypedArray()) {
1610         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1611     }
1612     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1613     // ReturnIfAbrupt(O).
1614     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1615 
1616     // 3. Let len be O.[[ArrayLength]].
1617     uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1618     // ReturnIfAbrupt(len).
1619     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1620 
1621     // 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
1622     JSTaggedNumber indexVal = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1623     // ReturnIfAbrupt(indexVal).
1624     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1625     int64_t relativeIndex = indexVal.GetNumber();
1626     int64_t k = 0;
1627     // 5. If relativeIndex ≥ 0, then Let k be relativeIndex.
1628     // 6. Else, Let k be len + relativeIndex.
1629     k = relativeIndex >= 0 ? relativeIndex : static_cast<int64_t>(len) + relativeIndex;
1630     // 7. If k < 0 or k ≥ len, return undefined.
1631     if (k < 0 || k >= len) {
1632         return JSTaggedValue::Undefined();
1633     }
1634     // 8. Return ! Get(O, ! ToString(��(k))).
1635     JSHandle<JSTaggedValue> kValue = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue();
1636     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1637     return kValue.GetTaggedValue();
1638 }
1639 
1640 // 23.2.3.33
ToSorted(EcmaRuntimeCallInfo * argv)1641 JSTaggedValue BuiltinsTypedArray::ToSorted(EcmaRuntimeCallInfo* argv)
1642 {
1643     ASSERT(argv);
1644     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, ToSorted);
1645     JSThread* thread = argv->GetThread();
1646     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1647 
1648     // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
1649     JSHandle<JSTaggedValue> comparefnHandle = GetCallArg(argv, 0);
1650     if (!comparefnHandle->IsUndefined() && !comparefnHandle->IsCallable()) {
1651         THROW_TYPE_ERROR_AND_RETURN(thread, "the comparefn is not callable.", JSTaggedValue::Exception());
1652     }
1653     // 2. Let O be the this value.
1654     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1655     // 3. Perform ? ValidateTypedArray(O).
1656     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1657     // ReturnIfAbrupt(valid).
1658     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1659 
1660     JSHandle<JSTypedArray> thisObj(thisHandle);
1661     // 4. Let len be O.[[ArrayLength]].
1662     uint32_t len = thisObj->GetArrayLength();
1663 
1664     // 5. Let A be ? TypedArrayCreateSameType(O, « ��(len) »).
1665     JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
1666     JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArrayCreateSameType(thread, thisObj, 1, args); // 1: one arg.
1667     // ReturnIfAbrupt(A).
1668     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1669 
1670     JSHandle<JSTaggedValue> buffer =
1671         JSHandle<JSTaggedValue>(thread, TypedArrayHelper::ValidateTypedArray(thread, thisHandle));
1672     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1673 
1674     JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
1675     JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
1676     JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
1677     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
1678     JSMutableHandle<JSTaggedValue> key1(thread, JSTaggedValue::Undefined());
1679     JSMutableHandle<JSTaggedValue> key2(thread, JSTaggedValue::Undefined());
1680     if (len > 0) {
1681         previousValue.Update(
1682             ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), JSTaggedValue(0)));
1683         ObjectFastOperator::FastSetPropertyByIndex(
1684             thread, newArrObj.GetTaggedValue(), 0, previousValue.GetTaggedValue());
1685     }
1686     for (uint32_t i = 1; i < len; i++) {
1687         uint32_t beginIndex = 0;
1688         uint32_t endIndex = i;
1689         key.Update(JSTaggedValue(i));
1690         presentValue.Update(
1691             ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), key.GetTaggedValue()));
1692         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1693         while (beginIndex < endIndex) {
1694             uint32_t middleIndex = beginIndex + (endIndex - beginIndex) / 2; // 2 : half
1695             key1.Update(JSTaggedValue(middleIndex));
1696             middleValue.Update(
1697                 ObjectFastOperator::FastGetPropertyByValue(thread, newArrObj.GetTaggedValue(), key1.GetTaggedValue()));
1698             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1699             int32_t compareResult =
1700                 TypedArrayHelper::SortCompare(thread, comparefnHandle, buffer, middleValue, presentValue);
1701             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1702             compareResult > 0 ? (endIndex = middleIndex) : (beginIndex = middleIndex + 1);
1703         }
1704 
1705         if (endIndex < i) {
1706             for (uint32_t j = i; j > endIndex; j--) {
1707                 key2.Update(JSTaggedValue(j - 1));
1708                 previousValue.Update(ObjectFastOperator::FastGetPropertyByValue(
1709                     thread, newArrObj.GetTaggedValue(), key2.GetTaggedValue()));
1710                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1711                 ObjectFastOperator::FastSetPropertyByIndex(
1712                     thread, newArrObj.GetTaggedValue(), j, previousValue.GetTaggedValue());
1713                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1714             }
1715         }
1716         ObjectFastOperator::FastSetPropertyByIndex(
1717             thread, newArrObj.GetTaggedValue(), endIndex, presentValue.GetTaggedValue());
1718         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1719     }
1720     return newArrObj.GetTaggedValue();
1721 }
1722 
1723 // 23.2.3.36
With(EcmaRuntimeCallInfo * argv)1724 JSTaggedValue BuiltinsTypedArray::With(EcmaRuntimeCallInfo* argv)
1725 {
1726     ASSERT(argv);
1727     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, With);
1728     JSThread* thread = argv->GetThread();
1729     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1730 
1731     // 1. Let O be the this value.
1732     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1733     // 2. Perform ? ValidateTypedArray(O).
1734     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1735     // ReturnIfAbrupt(valid).
1736     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1737 
1738     JSHandle<JSTypedArray> thisObj(thisHandle);
1739     // 3. Let len be O.[[ArrayLength]].
1740     uint32_t len = thisObj->GetArrayLength();
1741 
1742     // 4. Let relativeIndex be ? ToIntegerOrInfinity(index).
1743     JSTaggedNumber indexVal = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0));
1744     // ReturnIfAbrupt(indexVal).
1745     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1746     int64_t relativeIndex = indexVal.GetNumber();
1747     // 5. If relativeIndex ≥ 0, let actualIndex be relativeIndex.
1748     // 6. Else, let actualIndex be len + relativeIndex.
1749     int64_t actualIndex = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
1750 
1751     // 7. If O.[[ContentType]] is BigInt, let numericValue be ? ToBigInt(value).
1752     // 8. Else, let numericValue be ? ToNumber(value).
1753     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
1754     ContentType contentType = thisObj->GetContentType();
1755     JSHandle<JSTaggedValue> numericValue;
1756     if (contentType == ContentType::BigInt) {
1757         numericValue = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, value));
1758     } else {
1759         numericValue = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToNumber(thread, value));
1760     }
1761     // ReturnIfAbrupt(numericValue).
1762     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1763 
1764     // 9. If IsValidIntegerIndex(O, ��(actualIndex)) is false, throw a RangeError exception.
1765     if (!JSTypedArray::IsValidIntegerIndex(thisHandle, JSTaggedValue(actualIndex))) {
1766         THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid typed array index", JSTaggedValue::Exception());
1767     }
1768 
1769     // 10. Let A be ? TypedArrayCreateSameType(O, « ��(len) »).
1770     JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() };
1771     JSHandle<JSObject> newArrObj = TypedArrayHelper::TypedArrayCreateSameType(thread, thisObj, 1, args); // 1: one arg.
1772     // ReturnIfAbrupt(A).
1773     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1774 
1775     // 11. Let k be 0.
1776     // 12. Repeat, while k < len,
1777     //     a. Let Pk be ! ToString(��(k)).
1778     //     b. If k is actualIndex, let fromValue be numericValue.
1779     //     c. Else, let fromValue be ! Get(O, Pk).
1780     //     d. Perform ! Set(A, Pk, fromValue, true).
1781     //     e. Set k to k + 1.
1782     JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
1783     JSMutableHandle<JSTaggedValue> fromValue(thread, JSTaggedValue::Undefined());
1784     uint32_t k = 0;
1785     while (k < len) {
1786         tKey.Update(JSTaggedValue(k));
1787         if (k == actualIndex) {
1788             fromValue.Update(numericValue);
1789         } else {
1790             fromValue.Update(
1791                 ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), tKey.GetTaggedValue()));
1792             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1793         }
1794         ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(),
1795             tKey.GetTaggedValue(), fromValue.GetTaggedValue());
1796         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1797         k++;
1798     }
1799     return newArrObj.GetTaggedValue();
1800 }
1801 
1802 // es12 23.2.3.13
Includes(EcmaRuntimeCallInfo * argv)1803 JSTaggedValue BuiltinsTypedArray::Includes(EcmaRuntimeCallInfo *argv)
1804 {
1805     ASSERT(argv);
1806     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, Includes);
1807     if (!GetThis(argv)->IsTypedArray()) {
1808         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1809     }
1810     return BuiltinsArray::Includes(argv);
1811 }
1812 
1813 // 23.2.3.32
ToReversed(EcmaRuntimeCallInfo * argv)1814 JSTaggedValue BuiltinsTypedArray::ToReversed(EcmaRuntimeCallInfo *argv)
1815 {
1816     ASSERT(argv);
1817     JSThread *thread = argv->GetThread();
1818     BUILTINS_API_TRACE(thread, TypedArray, ToReversed);
1819     [[maybe_unused]] EcmaHandleScope handleScope(thread);
1820 
1821     // 1. Let O be ToObject(this value).
1822     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
1823     JSHandle<JSTypedArray> thisObj(thisHandle);
1824     // 2. Perform ? ValidateTypedArray(O).
1825     TypedArrayHelper::ValidateTypedArray(thread, thisHandle);
1826     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1827     JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
1828     // ReturnIfAbrupt(O).
1829     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1830     // 3. Let len be O.[[ArrayLength]].
1831     uint32_t len = JSHandle<JSTypedArray>::Cast(thisObjHandle)->GetArrayLength();
1832     // ReturnIfAbrupt(len).
1833     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1834     // 4. Let A be ? TypedArrayCreateSameType(O, « ��(length) »).
1835     JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()};
1836     JSHandle<JSObject> newArrayHandle = TypedArrayHelper::TypedArrayCreateSameType(thread, thisObj, 1, args);
1837     // ReturnIfAbrupt(newObj).
1838     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1839     // 5. Let k be 0.
1840     uint32_t k = 0;
1841 
1842     // 6. Repeat, while k < length,
1843     //     a. Let from be ! ToString(��(length - k - 1)).
1844     //     b. Let Pk be ! ToString(��(k)).
1845     //     c. Let fromValue be ! Get(O, from).
1846     //     d. Perform ! Set(A, Pk, fromValue, true).
1847     //     e. Set k to k + 1.
1848     while (k < len) {
1849         uint32_t from = len - k - 1;
1850         JSHandle<JSTaggedValue> fromValue = JSTypedArray::GetProperty(thread, thisHandle, from).GetValue();
1851         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1852         ObjectFastOperator::FastSetPropertyByIndex(thread, newArrayHandle.GetTaggedValue(), k,
1853                                                    fromValue.GetTaggedValue());
1854         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1855         ++k;
1856     }
1857     // 7. Return A.
1858     return newArrayHandle.GetTaggedValue();
1859 }
1860 
1861 // 23.2.3.13
FindLast(EcmaRuntimeCallInfo * argv)1862 JSTaggedValue BuiltinsTypedArray::FindLast(EcmaRuntimeCallInfo *argv)
1863 {
1864     ASSERT(argv);
1865     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, FindLast);
1866     if (!GetThis(argv)->IsTypedArray()) {
1867         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1868     }
1869     return BuiltinsArray::FindLast(argv);
1870 }
1871 
1872 // 23.2.3.14
FindLastIndex(EcmaRuntimeCallInfo * argv)1873 JSTaggedValue BuiltinsTypedArray::FindLastIndex(EcmaRuntimeCallInfo *argv)
1874 {
1875     ASSERT(argv);
1876     BUILTINS_API_TRACE(argv->GetThread(), TypedArray, FindLastIndex);
1877     if (!GetThis(argv)->IsTypedArray()) {
1878         THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
1879     }
1880     return BuiltinsArray::FindLastIndex(argv);
1881 }
1882 }  // namespace panda::ecmascript::builtins
1883