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