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