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