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/js_typed_array.h"
17
18 #include "ecmascript/accessor_data.h"
19 #include "ecmascript/base/typed_array_helper-inl.h"
20 #include "ecmascript/builtins/builtins_arraybuffer.h"
21
22 namespace panda::ecmascript {
23 using TypedArrayHelper = base::TypedArrayHelper;
24 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
25
ToPropKey(JSThread * thread,const JSHandle<JSTaggedValue> & key)26 JSHandle<JSTaggedValue> JSTypedArray::ToPropKey(JSThread *thread, const JSHandle<JSTaggedValue> &key)
27 {
28 if (key->IsSymbol()) {
29 return key;
30 }
31 return JSHandle<JSTaggedValue>(JSTaggedValue::ToString(thread, key));
32 }
33 // 9.4.5.1 [[GetOwnProperty]] ( P )
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)34 bool JSTypedArray::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
35 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
36 {
37 // 1. Assert : IsPropertyKey(P) is true.
38 ASSERT(JSTaggedValue::IsPropertyKey(key));
39 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
40 // 3. If Type(P) is String, then
41 // a. Let numericIndex be CanonicalNumericIndexString(P).
42 // b. Assert: numericIndex is not an abrupt completion.
43 // c. If numericIndex is not undefined, then
44 // i. Let value be IntegerIndexedElementGet (O, numericIndex).
45 // ii. ReturnIfAbrupt(value).
46 // iii. If value is undefined, return undefined.
47 // iv. Return a PropertyDescriptor{ [[Value]]: value, [[Enumerable]]: true, [[Writable]]: true,
48 // [[Configurable]]: false }.
49 if (key->IsString() || key->IsNumber()) {
50 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
51 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
52 if (!numericIndex.IsUndefined()) {
53 JSHandle<JSTaggedValue> value =
54 JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex).GetValue();
55 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
56 if (value->IsUndefined()) {
57 return false;
58 }
59 desc.SetValue(value);
60 desc.SetEnumerable(true);
61 desc.SetWritable(true);
62 desc.SetConfigurable(true);
63 return true;
64 }
65 }
66 // 4. Return OrdinaryGetOwnProperty(O, P).
67 return JSObject::OrdinaryGetOwnProperty(thread, JSHandle<JSObject>(typedarray), key, desc);
68 }
69
70 // 9.4.5.2 [[HasProperty]] ( P )
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key)71 bool JSTypedArray::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
72 const JSHandle<JSTaggedValue> &key)
73 {
74 // 1. Assert: IsPropertyKey(P) is true.
75 ASSERT(JSTaggedValue::IsPropertyKey(key));
76 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
77 // 3. If Type(P) is String, then
78 // a. Let numericIndex be CanonicalNumericIndexString(P).
79 // b. Assert: numericIndex is not an abrupt completion.
80 // c. If numericIndex is not undefined, then
81 // i. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
82 // ii. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
83 // iii. If IsInteger(numericIndex) is false, return false
84 // iv. If numericIndex = −0, return false.
85 // v. If numericIndex < 0, return false.
86 // vi. If numericIndex ≥ the value of O’s [[ArrayLength]] internal slot, return false.
87 // vii. Return true.
88 JSHandle<JSTypedArray> typedarrayObj(typedarray);
89 if (key->IsString() || key->IsNumber()) {
90 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
91 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
92 if (!numericIndex.IsUndefined()) {
93 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
94 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
95 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
96 }
97 if (!numericIndex.IsInteger()) {
98 return false;
99 }
100 JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
101 JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
102 double tNegZero = -0.0;
103 auto eZero = JSTaggedNumber(tNegZero);
104 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
105 if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
106 return false;
107 }
108
109 if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
110 return false;
111 }
112 uint32_t arrLen = typedarrayObj->GetArrayLength();
113 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
114 return JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle);
115 }
116 }
117 // 4. Return OrdinaryHasProperty(O, P).
118 PropertyDescriptor desc(thread);
119 if (JSObject::OrdinaryGetOwnProperty(thread, JSHandle<JSObject>::Cast(typedarrayObj), key, desc)) {
120 return true;
121 }
122 JSTaggedValue parent = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>::Cast(typedarrayObj));
123 if (!parent.IsNull()) {
124 return JSTaggedValue::HasProperty(thread, JSHandle<JSTaggedValue>(thread, parent), key);
125 }
126 return false;
127 }
128
129 // 9.4.5.3 [[DefineOwnProperty]] ( P, Desc )
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)130 bool JSTypedArray::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
131 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
132 {
133 // 1. Assert: IsPropertyKey(P) is true.
134 ASSERT(JSTaggedValue::IsPropertyKey(key));
135 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
136 // 3. If Type(P) is String, then
137 // a. Let numericIndex be CanonicalNumericIndexString (P).
138 // b. Assert: numericIndex is not an abrupt completion.
139 // c. If numericIndex is not undefined, then
140 JSHandle<JSTypedArray> typedarrayObj(typedarray);
141 if (key->IsString() || key->IsNumber()) {
142 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
143 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
144 if (!numericIndex.IsUndefined()) {
145 // i. If IsInteger(numericIndex) is false, return false
146 // ii. Let intIndex be numericIndex.
147 // iii. If intIndex = −0, return false.
148 // iv. If intIndex < 0, return false.
149 // v. Let length be the value of O’s [[ArrayLength]] internal slot.
150 // vi. If intIndex ≥ length, return false.
151 // vii. If IsAccessorDescriptor(Desc) is true, return false.
152 // viii. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is true, return false.
153 // ix. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
154 // x. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false.
155 // xi. If Desc has a [[Value]] field, then
156 // 1. Let value be Desc.[[Value]].
157 // 2. Return IntegerIndexedElementSet (O, intIndex, value).
158 // xii. Return true.
159 if (!numericIndex.IsInteger()) {
160 return false;
161 }
162 JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
163 JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
164 double tNegZero = -0.0;
165 auto eZero = JSTaggedNumber(tNegZero);
166 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
167 if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
168 return false;
169 }
170 if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
171 return false;
172 }
173 uint32_t arrLen = typedarrayObj->GetArrayLength();
174 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
175 if (!JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle)) {
176 return false;
177 }
178 if (desc.IsAccessorDescriptor()) {
179 return false;
180 }
181 if (desc.HasConfigurable() && !desc.IsConfigurable()) {
182 return false;
183 }
184 if (desc.HasEnumerable() && !desc.IsEnumerable()) {
185 return false;
186 }
187 if (desc.HasWritable() && !desc.IsWritable()) {
188 return false;
189 }
190 if (desc.HasValue()) {
191 JSHandle<JSTaggedValue> value = desc.GetValue();
192 return (JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value));
193 }
194 return true;
195 }
196 }
197 // 4. Return OrdinaryDefineOwnProperty(O, P, Desc).
198 return JSObject::OrdinaryDefineOwnProperty(thread, JSHandle<JSObject>::Cast(typedarrayObj), key, desc);
199 }
200
201 // 9.4.5.4 [[Get]] ( P, Receiver )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)202 OperationResult JSTypedArray::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
203 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
204 {
205 // 1. Assert : IsPropertyKey(P) is true.
206 ASSERT(JSTaggedValue::IsPropertyKey(key));
207 // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
208 if ((key->IsString() || key->IsNumber()) && JSTaggedValue::SameValue(typedarray, receiver)) {
209 // a. Let numericIndex be CanonicalNumericIndexString (P).
210 // b. Assert: numericIndex is not an abrupt completion.
211 // c. If numericIndex is not undefined, then
212 // i. Return IntegerIndexedElementGet (O, numericIndex).
213 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
214 RETURN_VALUE_IF_ABRUPT_COMPLETION(
215 thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
216 if (!numericIndex.IsUndefined()) {
217 return JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex);
218 }
219 }
220
221 // 3. Return the result of calling the default ordinary object [[Get]] internal method (9.1.8) on O
222 // passing P and Receiver as arguments.
223 return JSObject::GetProperty(thread, typedarray, key, receiver);
224 }
225
226 // 9.4.5.5 [[Set]] ( P, V, Receiver )
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)227 bool JSTypedArray::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
228 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
229 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
230 {
231 // 1. Assert : IsPropertyKey(P) is true.
232 ASSERT(JSTaggedValue::IsPropertyKey(key));
233 // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
234 if ((key->IsString() || key->IsNumber()) && JSTaggedValue::SameValue(typedarray, receiver)) {
235 // a. Let numericIndex be CanonicalNumericIndexString (P).
236 // b. Assert: numericIndex is not an abrupt completion.
237 // c. If numericIndex is not undefined, then
238 // i. Return IntegerIndexedElementSet (O, numericIndex, V).
239 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
240 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
241 if (!numericIndex.IsUndefined()) {
242 return JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value);
243 }
244 }
245 // 3. Return the result of calling the default ordinary object [[Set]] internal method (9.1.8) on O passing
246 // P, V, and Receiver as arguments.
247 return JSObject::SetProperty(thread, typedarray, key, value, receiver, mayThrow);
248 }
249
250 // s12 10.4.5.6 [[Delete]] ( P )
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key)251 bool JSTypedArray::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
252 const JSHandle<JSTaggedValue> &key)
253 {
254 // 1. Assert: IsPropertyKey(P) is true.
255 // 2. Assert: O is an Integer-Indexed exotic object.
256 ASSERT(JSTaggedValue::IsPropertyKey(key));
257 // 3. If Type(P) is String, then
258 // a. Let numericIndex be CanonicalNumericIndexString(P).
259 // b. If numericIndex is not undefined, then
260 // i. If IsValidIntegerIndex(O, numericIndex) is false, return true; else return false.
261 if (key->IsString() || key->IsNumber()) {
262 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
263 if (!numericIndex.IsUndefined()) {
264 if (!IsValidIntegerIndex(typedarray, numericIndex)) {
265 return true;
266 }
267 return false;
268 }
269 }
270 // 4. Return ? OrdinaryDelete(O, P).
271 return JSObject::DeleteProperty(thread, JSHandle<JSObject>(typedarray), key);
272 }
273
274 // 9.4.5.6 [[OwnPropertyKeys]] ( )
OwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray)275 JSHandle<TaggedArray> JSTypedArray::OwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray)
276 {
277 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
278 // 1. Let keys be a new empty List.
279 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
280 // [[TypedArrayName]] internal slots.
281 // 3. Let len be the value of O’s [[ArrayLength]] internal slot.
282 JSHandle<JSTypedArray> arrayObj(typedarray);
283 JSHandle<TaggedArray> objKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>::Cast(arrayObj));
284 uint32_t objKeysLen = objKeys->GetLength();
285 uint32_t bufferKeysLen = arrayObj->GetArrayLength();
286 uint32_t length = objKeysLen + bufferKeysLen;
287 JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
288
289 // 4. For each integer i starting with 0 such that i < len, in ascending order,
290 // a. Add ToString(i) as the last element of keys.
291 uint32_t copyLength = 0;
292 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
293 for (uint32_t k = 0; k < bufferKeysLen; k++) {
294 tKey.Update(JSTaggedValue(k));
295 JSHandle<JSTaggedValue> sKey(JSTaggedValue::ToString(thread, tKey));
296 nameList->Set(thread, copyLength, sKey.GetTaggedValue());
297 copyLength++;
298 }
299
300 // 5. For each own property key P of O such that Type(P) is String and P is not an integer index, in
301 // property creation order
302 // a. Add P as the last element of keys.
303 for (uint32_t i = 0; i < objKeysLen; i++) {
304 JSTaggedValue key = objKeys->Get(i);
305 if (JSTaggedValue(key).IsString()) {
306 nameList->Set(thread, copyLength, key);
307 copyLength++;
308 }
309 }
310
311 // 6. For each own property key P of O such that Type(P) is Symbol, in property creation order
312 // a. Add P as the last element of keys.
313 for (uint32_t i = 0; i < objKeysLen; i++) {
314 JSTaggedValue key = objKeys->Get(i);
315 if (JSTaggedValue(key).IsSymbol()) {
316 nameList->Set(thread, copyLength, key);
317 copyLength++;
318 }
319 }
320
321 // 7. Return keys.
322 return factory->CopyArray(nameList, length, copyLength);
323 }
324
325 // 9.4.5.7 IntegerIndexedObjectCreate (prototype, internalSlotsList)
326
327 // 9.4.5.8 IntegerIndexedElementGet ( O, index )
IntegerIndexedElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index)328 OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
329 JSTaggedValue index)
330 {
331 // 1. Assert: Type(index) is Number.
332 ASSERT(index.IsNumber());
333 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
334 // [[TypedArrayName]] internal slots.
335 ASSERT(typedarray->IsTypedArray());
336 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
337 JSHandle<JSTypedArray> typedarrayObj(typedarray);
338 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
339 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
340 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
341 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
342 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
343 }
344 // 5. If IsInteger(index) is false, return undefined
345 if (!index.IsInteger()) {
346 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
347 }
348
349 // 6. If index = −0, return undefined.
350 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
351 // 8. If index < 0 or index ≥ length, return undefined.
352 JSHandle<JSTaggedValue> indexHandle(thread, index);
353 JSTaggedNumber indexNumber = JSTaggedValue::ToNumber(thread, indexHandle);
354 double tNegZero = -0.0;
355 auto eZero = JSTaggedNumber(tNegZero);
356 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
357 if (JSTaggedNumber::SameValue(indexNumber, eZero)) {
358 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
359 }
360 uint32_t arrLen = typedarrayObj->GetArrayLength();
361 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
362 if (JSTaggedValue::Less(thread, indexHandle, zero) || !JSTaggedValue::Less(thread, indexHandle, arrLenHandle)) {
363 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
364 }
365 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
366 uint32_t offset = typedarrayObj->GetByteOffset();
367 // 10. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
368 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for
369 // arrayTypeName.
370 uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
371 // 12. Let indexedPosition = (index × elementSize) + offset.
372 uint32_t k = static_cast<uint32_t>(JSTaggedValue::ToInteger(thread, indexHandle).ToInt32());
373 uint32_t byteIndex = k * elementSize + offset;
374 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
375 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
376 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
377 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
378 return OperationResult(thread, result, PropertyMetaData(true));
379 }
380
381 // s12 10.4.5.9 IsValidIntegerIndex ( O, index )
IsValidIntegerIndex(const JSHandle<JSTaggedValue> & typedArray,JSTaggedValue index)382 bool JSTypedArray::IsValidIntegerIndex(const JSHandle<JSTaggedValue> &typedArray, JSTaggedValue index)
383 {
384 // 1. Assert: O is an Integer-Indexed exotic object.
385 // 2. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
386 JSHandle<JSTypedArray> typedarrayObj(typedArray);
387 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
388 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
389 return false;
390 }
391 // 3. If ! IsIntegralNumber(index) is false, return false.
392 if (!index.IsInteger()) {
393 return false;
394 }
395 // 4. If index is -0, return false.
396 double val = index.GetNumber();
397 if (val == 0 && std::signbit(val)) {
398 return false;
399 }
400
401 uint32_t arrLen = typedarrayObj->GetArrayLength();
402 // 5. If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
403 if (val < 0 || val >= arrLen) {
404 return false;
405 }
406 // 6. Return true.
407 return true;
408 }
409
GetTypeFromName(JSThread * thread,const JSHandle<JSTaggedValue> & typeName)410 DataViewType JSTypedArray::GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName)
411 {
412 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
413 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) {
414 return DataViewType::FLOAT32;
415 }
416 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt8ArrayString())) {
417 return DataViewType::INT8;
418 }
419 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ArrayString())) {
420 return DataViewType::UINT8;
421 }
422 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ClampedArrayString())) {
423 return DataViewType::UINT8_CLAMPED;
424 }
425 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt16ArrayString())) {
426 return DataViewType::INT16;
427 }
428 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint16ArrayString())) {
429 return DataViewType::UINT16;
430 }
431 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt32ArrayString())) {
432 return DataViewType::INT32;
433 }
434 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint32ArrayString())) {
435 return DataViewType::UINT32;
436 }
437 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) {
438 return DataViewType::FLOAT64;
439 }
440 if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) {
441 return DataViewType::BIGINT64;
442 }
443 return DataViewType::BIGUINT64;
444 }
445
446 // static
FastCopyElementToArray(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<TaggedArray> & array)447 bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
448 JSHandle<TaggedArray> &array)
449 {
450 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
451 // [[TypedArrayName]] internal slots.
452 ASSERT(typedArray->IsTypedArray());
453 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
454 JSHandle<JSTypedArray> typedarrayObj(typedArray);
455 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
456 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
457 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
458 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
459 }
460
461 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
462 // 8. If index < 0 or index ≥ length, return undefined.
463 uint32_t arrLen = typedarrayObj->GetArrayLength();
464
465 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
466 uint32_t offset = typedarrayObj->GetByteOffset();
467 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
468 uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
469 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
470 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
471 for (uint32_t index = 0; index < arrLen; index++) {
472 // 12. Let indexedPosition = (index × elementSize) + offset.
473 uint32_t byteIndex = index * elementSize + offset;
474 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
475 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
476 array->Set(thread, index, result);
477 }
478 return true;
479 }
480
481 // static
FastElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,uint32_t index)482 OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
483 uint32_t index)
484 {
485 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
486 // [[TypedArrayName]] internal slots.
487 ASSERT(typedarray->IsTypedArray());
488 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
489 JSHandle<JSTypedArray> typedarrayObj(typedarray);
490 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
491 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
492 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
493 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
494 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
495 }
496
497 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
498 // 8. If index < 0 or index ≥ length, return undefined.
499 uint32_t arrLen = typedarrayObj->GetArrayLength();
500 if (index >= arrLen) {
501 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
502 }
503 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
504 uint32_t offset = typedarrayObj->GetByteOffset();
505 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
506 uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
507 // 12. Let indexedPosition = (index × elementSize) + offset.
508 uint32_t byteIndex = index * elementSize + offset;
509 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
510 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
511 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
512 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
513 return OperationResult(thread, result, PropertyMetaData(true));
514 }
515
516 // 9.4.5.9 IntegerIndexedElementSet ( O, index, value )
IntegerIndexedElementSet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index,const JSHandle<JSTaggedValue> & value)517 bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
518 JSTaggedValue index, const JSHandle<JSTaggedValue> &value)
519 {
520 // 1. Assert: Type(index) is Number.
521 ASSERT(index.IsNumber());
522 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
523 // [[TypedArrayName]] internal slots.
524 ASSERT(typedarray->IsTypedArray());
525 // 3. If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
526 JSHandle<JSTaggedValue> numValueHandle;
527 ContentType contentType = JSHandle<JSTypedArray>::Cast(typedarray)->GetContentType();
528 if (UNLIKELY(contentType == ContentType::BigInt)) {
529 numValueHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, value));
530 } else {
531 numValueHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToNumber(thread, value));
532 }
533 // 4. ReturnIfAbrupt(numValue).
534 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
535
536 JSHandle<JSTypedArray> typedarrayObj(typedarray);
537 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
538 JSHandle<JSTaggedValue> indexHandle(thread, index);
539 // 5. If ! IsValidIntegerIndex(O, index) is true, then
540 if (IsValidIntegerIndex(typedarray, index)) {
541 // 6. Let offset be the value of O’s [[ByteOffset]] internal slot.
542 uint32_t offset = typedarrayObj->GetByteOffset();
543 // 7. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
544 // 8. Let elementSize be the Number value of the Element Size value specified in Table 49 for
545 // arrayTypeName.
546 uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
547 // 9. Let indexedPosition = (index × elementSize) + offset.
548 uint32_t k = JSTaggedValue::ToInteger(thread, indexHandle).ToUint32();
549 uint32_t byteIndex = k * elementSize + offset;
550 // 10. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
551 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
552 // 11. Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
553 BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, byteIndex, elementType, numValueHandle, true);
554 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
555 }
556 return true;
557 }
558
559 // only use in TypeArray fast set property
NonEcmaObjectToNumber(JSThread * thread,const JSTaggedValue tagged)560 JSTaggedNumber JSTypedArray::NonEcmaObjectToNumber(JSThread *thread, const JSTaggedValue tagged)
561 {
562 ASSERT_PRINT(!tagged.IsECMAObject(), "tagged must not be EcmaObject");
563 if (tagged.IsInt() || tagged.IsDouble()) {
564 return JSTaggedNumber(tagged);
565 }
566 if (tagged.IsString()) {
567 return JSTaggedValue::StringToDouble(tagged);
568 }
569 switch (tagged.GetRawData()) {
570 case JSTaggedValue::VALUE_UNDEFINED:
571 case JSTaggedValue::VALUE_HOLE: {
572 return JSTaggedNumber(base::NAN_VALUE);
573 }
574 case JSTaggedValue::VALUE_TRUE: {
575 return JSTaggedNumber(1);
576 }
577 case JSTaggedValue::VALUE_FALSE:
578 case JSTaggedValue::VALUE_NULL: {
579 return JSTaggedNumber(0);
580 }
581 default: {
582 break;
583 }
584 }
585 if (tagged.IsSymbol()) {
586 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
587 }
588 if (tagged.IsBigInt()) {
589 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
590 }
591 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
592 }
593
FastGetPropertyByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSType jsType)594 JSTaggedValue JSTypedArray::FastGetPropertyByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
595 JSType jsType)
596 {
597 // Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
598 // [[TypedArrayName]] internal slots.
599 ASSERT(typedarray.IsTypedArray());
600 // Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
601 JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
602 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
603 // If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
604 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
605 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
606 }
607
608 DISALLOW_GARBAGE_COLLECTION;
609 // Let length be the value of O’s [[ArrayLength]] internal slot.
610 // If arrLen < 0 or index ≥ length, return undefined.
611 uint32_t arrLen = typedarrayObj->GetArrayLength();
612 if (index >= arrLen) {
613 return JSTaggedValue::Undefined();
614 }
615 // Let offset be the value of O’s [[ByteOffset]] internal slot.
616 uint32_t offset = typedarrayObj->GetByteOffset();
617 // Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
618 uint32_t elementSize = TypedArrayHelper::GetElementSize(jsType);
619 // Let indexedPosition = (index × elementSize) + offset.
620 uint32_t byteIndex = index * elementSize + offset;
621 // Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
622 DataViewType elementType = TypedArrayHelper::GetType(jsType);
623 // Return GetValueFromBuffer(buffer, indexedPosition, elementType).
624 return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
625 }
626
FastSetPropertyByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSTaggedValue value,JSType jsType)627 JSTaggedValue JSTypedArray::FastSetPropertyByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
628 JSTaggedValue value, JSType jsType)
629 {
630 // Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
631 // [[TypedArrayName]] internal slots.
632 ASSERT(typedarray.IsTypedArray());
633 // If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
634 JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
635 if (UNLIKELY(typedarrayObj->GetContentType() == ContentType::BigInt || value.IsECMAObject())) {
636 return JSTaggedValue::Hole();
637 }
638 JSTaggedNumber numValue = JSTypedArray::NonEcmaObjectToNumber(thread, value);
639 // ReturnIfAbrupt(numValue).
640 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
641
642 DISALLOW_GARBAGE_COLLECTION;
643 JSTaggedValue buffer = typedarrayObj->GetViewedArrayBuffer();
644
645 // If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
646 uint32_t arrLen = typedarrayObj->GetArrayLength();
647 if (index >= arrLen) {
648 return JSTaggedValue::Undefined();
649 }
650 // Let offset be the value of O’s [[ByteOffset]] internal slot.
651 uint32_t offset = typedarrayObj->GetByteOffset();
652 // Let arrayTypeName be the String value of O’s [[TypedArrayName]]
653 // Let elementSize be the Number value of the Element Size value specified in Table 49 for
654 // arrayTypeName.
655 uint32_t elementSize = TypedArrayHelper::GetElementSize(jsType);
656 // Let indexedPosition = (index × elementSize) + offset.
657 uint32_t byteIndex = index * elementSize + offset;
658 // Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
659 DataViewType elementType = TypedArrayHelper::GetType(jsType);
660 // Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
661 return BuiltinsArrayBuffer::FastSetValueInBuffer(buffer, byteIndex, elementType, numValue.GetNumber(), true);
662 }
663
GetOffHeapBuffer(JSThread * thread,JSHandle<JSTypedArray> & typedArray)664 JSTaggedValue JSTypedArray::GetOffHeapBuffer(JSThread *thread, JSHandle<JSTypedArray> &typedArray)
665 {
666 JSTaggedValue arrBuf = typedArray->GetViewedArrayBuffer();
667 if (arrBuf.IsArrayBuffer() || arrBuf.IsSharedArrayBuffer()) {
668 return arrBuf;
669 }
670
671 ByteArray *byteArray = ByteArray::Cast(arrBuf.GetTaggedObject());
672 int32_t length = static_cast<int32_t>(byteArray->GetLength() * byteArray->GetSize());
673 JSHandle<JSArrayBuffer> arrayBuffer = thread->GetEcmaVM()->GetFactory()->NewJSArrayBuffer(length);
674
675 if (length > 0) {
676 void *fromBuf = reinterpret_cast<void *>(ToUintPtr(
677 ByteArray::Cast(typedArray->GetViewedArrayBuffer().GetTaggedObject())->GetData()));
678 JSTaggedValue data = arrayBuffer->GetArrayBufferData();
679 void *toBuf = reinterpret_cast<void *>(
680 ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer()));
681 JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, 0, length);
682 }
683 typedArray->SetViewedArrayBuffer(thread, arrayBuffer.GetTaggedValue());
684 typedArray->SetIsOnHeap(false);
685
686 return arrayBuffer.GetTaggedValue();
687 }
688 } // namespace panda::ecmascript
689