1 /*
2 * Copyright (c) 2021 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 #include "ecmascript/accessor_data.h"
18 #include "ecmascript/base/typed_array_helper-inl.h"
19 #include "ecmascript/builtins/builtins_arraybuffer.h"
20
21 namespace panda::ecmascript {
22 using TypedArrayHelper = base::TypedArrayHelper;
23 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
24
ToPropKey(JSThread * thread,const JSHandle<JSTaggedValue> & key)25 JSHandle<JSTaggedValue> JSTypedArray::ToPropKey(JSThread *thread, const JSHandle<JSTaggedValue> &key)
26 {
27 if (key->IsSymbol()) {
28 return key;
29 }
30 return JSHandle<JSTaggedValue>(JSTaggedValue::ToString(thread, key));
31 }
32 // 9.4.5.1 [[GetOwnProperty]] ( P )
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)33 bool JSTypedArray::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
34 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
35 {
36 // 1. Assert : IsPropertyKey(P) is true.
37 ASSERT(JSTaggedValue::IsPropertyKey(key));
38 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
39 // 3. If Type(P) is String, then
40 // a. Let numericIndex be CanonicalNumericIndexString(P).
41 // b. Assert: numericIndex is not an abrupt completion.
42 // c. If numericIndex is not undefined, then
43 // i. Let value be IntegerIndexedElementGet (O, numericIndex).
44 // ii. ReturnIfAbrupt(value).
45 // iii. If value is undefined, return undefined.
46 // iv. Return a PropertyDescriptor{ [[Value]]: value, [[Enumerable]]: true, [[Writable]]: true,
47 // [[Configurable]]: false }.
48 if (key->IsString()) {
49 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
50 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
51 if (!numericIndex.IsUndefined()) {
52 JSHandle<JSTaggedValue> value =
53 JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex).GetValue();
54 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
55 if (value->IsUndefined()) {
56 return false;
57 }
58 desc.SetValue(value);
59 desc.SetEnumerable(true);
60 desc.SetWritable(true);
61 desc.SetConfigurable(true);
62 return true;
63 }
64 }
65 // 4. Return OrdinaryGetOwnProperty(O, P).
66 return JSObject::OrdinaryGetOwnProperty(thread, JSHandle<JSObject>(typedarray), key, desc);
67 }
68
69 // 9.4.5.2 [[HasProperty]] ( P )
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key)70 bool JSTypedArray::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
71 const JSHandle<JSTaggedValue> &key)
72 {
73 // 1. Assert: IsPropertyKey(P) is true.
74 ASSERT(JSTaggedValue::IsPropertyKey(key));
75 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
76 // 3. If Type(P) is String, then
77 // a. Let numericIndex be CanonicalNumericIndexString(P).
78 // b. Assert: numericIndex is not an abrupt completion.
79 // c. If numericIndex is not undefined, then
80 // i. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
81 // ii. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
82 // iii. If IsInteger(numericIndex) is false, return false
83 // iv. If numericIndex = −0, return false.
84 // v. If numericIndex < 0, return false.
85 // vi. If numericIndex ≥ the value of O’s [[ArrayLength]] internal slot, return false.
86 // vii. Return true.
87 JSHandle<JSObject> typedarrayObj(typedarray);
88 if (key->IsString()) {
89 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
90 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
91 if (!numericIndex.IsUndefined()) {
92 JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer();
93 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
94 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
95 }
96 if (!numericIndex.IsInteger()) {
97 return false;
98 }
99 JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
100 JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
101 double tNegZero = -0.0;
102 auto eZero = JSTaggedNumber(tNegZero);
103 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
104 if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
105 return false;
106 }
107
108 if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
109 return false;
110 }
111 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
112 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
113 return JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle);
114 }
115 }
116 // 4. Return OrdinaryHasProperty(O, P).
117 PropertyDescriptor desc(thread);
118 if (JSObject::OrdinaryGetOwnProperty(thread, typedarrayObj, key, desc)) {
119 return true;
120 }
121 JSTaggedValue parent = typedarrayObj->GetPrototype(thread);
122 if (!parent.IsNull()) {
123 return JSTaggedValue::HasProperty(thread, JSHandle<JSTaggedValue>(thread, parent), key);
124 }
125 return false;
126 }
127
128 // 9.4.5.3 [[DefineOwnProperty]] ( P, Desc )
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)129 bool JSTypedArray::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
130 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
131 {
132 // 1. Assert: IsPropertyKey(P) is true.
133 ASSERT(JSTaggedValue::IsPropertyKey(key));
134 // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
135 // 3. If Type(P) is String, then
136 // a. Let numericIndex be CanonicalNumericIndexString (P).
137 // b. Assert: numericIndex is not an abrupt completion.
138 // c. If numericIndex is not undefined, then
139 JSHandle<JSObject> typedarrayObj(typedarray);
140 if (key->IsString()) {
141 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
142 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
143 if (!numericIndex.IsUndefined()) {
144 // i. If IsInteger(numericIndex) is false, return false
145 // ii. Let intIndex be numericIndex.
146 // iii. If intIndex = −0, return false.
147 // iv. If intIndex < 0, return false.
148 // v. Let length be the value of O’s [[ArrayLength]] internal slot.
149 // vi. If intIndex ≥ length, return false.
150 // vii. If IsAccessorDescriptor(Desc) is true, return false.
151 // viii. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is true, return false.
152 // ix. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]] is false, return false.
153 // x. If Desc has a [[Writable]] field and if Desc.[[Writable]] is false, return false.
154 // xi. If Desc has a [[Value]] field, then
155 // 1. Let value be Desc.[[Value]].
156 // 2. Return IntegerIndexedElementSet (O, intIndex, value).
157 // xii. Return true.
158 if (!numericIndex.IsInteger()) {
159 return false;
160 }
161 JSHandle<JSTaggedValue> numericIndexHandle(thread, numericIndex);
162 JSTaggedNumber numericIndexNumber = JSTaggedValue::ToNumber(thread, numericIndexHandle);
163 double tNegZero = -0.0;
164 auto eZero = JSTaggedNumber(tNegZero);
165 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
166 if (JSTaggedNumber::SameValue(numericIndexNumber, eZero)) {
167 return false;
168 }
169 if (JSTaggedValue::Less(thread, numericIndexHandle, zero)) {
170 return false;
171 }
172 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
173 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
174 if (!JSTaggedValue::Less(thread, numericIndexHandle, arrLenHandle)) {
175 return false;
176 }
177 if (desc.IsAccessorDescriptor()) {
178 return false;
179 }
180 if (desc.HasConfigurable() && !desc.IsConfigurable()) {
181 return false;
182 }
183 if (desc.HasEnumerable() && !desc.IsEnumerable()) {
184 return false;
185 }
186 if (desc.HasWritable() && !desc.IsWritable()) {
187 return false;
188 }
189 if (desc.HasValue()) {
190 JSHandle<JSTaggedValue> value = desc.GetValue();
191 return (JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value));
192 }
193 return true;
194 }
195 }
196 // 4. Return OrdinaryDefineOwnProperty(O, P, Desc).
197 return JSObject::OrdinaryDefineOwnProperty(thread, typedarrayObj, key, desc);
198 }
199
200 // 9.4.5.4 [[Get]] ( P, Receiver )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)201 OperationResult JSTypedArray::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
202 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
203 {
204 // 1. Assert : IsPropertyKey(P) is true.
205 ASSERT(JSTaggedValue::IsPropertyKey(key));
206 // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
207 if (key->IsString() && JSTaggedValue::SameValue(typedarray, receiver)) {
208 // a. Let numericIndex be CanonicalNumericIndexString (P).
209 // b. Assert: numericIndex is not an abrupt completion.
210 // c. If numericIndex is not undefined, then
211 // i. Return IntegerIndexedElementGet (O, numericIndex).
212 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
213 RETURN_VALUE_IF_ABRUPT_COMPLETION(
214 thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
215 if (!numericIndex.IsUndefined()) {
216 return JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex);
217 }
218 }
219
220 // 3. Return the result of calling the default ordinary object [[Get]] internal method (9.1.8) on O
221 // passing P and Receiver as arguments.
222 return JSObject::GetProperty(thread, typedarray, key, receiver);
223 }
224
225 // 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)226 bool JSTypedArray::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
227 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
228 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
229 {
230 // 1. Assert : IsPropertyKey(P) is true.
231 ASSERT(JSTaggedValue::IsPropertyKey(key));
232 // 2. If Type(P) is String and if SameValue(O, Receiver) is true, then
233 if (key->IsString() && JSTaggedValue::SameValue(typedarray, receiver)) {
234 // a. Let numericIndex be CanonicalNumericIndexString (P).
235 // b. Assert: numericIndex is not an abrupt completion.
236 // c. If numericIndex is not undefined, then
237 // i. Return IntegerIndexedElementSet (O, numericIndex, V).
238 JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key);
239 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
240 if (!numericIndex.IsUndefined()) {
241 return JSTypedArray::IntegerIndexedElementSet(thread, typedarray, numericIndex, value);
242 }
243 }
244 // 3. Return the result of calling the default ordinary object [[Set]] internal method (9.1.8) on O passing
245 // P, V, and Receiver as arguments.
246 return JSObject::SetProperty(thread, typedarray, key, value, receiver, mayThrow);
247 }
248
249 // 9.4.5.6 [[OwnPropertyKeys]] ( )
OwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray)250 JSHandle<TaggedArray> JSTypedArray::OwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray)
251 {
252 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
253 // 1. Let keys be a new empty List.
254 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
255 // [[TypedArrayName]] internal slots.
256 // 3. Let len be the value of O’s [[ArrayLength]] internal slot.
257 JSHandle<JSObject> arrayObj(typedarray);
258 JSHandle<TaggedArray> objKeys = JSObject::GetOwnPropertyKeys(thread, arrayObj);
259 uint32_t objKeysLen = objKeys->GetLength();
260 uint32_t bufferKeysLen = TypedArrayHelper::GetArrayLength(thread, arrayObj);
261 uint32_t length = objKeysLen + bufferKeysLen;
262 JSHandle<TaggedArray> nameList = factory->NewTaggedArray(length);
263
264 // 4. For each integer i starting with 0 such that i < len, in ascending order,
265 // a. Add ToString(i) as the last element of keys.
266 uint32_t copyLength = 0;
267 JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
268 for (uint32_t k = 0; k < bufferKeysLen; k++) {
269 tKey.Update(JSTaggedValue(k));
270 JSHandle<JSTaggedValue> sKey(JSTaggedValue::ToString(thread, tKey));
271 nameList->Set(thread, copyLength, sKey.GetTaggedValue());
272 copyLength++;
273 }
274
275 // 5. For each own property key P of O such that Type(P) is String and P is not an integer index, in
276 // property creation order
277 // a. Add P as the last element of keys.
278 for (uint32_t i = 0; i < objKeysLen; i++) {
279 JSTaggedValue key = objKeys->Get(i);
280 if (JSTaggedValue(key).IsString()) {
281 nameList->Set(thread, copyLength, key);
282 copyLength++;
283 }
284 }
285
286 // 6. For each own property key P of O such that Type(P) is Symbol, in property creation order
287 // a. Add P as the last element of keys.
288 for (uint32_t i = 0; i < objKeysLen; i++) {
289 JSTaggedValue key = objKeys->Get(i);
290 if (JSTaggedValue(key).IsSymbol()) {
291 nameList->Set(thread, copyLength, key);
292 copyLength++;
293 }
294 }
295
296 // 7. Return keys.
297 return factory->CopyArray(nameList, length, copyLength);
298 }
299
300 // 9.4.5.7 IntegerIndexedObjectCreate (prototype, internalSlotsList)
301
302 // 9.4.5.8 IntegerIndexedElementGet ( O, index )
IntegerIndexedElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index)303 OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
304 JSTaggedValue index)
305 {
306 // 1. Assert: Type(index) is Number.
307 ASSERT(index.IsNumber());
308 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
309 // [[TypedArrayName]] internal slots.
310 ASSERT(typedarray->IsTypedArray());
311 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
312 JSHandle<JSObject> typedarrayObj(typedarray);
313 JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer();
314 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
315 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
316 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
317 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
318 }
319 // 5. If IsInteger(index) is false, return undefined
320 if (!index.IsInteger()) {
321 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
322 }
323
324 // 6. If index = −0, return undefined.
325 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
326 // 8. If index < 0 or index ≥ length, return undefined.
327 JSHandle<JSTaggedValue> indexHandle(thread, index);
328 JSTaggedNumber indexNumber = JSTaggedValue::ToNumber(thread, indexHandle);
329 double tNegZero = -0.0;
330 auto eZero = JSTaggedNumber(tNegZero);
331 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
332 if (JSTaggedNumber::SameValue(indexNumber, eZero)) {
333 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
334 }
335 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
336 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
337 if (JSTaggedValue::Less(thread, indexHandle, zero) || !JSTaggedValue::Less(thread, indexHandle, arrLenHandle)) {
338 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
339 }
340 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
341 int32_t offset = TypedArrayHelper::GetByteOffset(thread, typedarrayObj);
342 // 10. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
343 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for
344 // arrayTypeName.
345 int32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
346 // 12. Let indexedPosition = (index × elementSize) + offset.
347 int32_t k = JSTaggedValue::ToInteger(thread, indexHandle).ToInt32();
348 int32_t byteIndex = k * elementSize + offset;
349 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
350 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
351 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
352 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(buffer, byteIndex, elementType, true);
353 return OperationResult(thread, result, PropertyMetaData(true));
354 }
355
356 // static
FastCopyElementToArray(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<TaggedArray> & array)357 bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
358 JSHandle<TaggedArray> &array)
359 {
360 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
361 // [[TypedArrayName]] internal slots.
362 ASSERT(typedArray->IsTypedArray());
363 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
364 JSHandle<JSObject> typedarrayObj(typedArray);
365 JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer();
366 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
367 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
368 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
369 }
370
371 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
372 // 8. If index < 0 or index ≥ length, return undefined.
373 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
374 if (arrLen < 0) {
375 return false;
376 }
377
378 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
379 int32_t offset = TypedArrayHelper::GetByteOffset(thread, typedarrayObj);
380 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
381 int32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
382 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
383 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
384 for (int index = 0; index < arrLen; index++) {
385 // 12. Let indexedPosition = (index × elementSize) + offset.
386 int32_t byteIndex = index * elementSize + offset;
387 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
388 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(buffer, byteIndex, elementType, true);
389 array->Set(thread, index, result);
390 }
391 return true;
392 }
393
394 // static
FastElementGet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,uint32_t index)395 OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
396 uint32_t index)
397 {
398 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
399 // [[TypedArrayName]] internal slots.
400 ASSERT(typedarray->IsTypedArray());
401 // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
402 JSHandle<JSObject> typedarrayObj(typedarray);
403 JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer();
404 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
405 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
406 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
407 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
408 }
409
410 // 7. Let length be the value of O’s [[ArrayLength]] internal slot.
411 // 8. If index < 0 or index ≥ length, return undefined.
412 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
413 if (arrLen < 0 || index >= static_cast<uint32_t>(arrLen)) {
414 return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
415 }
416 // 9. Let offset be the value of O’s [[ByteOffset]] internal slot.
417 int32_t offset = TypedArrayHelper::GetByteOffset(thread, typedarrayObj);
418 // 11. Let elementSize be the Number value of the Element Size value specified in Table 49 for arrayTypeName.
419 int32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
420 // 12. Let indexedPosition = (index × elementSize) + offset.
421 int32_t byteIndex = index * elementSize + offset;
422 // 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
423 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
424 // 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
425 JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(buffer, byteIndex, elementType, true);
426 return OperationResult(thread, result, PropertyMetaData(true));
427 }
428
429 // 9.4.5.9 IntegerIndexedElementSet ( O, index, value )
IntegerIndexedElementSet(JSThread * thread,const JSHandle<JSTaggedValue> & typedarray,JSTaggedValue index,const JSHandle<JSTaggedValue> & value)430 bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandle<JSTaggedValue> &typedarray,
431 JSTaggedValue index, const JSHandle<JSTaggedValue> &value)
432 {
433 // 1. Assert: Type(index) is Number.
434 ASSERT(index.IsNumber());
435 // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and
436 // [[TypedArrayName]] internal slots.
437 ASSERT(typedarray->IsTypedArray());
438 // 3. Let numValue be ToNumber(value).
439 JSTaggedNumber numVal = JSTaggedValue::ToNumber(thread, value);
440 // 4. ReturnIfAbrupt(numValue).
441 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
442
443 // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
444 JSHandle<JSObject> typedarrayObj(typedarray);
445 JSTaggedValue buffer = JSTypedArray::Cast(*typedarrayObj)->GetViewedArrayBuffer();
446 // 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
447 if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
448 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
449 }
450 // 7. If IsInteger(index) is false, return false
451 if (!index.IsInteger()) {
452 return false;
453 }
454
455 // 8. If index = −0, return false.
456 // 9. Let length be the value of O’s [[ArrayLength]] internal slot.
457 // 10. If index < 0 or index ≥ length, return false.
458 JSHandle<JSTaggedValue> indexHandle(thread, index);
459 JSTaggedNumber indexNumber = JSTaggedValue::ToNumber(thread, indexHandle);
460 double tNegZero = -0.0;
461 auto eZero = JSTaggedNumber(tNegZero);
462 JSHandle<JSTaggedValue> zero(thread, JSTaggedValue(0));
463 if (JSTaggedNumber::SameValue(indexNumber, eZero)) {
464 return false;
465 }
466 int32_t arrLen = TypedArrayHelper::GetArrayLength(thread, typedarrayObj);
467 JSHandle<JSTaggedValue> arrLenHandle(thread, JSTaggedValue(arrLen));
468 if (JSTaggedValue::Less(thread, indexHandle, zero) || !JSTaggedValue::Less(thread, indexHandle, arrLenHandle)) {
469 return false;
470 }
471
472 // 11. Let offset be the value of O’s [[ByteOffset]] internal slot.
473 int32_t offset = TypedArrayHelper::GetByteOffset(thread, typedarrayObj);
474 // 12. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot.
475 // 13. Let elementSize be the Number value of the Element Size value specified in Table 49 for
476 // arrayTypeName.
477 int32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj);
478 // 14. Let indexedPosition = (index × elementSize) + offset.
479 int32_t k = JSTaggedValue::ToInteger(thread, indexHandle).ToInt32();
480 int32_t byteIndex = k * elementSize + offset;
481 // 15. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
482 DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
483 // 16. Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
484 BuiltinsArrayBuffer::SetValueInBuffer(buffer, byteIndex, elementType, numVal, true);
485 // 17. Return true.
486 return true;
487 }
488 } // namespace panda::ecmascript
489