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