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