• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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