• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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/base/typed_array_helper-inl.h"
19 #include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
20 
21 namespace panda::ecmascript {
22 using TypedArrayHelper = base::TypedArrayHelper;
23 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
24 using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer;
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->GetViewedArrayBufferOrByteArray();
94             if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
95                 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
96             }
97             if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
98                 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
99             }
100             if (!numericIndex.IsInteger()) {
101                 return false;
102             }
103             JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
104             JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
105             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
106             double tNegZero = -0.0;
107             auto eZero = JSTaggedNumber(tNegZero);
108             JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
109             if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
110                 return false;
111             }
112 
113             if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
114                 return false;
115             }
116             uint32_t arrLen = typedarrayObj->GetArrayLength();
117             JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
118             return JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle);
119         }
120     }
121     // 4. Return OrdinaryHasProperty(O, P).
122     PropertyDescriptor desc(thread);
123     if (JSObject::OrdinaryGetOwnProperty(thread, JSHandle<JSObject>::Cast(typedarrayObj), key, desc)) {
124         return true;
125     }
126     JSTaggedValue parent = JSTaggedValue::GetPrototype(thread, JSHandle<JSTaggedValue>::Cast(typedarrayObj));
127     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
128     if (!parent.IsNull()) {
129         return JSTaggedValue::HasProperty(thread, JSHandle<JSTaggedValue>(thread, parent), key);
130     }
131     return false;
132 }
133 
134 // 9.4.5.3 [[DefineOwnProperty]] ( P, Desc )
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)135 bool JSTypedArray::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
136                                      const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
137 {
138     // 1. Assert: IsPropertyKey(P) is true.
139     ASSERT(JSTaggedValue::IsPropertyKey(key));
140     // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
141     // 3. If Type(P) is String, then
142     //   a. Let numericIndex be CanonicalNumericIndexString (P).
143     //   b. Assert: numericIndex is not an abrupt completion.
144     //   c. If numericIndex is not undefined, then
145     JSHandle<JSTypedArray> typedarrayObj(typedarray);
146     if (key->IsString() || key->IsNumber()) {
147         JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
148         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
149         if (!numericIndex.IsUndefined()) {
150             // i. If IsInteger(numericIndex) is false, return false
151             // ii. Let intIndex be numericIndex.
152             // iii. If intIndex = −0, return false.
153             // iv. If intIndex < 0, return false.
154             // v. Let length be the value of O’s [[ArrayLength]] internal slot.
155             // vi. If intIndex ≥ length, return false.
156             // vii. If IsAccessorDescriptor(Desc) is true, return false.
157             // viii. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is true, return false.
158             // ix. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
159             // x. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false.
160             // xi. If Desc has a [[Value]] field, then
161             //   1. Let value be Desc.[[Value]].
162             //   2. Return IntegerIndexedElementSet (O, intIndex, value).
163             // xii. Return true.
164             if (!numericIndex.IsInteger()) {
165                 return false;
166             }
167             JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
168             JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
169             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
170             double tNegZero = -0.0;
171             auto eZero = JSTaggedNumber(tNegZero);
172             JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
173             if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
174                 return false;
175             }
176             if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
177                 return false;
178             }
179             uint32_t arrLen = typedarrayObj->GetArrayLength();
180             JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
181             if (!JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle)) {
182                 return false;
183             }
184             if (desc.IsAccessorDescriptor()) {
185                 return false;
186             }
187             if (desc.HasConfigurable() && !desc.IsConfigurable()) {
188                 return false;
189             }
190             if (desc.HasEnumerable() && !desc.IsEnumerable()) {
191                 return false;
192             }
193             if (desc.HasWritable() && !desc.IsWritable()) {
194                 return false;
195             }
196             if (desc.HasValue()) {
197                 JSHandle<JSTaggedValue> value = desc.GetValue();
198                 return (JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value));
199             }
200             return true;
201         }
202     }
203     // 4. Return OrdinaryDefineOwnProperty(O, P, Desc).
204     bool result = JSObject::OrdinaryDefineOwnProperty(thread, JSHandle<JSObject>::Cast(typedarrayObj), key, desc);
205     if (result) {
206         JSTaggedValue constructorKey = thread->GlobalConstants()->GetConstructorString();
207         if (key.GetTaggedValue() == constructorKey) {
208             typedarrayObj->GetJSHClass()->SetHasConstructor(true);
209             return true;
210         }
211     }
212     return result;
213 }
214 
215 // 9.4.5.4 [[Get]] ( P, Receiver )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)216 OperationResult JSTypedArray::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
217                                           const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
218 {
219     // 1. Assert : IsPropertyKey(P) is true.
220     ASSERT(JSTaggedValue::IsPropertyKey(key));
221     // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
222     if ((key->IsString() || key->IsNumber()) && JSTaggedValue::SameValue(typedarray, receiver)) {
223         //   a. Let numericIndex be CanonicalNumericIndexString (P).
224         //   b. Assert: numericIndex is not an abrupt completion.
225         //   c. If numericIndex is not undefined, then
226         //     i. Return IntegerIndexedElementGet (O, numericIndex).
227         JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
228         RETURN_VALUE_IF_ABRUPT_COMPLETION(
229             thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
230         if (!numericIndex.IsUndefined()) {
231             return JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex);
232         }
233     }
234 
235     // 3. Return the result of calling the default ordinary object [[Get]] internal method (9.1.8) on O
236     //   passing P and Receiver as arguments.
237     return JSObject::GetProperty(thread, typedarray, key, receiver);
238 }
239 
240 // 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)241 bool JSTypedArray::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
242                                const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
243                                const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
244 {
245     // 1. Assert : IsPropertyKey(P) is true.
246     ASSERT(JSTaggedValue::IsPropertyKey(key));
247     // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
248     if ((key->IsString() || key->IsNumber()) && JSTaggedValue::SameValue(typedarray, receiver)) {
249         //   a. Let numericIndex be CanonicalNumericIndexString (P).
250         //   b. Assert: numericIndex is not an abrupt completion.
251         //   c. If numericIndex is not undefined, then
252         //     i. Return IntegerIndexedElementSet (O, numericIndex, V).
253         JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
254         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
255         if (!numericIndex.IsUndefined()) {
256             return JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value);
257         }
258     }
259     // 3. Return the result of calling the default ordinary object [[Set]] internal method (9.1.8) on O passing
260     // P, V, and Receiver as arguments.
261     return JSObject::SetProperty(thread, typedarray, key, value, receiver, mayThrow);
262 }
263 
264 // s12 10.4.5.6 [[Delete]] ( P )
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key)265 bool JSTypedArray::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
266                                   const JSHandle<JSTaggedValue> &key)
267 {
268     // 1. Assert: IsPropertyKey(P) is true.
269     // 2. Assert: O is an Integer-Indexed exotic object.
270     ASSERT(JSTaggedValue::IsPropertyKey(key));
271     // 3. If Type(P) is String, then
272         // a. Let numericIndex be CanonicalNumericIndexString(P).
273         // b. If numericIndex is not undefined, then
274            // i. If IsValidIntegerIndex(O, numericIndex) is false, return true; else return false.
275     if (key->IsString() || key->IsNumber()) {
276         JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
277         if (!numericIndex.IsUndefined()) {
278             if (!IsValidIntegerIndex(typedarray, numericIndex)) {
279                 return true;
280             }
281             return false;
282         }
283     }
284     // 4. Return ? OrdinaryDelete(O, P).
285     return JSObject::DeleteProperty(thread, JSHandle<JSObject>(typedarray), key);
286 }
287 
288 // 9.4.5.6 [[OwnPropertyKeys]] ( )
OwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray)289 JSHandle<TaggedArray> JSTypedArray::OwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray)
290 {
291     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
292     // 1. Let keys be a new empty List.
293     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
294     // [[TypedArrayName]] internal slots.
295     // 3. Let len be the value of O’s [[ArrayLength]] internal slot.
296     JSHandle<JSTypedArray> arrayObj(typedarray);
297     JSHandle<TaggedArray> objKeys = JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>::Cast(arrayObj));
298     uint32_t objKeysLen = objKeys->GetLength();
299     uint32_t bufferKeysLen = arrayObj->GetArrayLength();
300     uint32_t length = objKeysLen + bufferKeysLen;
301     JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
302 
303     // 4. For each integer i starting with 0 such that i < len, in ascending order,
304     //   a. Add ToString(i) as the last element of keys.
305     uint32_t copyLength = 0;
306     JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
307     for (uint32_t k = 0; k < bufferKeysLen; k++) {
308         tKey.Update(JSTaggedValue(k));
309         JSHandle<JSTaggedValue> sKey(JSTaggedValue::ToString(thread, tKey));
310         RETURN_HANDLE_IF_ABRUPT_COMPLETION(TaggedArray, thread);
311         nameList->Set(thread, copyLength, sKey.GetTaggedValue());
312         copyLength++;
313     }
314 
315     // 5. For each own property key P of O such that Type(P) is String and P is not an integer index, in
316     // property creation order
317     //   a. Add P as the last element of keys.
318     for (uint32_t i = 0; i < objKeysLen; i++) {
319         JSTaggedValue key = objKeys->Get(i);
320         if (JSTaggedValue(key).IsString()) {
321             nameList->Set(thread, copyLength, key);
322             copyLength++;
323         }
324     }
325 
326     // 6. For each own property key P of O such that Type(P) is Symbol, in property creation order
327     //   a. Add P as the last element of keys.
328     for (uint32_t i = 0; i < objKeysLen; i++) {
329         JSTaggedValue key = objKeys->Get(i);
330         if (JSTaggedValue(key).IsSymbol()) {
331             nameList->Set(thread, copyLength, key);
332             copyLength++;
333         }
334     }
335 
336     // 7. Return keys.
337     return factory->CopyArray(nameList, length, copyLength);
338 }
339 
OwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray)340 JSHandle<TaggedArray> JSTypedArray::OwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray)
341 {
342     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
343     // 1. Let keys be a new empty List.
344     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
345     // [[TypedArrayName]] internal slots.
346     // 3. Let len be the value of O’s [[ArrayLength]] internal slot.
347     JSHandle<JSTypedArray> arrayObj(typedarray);
348     JSHandle<TaggedArray> objKeys = JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>::Cast(arrayObj));
349     uint32_t objKeysLen = objKeys->GetLength();
350     uint32_t bufferKeysLen = arrayObj->GetArrayLength();
351     uint32_t length = objKeysLen + bufferKeysLen;
352     JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
353 
354     // 4. For each integer i starting with 0 such that i < len, in ascending order,
355     //   a. Add ToString(i) as the last element of keys.
356     uint32_t copyLength = 0;
357     for (uint32_t k = 0; k < bufferKeysLen; k++) {
358         auto key = base::NumberHelper::IntToEcmaString(thread, k);
359         nameList->Set(thread, copyLength, key);
360         copyLength++;
361     }
362 
363     // 5. For each own property key P of O such that Type(P) is String and P is not an integer index, in
364     // property creation order
365     //   a. Add P as the last element of keys.
366     for (uint32_t i = 0; i < objKeysLen; i++) {
367         JSTaggedValue key = objKeys->Get(i);
368         nameList->Set(thread, copyLength, key);
369         copyLength++;
370     }
371 
372     // 7. Return keys.
373     return factory->CopyArray(nameList, length, copyLength);
374 }
375 
376 // 9.4.5.7 IntegerIndexedObjectCreate (prototype, internalSlotsList)
377 
378 // 9.4.5.8 IntegerIndexedElementGet ( O, index )
IntegerIndexedElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index)379 OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
380                                                        JSTaggedValue index)
381 {
382     // 1. Assert: Type(index) is Number.
383     ASSERT(index.IsNumber());
384     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
385     // [[TypedArrayName]] internal slots.
386     ASSERT(typedarray->IsTypedArray() || typedarray->IsSharedTypedArray());
387     // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
388     JSHandle<JSTypedArray> typedarrayObj(typedarray);
389     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
390     // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
391     if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
392         if (index == JSTaggedValue(0)) {
393             return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
394         }
395         THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
396                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
397     }
398     if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
399         THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
400                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
401     }
402     // 5. If IsInteger(index) is false, return undefined
403     if (!index.IsInteger()) {
404         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
405     }
406 
407     // 6. If index = −0, return undefined.
408     // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
409     // 8. If index < 0 or index ≥ length, return undefined.
410     JSHandle<JSTaggedValue> indexHandle(thread, index);
411     JSTaggedNumber indexNumber = JSTaggedValue::ToNumber(thread, indexHandle);
412     RETURN_VALUE_IF_ABRUPT_COMPLETION(
413         thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
414     double tNegZero = -0.0;
415     auto eZero = JSTaggedNumber(tNegZero);
416     JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
417     if (JSTaggedNumber::SameValue(indexNumber, eZero)) {
418         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
419     }
420     uint32_t arrLen = typedarrayObj->GetArrayLength();
421     JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
422     if (JSTaggedValue::Less(thread, indexHandle, zero) || !JSTaggedValue::Less(thread, indexHandle, arrLenHandle)) {
423         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
424     }
425     // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
426     uint32_t offset = typedarrayObj->GetByteOffset();
427     // 10. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
428     // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for
429     // arrayTypeName.
430     uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
431     // 12. Let indexedPosition = (index × elementSize) + offset.
432     uint32_t k = static_cast<uint32_t>(JSTaggedValue::ToInteger(thread, indexHandle).ToInt32());
433     uint32_t byteIndex = k * elementSize + offset;
434     // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
435     DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
436     // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
437     JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
438     return OperationResult(thread, result, PropertyMetaData(true));
439 }
440 
441 // s12 10.4.5.9 IsValidIntegerIndex ( O, index )
IsValidIntegerIndex(const JSHandle<JSTaggedValue> & typedArray,JSTaggedValue index)442 bool JSTypedArray::IsValidIntegerIndex(const JSHandle<JSTaggedValue> &typedArray, JSTaggedValue index)
443 {
444     // 1. Assert: O is an Integer-Indexed exotic object.
445     // 2. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
446     JSHandle<JSTypedArray> typedarrayObj(typedArray);
447     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
448     if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
449         return false;
450     }
451     if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
452         return false;
453     }
454     // 3. If ! IsIntegralNumber(index) is false, return false.
455     if (!index.IsInteger()) {
456         return false;
457     }
458     // 4. If index is -0��, return false.
459     double val = index.GetNumber();
460     if (val == 0 && std::signbit(val)) {
461         return false;
462     }
463 
464     uint32_t arrLen = typedarrayObj->GetArrayLength();
465     // 5. If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
466     if (val < 0 || val >= arrLen) {
467         return false;
468     }
469     // 6. Return true.
470     return true;
471 }
472 
GetTypeFromName(JSThread * thread,const JSHandle<JSTaggedValue> & typeName)473 DataViewType JSTypedArray::GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName)
474 {
475     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
476     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt8ArrayString()) ||
477         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedInt8ArrayString())) {
478         return DataViewType::INT8;
479     }
480     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ArrayString()) ||
481         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedUint8ArrayString())) {
482         return DataViewType::UINT8;
483     }
484     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ClampedArrayString()) ||
485         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedUint8ClampedArrayString())) {
486         return DataViewType::UINT8_CLAMPED;
487     }
488     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt16ArrayString()) ||
489         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedInt16ArrayString())) {
490         return DataViewType::INT16;
491     }
492     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint16ArrayString()) ||
493         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedUint16ArrayString())) {
494         return DataViewType::UINT16;
495     }
496     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt32ArrayString()) ||
497         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedInt32ArrayString())) {
498         return DataViewType::INT32;
499     }
500     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint32ArrayString()) ||
501         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedUint32ArrayString())) {
502         return DataViewType::UINT32;
503     }
504     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString()) ||
505         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedFloat32ArrayString())) {
506         return DataViewType::FLOAT32;
507     }
508     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString()) ||
509         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedFloat64ArrayString())) {
510         return DataViewType::FLOAT64;
511     }
512     if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString()) ||
513         JSTaggedValue::SameValue(typeName, globalConst->GetHandledSharedBigInt64ArrayString())) {
514         return DataViewType::BIGINT64;
515     }
516     return DataViewType::BIGUINT64;
517 }
518 
519 // static
FastCopyElementToArray(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<TaggedArray> & array)520 bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
521                                           JSHandle<TaggedArray> &array)
522 {
523     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
524     // [[TypedArrayName]] internal slots.
525     ASSERT(typedArray->IsTypedArray() || typedArray->IsSharedTypedArray());
526     // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
527     JSHandle<JSTypedArray> typedarrayObj(typedArray);
528     JSHandle<JSTaggedValue> bufferHandle = JSHandle<JSTaggedValue>(thread,
529                                                                    typedarrayObj->GetViewedArrayBufferOrByteArray());
530     // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
531     if (!bufferHandle.GetTaggedValue().IsSendableArrayBuffer() &&
532         BuiltinsArrayBuffer::IsDetachedBuffer(bufferHandle.GetTaggedValue())) {
533         THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
534     }
535     if (bufferHandle.GetTaggedValue().IsSendableArrayBuffer() &&
536         BuiltinsSendableArrayBuffer::IsDetachedBuffer(bufferHandle.GetTaggedValue())) {
537         THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
538     }
539 
540     // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
541     // 8. If index < 0 or index ≥ length, return undefined.
542     uint32_t arrLen = typedarrayObj->GetArrayLength();
543 
544     // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
545     uint32_t offset = typedarrayObj->GetByteOffset();
546     // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
547     uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
548     // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
549     DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
550     for (uint32_t index = 0; index < arrLen; index++) {
551         // 12. Let indexedPosition = (index × elementSize) + offset.
552         uint32_t byteIndex = index * elementSize + offset;
553         // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
554         JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(),
555                                                                        byteIndex, elementType, true);
556         array->Set(thread, index, result);
557     }
558     return true;
559 }
560 
561 // static
FastElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,uint32_t index)562 OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
563                                              uint32_t index)
564 {
565     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
566     // [[TypedArrayName]] internal slots.
567     ASSERT(typedarray->IsTypedArray() || typedarray->IsSharedTypedArray());
568     // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
569     JSHandle<JSTypedArray> typedarrayObj(typedarray);
570     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
571     // 10.4.5.15 TypedArrayGetElement ( O, index )
572     //  1. If IsValidIntegerIndex(O, index) is false, return undefined.
573     if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
574         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
575     }
576     if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
577         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
578     }
579 
580     // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
581     // 8. If index < 0 or index ≥ length, return undefined.
582     uint32_t arrLen = typedarrayObj->GetArrayLength();
583     if (index >= arrLen) {
584         return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
585     }
586     // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
587     uint32_t offset = typedarrayObj->GetByteOffset();
588     // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
589     uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
590     // 12. Let indexedPosition = (index × elementSize) + offset.
591     uint32_t byteIndex = index * elementSize + offset;
592     // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
593     DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
594     // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
595     JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
596     return OperationResult(thread, result, PropertyMetaData(true));
597 }
598 
599 // 9.4.5.9 IntegerIndexedElementSet ( O, index, value )
IntegerIndexedElementSet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index,const JSHandle<JSTaggedValue> & value)600 bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
601                                             JSTaggedValue index, const JSHandle<JSTaggedValue> &value)
602 {
603     // 1. Assert: Type(index) is Number.
604     ASSERT(index.IsNumber());
605     // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
606     // [[TypedArrayName]] internal slots.
607     ASSERT(typedarray->IsTypedArray() || typedarray->IsSharedTypedArray());
608     // 3. If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
609     JSHandle<JSTaggedValue> numValueHandle;
610     ContentType contentType = JSHandle<JSTypedArray>::Cast(typedarray)->GetContentType();
611     if (UNLIKELY(contentType == ContentType::BigInt)) {
612         numValueHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, value));
613         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
614     } else {
615         numValueHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToNumber(thread, value));
616         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
617     }
618 
619     JSHandle<JSTypedArray> typedarrayObj(typedarray);
620     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
621     JSHandle<JSTaggedValue> indexHandle(thread, index);
622     // 5. If ! IsValidIntegerIndex(O, index) is true, then
623     if (IsValidIntegerIndex(typedarray, index)) {
624         // 6. Let offset be the value of O’s [[ByteOffset]] internal slot.
625         uint32_t offset = typedarrayObj->GetByteOffset();
626         // 7. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
627         // 8. Let elementSize be the Number value of the Element Size value specified in Table 49 for
628         // arrayTypeName.
629         uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
630         // 9. Let indexedPosition = (index × elementSize) + offset.
631         uint32_t k = JSTaggedValue::ToInteger(thread, indexHandle).ToUint32();
632         uint32_t byteIndex = k * elementSize + offset;
633         // 10. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
634         DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
635         // 11. Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
636         BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, byteIndex, elementType, numValueHandle, true);
637         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
638     }
639     return true;
640 }
641 
642 // only use in TypeArray fast set property
NonEcmaObjectToNumber(JSThread * thread,const JSTaggedValue tagged)643 JSTaggedNumber JSTypedArray::NonEcmaObjectToNumber(JSThread *thread, const JSTaggedValue tagged)
644 {
645     ASSERT_PRINT(!tagged.IsECMAObject(), "tagged must not be EcmaObject");
646     if (tagged.IsInt() || tagged.IsDouble()) {
647         return JSTaggedNumber(tagged);
648     }
649     if (tagged.IsString()) {
650         return JSTaggedValue::StringToDouble(tagged);
651     }
652     switch (tagged.GetRawData()) {
653         case JSTaggedValue::VALUE_UNDEFINED:
654         case JSTaggedValue::VALUE_HOLE: {
655             return JSTaggedNumber(base::NAN_VALUE);
656         }
657         case JSTaggedValue::VALUE_TRUE: {
658             return JSTaggedNumber(1);
659         }
660         case JSTaggedValue::VALUE_FALSE:
661         case JSTaggedValue::VALUE_NULL: {
662             return JSTaggedNumber(0);
663         }
664         default: {
665             break;
666         }
667     }
668     if (tagged.IsSymbol()) {
669         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
670     }
671     if (tagged.IsBigInt()) {
672         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
673     }
674     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
675 }
676 
FastGetPropertyByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSType jsType)677 JSTaggedValue JSTypedArray::FastGetPropertyByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
678                                                    JSType jsType)
679 {
680     // Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
681     // [[TypedArrayName]] internal slots.
682     ASSERT(typedarray.IsTypedArray() || typedarray.IsSharedTypedArray());
683     // Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
684     JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
685     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
686     if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
687         return JSTaggedValue::Undefined();
688     }
689     if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
690         return JSTaggedValue::Undefined();
691     }
692 
693     DISALLOW_GARBAGE_COLLECTION;
694     // Let length be the value of O’s [[ArrayLength]] internal slot.
695     // If arrLen < 0 or index ≥ length, return undefined.
696     uint32_t arrLen = typedarrayObj->GetArrayLength();
697     if (index >= arrLen) {
698         return JSTaggedValue::Undefined();
699     }
700     // Let offset be the value of O’s [[ByteOffset]] internal slot.
701     uint32_t offset = typedarrayObj->GetByteOffset();
702     // Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
703     uint32_t elementSize = TypedArrayHelper::GetElementSize(jsType);
704     // Let indexedPosition = (index × elementSize) + offset.
705     uint32_t byteIndex = index * elementSize + offset;
706     // Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
707     DataViewType elementType = TypedArrayHelper::GetType(jsType);
708     // Return GetValueFromBuffer(buffer, indexedPosition, elementType).
709     return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
710 }
711 
FastSetPropertyByIndex(JSThread * thread,const JSTaggedValue typedarray,uint32_t index,JSTaggedValue value,JSType jsType)712 JSTaggedValue JSTypedArray::FastSetPropertyByIndex(JSThread *thread, const JSTaggedValue typedarray, uint32_t index,
713                                                    JSTaggedValue value, JSType jsType)
714 {
715     // Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
716     // [[TypedArrayName]] internal slots.
717     ASSERT(typedarray.IsTypedArray() || typedarray.IsSharedTypedArray());
718     // If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
719     JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
720     if (UNLIKELY(typedarrayObj->GetContentType() == ContentType::BigInt || value.IsECMAObject())) {
721         return JSTaggedValue::Hole();
722     }
723     JSTaggedNumber numValue = JSTypedArray::NonEcmaObjectToNumber(thread, value);
724     // ReturnIfAbrupt(numValue).
725     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
726 
727     DISALLOW_GARBAGE_COLLECTION;
728     JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
729 
730     // If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
731     uint32_t arrLen = typedarrayObj->GetArrayLength();
732     if (index >= arrLen) {
733         return JSTaggedValue::Undefined();
734     }
735     // Let offset be the value of O’s [[ByteOffset]] internal slot.
736     uint32_t offset = typedarrayObj->GetByteOffset();
737     // Let arrayTypeName be the String value of O’s [[TypedArrayName]]
738     // Let elementSize be the Number value of the Element Size value specified in Table 49 for
739     // arrayTypeName.
740     uint32_t elementSize = TypedArrayHelper::GetElementSize(jsType);
741     // Let indexedPosition = (index × elementSize) + offset.
742     uint32_t byteIndex = index * elementSize + offset;
743     // Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
744     DataViewType elementType = TypedArrayHelper::GetType(jsType);
745     // Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
746     return BuiltinsArrayBuffer::FastSetValueInBuffer(thread,
747         buffer, byteIndex, elementType, numValue.GetNumber(), true);
748 }
749 
GetOffHeapBuffer(JSThread * thread,JSHandle<JSTypedArray> & typedArray)750 JSTaggedValue JSTypedArray::GetOffHeapBuffer(JSThread *thread, JSHandle<JSTypedArray> &typedArray)
751 {
752     JSTaggedValue arrBuf = typedArray->GetViewedArrayBufferOrByteArray();
753     if (arrBuf.IsArrayBuffer() || arrBuf.IsSharedArrayBuffer()) {
754         return arrBuf;
755     }
756 
757     ByteArray *byteArray = ByteArray::Cast(arrBuf.GetTaggedObject());
758     int32_t length = static_cast<int32_t>(byteArray->GetArrayLength() * byteArray->GetByteLength());
759     JSHandle<JSArrayBuffer> arrayBuffer = thread->GetEcmaVM()->GetFactory()->NewJSArrayBuffer(length);
760 
761     if (length > 0) {
762         void *fromBuf = reinterpret_cast<void *>(ToUintPtr(
763             ByteArray::Cast(typedArray->GetViewedArrayBufferOrByteArray().GetTaggedObject())->GetData()));
764         JSTaggedValue data = arrayBuffer->GetArrayBufferData();
765         void *toBuf = reinterpret_cast<void *>(
766             ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer()));
767         JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, 0, length);
768     }
769     typedArray->SetViewedArrayBufferOrByteArray(thread, arrayBuffer.GetTaggedValue());
770     JSHandle<JSTaggedValue> typeName(thread, typedArray->GetTypedArrayName());
771     DataViewType arrayType = JSTypedArray::GetTypeFromName(thread, typeName);
772     JSHandle<JSHClass> notOnHeapHclass = TypedArrayHelper::GetNotOnHeapHclassFromType(
773         thread, typedArray, arrayType);
774 #if ECMASCRIPT_ENABLE_IC
775     JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, typedArray->GetJSHClass()), notOnHeapHclass);
776 #endif
777     TaggedObject::Cast(*typedArray)->SynchronizedSetClass(thread, *notOnHeapHclass); // onHeap->notOnHeap
778 
779     return arrayBuffer.GetTaggedValue();
780 }
781 
GetSharedOffHeapBuffer(JSThread * thread,JSHandle<JSSharedTypedArray> typedArray)782 JSTaggedValue JSSharedTypedArray::GetSharedOffHeapBuffer(JSThread *thread, JSHandle<JSSharedTypedArray> typedArray)
783 {
784     JSTaggedValue arrBuf = typedArray->GetViewedArrayBufferOrByteArray();
785     if (arrBuf.IsSendableArrayBuffer()) {
786         return arrBuf;
787     }
788 
789     ByteArray *byteArray = ByteArray::Cast(arrBuf.GetTaggedObject());
790     int32_t length = static_cast<int32_t>(byteArray->GetArrayLength() * byteArray->GetByteLength());
791     JSHandle<JSSendableArrayBuffer> arrayBuffer = thread->GetEcmaVM()->GetFactory()->NewJSSendableArrayBuffer(length);
792 
793     if (length > 0) {
794         void *fromBuf = reinterpret_cast<void *>(ToUintPtr(
795             ByteArray::Cast(typedArray->GetViewedArrayBufferOrByteArray().GetTaggedObject())->GetData()));
796         JSTaggedValue data = arrayBuffer->GetArrayBufferData();
797         void *toBuf = reinterpret_cast<void *>(
798             ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer()));
799         JSSendableArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, 0, length);
800     }
801     typedArray->SetViewedArrayBufferOrByteArray(thread, arrayBuffer.GetTaggedValue());
802     JSHandle<JSTaggedValue> typeName(thread, typedArray->GetTypedArrayName());
803     DataViewType arrayType = JSTypedArray::GetTypeFromName(thread, typeName);
804     JSHandle<JSHClass> notOnHeapHclass = TypedArrayHelper::GetSharedNotOnHeapHclassFromType(
805         thread, typedArray, arrayType);
806 #if ECMASCRIPT_ENABLE_IC
807     JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, typedArray->GetJSHClass()), notOnHeapHclass);
808 #endif
809     TaggedObject::Cast(*typedArray)->SynchronizedSetClass(thread, *notOnHeapHclass); // onHeap->notOnHeap
810 
811     return arrayBuffer.GetTaggedValue();
812 }
813 
FastTypedArrayFill(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,const JSHandle<JSTaggedValue> & value,uint32_t start,uint32_t end)814 bool JSTypedArray::FastTypedArrayFill(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
815                                       const JSHandle<JSTaggedValue> &value, uint32_t start, uint32_t end)
816 {
817     // Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
818     // [[TypedArrayName]] internal slots.
819     ASSERT(typedArray->IsTypedArray() || typedArray->IsSharedTypedArray());
820     // If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value).
821     JSHandle<JSTypedArray> typedArrayObj = JSHandle<JSTypedArray>::Cast(typedArray);
822     if (UNLIKELY(typedArrayObj->GetContentType() == ContentType::BigInt || value->IsECMAObject())) {
823         return false;
824     }
825     JSTaggedNumber numValue = JSTypedArray::NonEcmaObjectToNumber(thread, value.GetTaggedValue());
826     // ReturnIfAbrupt(numValue).
827     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, true);
828     JSTaggedValue buffer = typedArrayObj->GetViewedArrayBufferOrByteArray();
829     // If ℝ(index) < 0 or ℝ(index) ≥ O.[[ArrayLength]], return false.
830     uint32_t arrLen = typedArrayObj->GetArrayLength();
831     // Let offset be the value of O’s [[ByteOffset]] internal slot.
832     uint32_t offset = typedArrayObj->GetByteOffset();
833     // Let arrayTypeName be the String value of O’s [[TypedArrayName]]
834     // Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
835     JSType jsType = typedArrayObj->GetClass()->GetObjectType();
836     uint32_t elementSize = TypedArrayHelper::GetElementSize(jsType);
837     // Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
838     DataViewType elementType = TypedArrayHelper::GetType(jsType);
839     uint64_t byteBeginOffset = start * elementSize + offset;
840     uint64_t byteEndOffset = std::min(end, arrLen) * elementSize + offset;
841     if (byteBeginOffset < byteEndOffset) {
842         BuiltinsArrayBuffer::TryFastSetValueInBuffer(thread, buffer,
843             byteBeginOffset, byteEndOffset, elementType, numValue.GetNumber(), true);
844     }
845     return true;
846 }
847 }  // namespace panda::ecmascript
848