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