diff --git a/ecmascript/js_typed_array.cpp b/ecmascript/js_typed_array.cpp index fea0aa5d8195e095b8f98b02ec099a55273835cc..79c1bd059337fe5eadac31f8430a5dc8f2f073bf 100644 --- a/ecmascript/js_typed_array.cpp +++ b/ecmascript/js_typed_array.cpp @@ -209,19 +209,31 @@ OperationResult JSTypedArray::GetProperty(JSThread *thread, const JSHandleIsString() || key->IsNumber()) && JSTaggedValue::SameValue(thread, typedarray, receiver)) { - // a. Let numericIndex be CanonicalNumericIndexString (P). - // b. Assert: numericIndex is not an abrupt completion. - // c. If numericIndex is not undefined, then - // i. Return IntegerIndexedElementGet (O, numericIndex). - JSTaggedValue numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key); - RETURN_VALUE_IF_ABRUPT_COMPLETION( - thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); - if (!numericIndex.IsUndefined()) { - return JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex); + JSTaggedValue numericIndex = JSTaggedValue::Undefined(); + if (key->IsString()) { + if (JSTaggedValue::SameValue(thread, typedarray, receiver)) { + // a. Let numericIndex be CanonicalNumericIndexString (P). + // b. Assert: numericIndex is not an abrupt completion. + // c. If numericIndex is not undefined, then + // i. Return IntegerIndexedElementGet (O, numericIndex, V). + numericIndex = JSTaggedValue::CanonicalNumericIndexString(thread, key); + RETURN_VALUE_IF_ABRUPT_COMPLETION( + thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); + if (!numericIndex.IsUndefined()) { + return JSTypedArray::IntegerIndexedElementGet(thread, typedarray, numericIndex); + } + } + } else if (key->IsNumber()) { + if (JSTaggedValue::SameValue(thread, typedarray, receiver)) { + // a. Let numericIndex be key. + // b. If numericIndex is not undefined, then + // i. Return IntegerIndexedElementGetForNum (O, numericIndex, V). + numericIndex = key.GetTaggedValue(); + if (!numericIndex.IsUndefined()) { + return JSTypedArray::IntegerIndexedElementGetForNum(thread, typedarray, numericIndex); + } } } - // 3. Return the result of calling the default ordinary object [[Get]] internal method (9.1.8) on O // passing P and Receiver as arguments. return JSObject::GetProperty(thread, typedarray, key, receiver); @@ -431,6 +443,67 @@ OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const J return OperationResult(thread, result, PropertyMetaData(true)); } +// The difference between IntegerIndexedElementGetForNum and IntegerIndexedElementGetForNum is +// The detection of -0.0 returns undefined. +OperationResult JSTypedArray::IntegerIndexedElementGetForNum(JSThread *thread, const JSHandle &typedarray, + JSTaggedValue index) +{ + // 1. Assert: Type(index) is Number. + ASSERT(index.IsNumber()); + // 2. Assert: O is an Object that has [[ViewedArrayBuffer]], [[ArrayLength]], [[ByteOffset]], and + // [[TypedArrayName]] internal slots. + ASSERT(typedarray->IsTypedArray() || typedarray->IsSharedTypedArray()); + // 3. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + JSHandle typedarrayObj(typedarray); + JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray(thread); + // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) { + if (index == JSTaggedValue(0)) { + return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true)); + } + THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", + OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); + } + if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(thread, buffer)) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", + OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); + } + // 5. If IsInteger(index) is false, return undefined + if (!index.IsInteger()) { + return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true)); + } + + // 6. Let length be the value of O’s [[ArrayLength]] internal slot. + // 7. If index < 0 or index ≥ length, return undefined. + JSHandle indexHandle(thread, index); + JSTaggedNumber indexNumber = JSTaggedValue::ToNumber(thread, indexHandle); + RETURN_VALUE_IF_ABRUPT_COMPLETION( + thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); + JSHandle zero(thread, JSTaggedValue(0)); + uint32_t arrLen = typedarrayObj->GetArrayLength(); + JSHandle arrLenHandle(thread, JSTaggedValue(arrLen)); + if (JSTaggedValue::Less(thread, indexHandle, zero) || !JSTaggedValue::Less(thread, indexHandle, arrLenHandle)) { + return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true)); + } + // 8. Let offset be the value of O’s [[ByteOffset]] internal slot. + uint32_t offset = typedarrayObj->GetByteOffset(); + // 9. Let arrayTypeName be the String value of O’s [[TypedArrayName]] internal slot. + // 10. Let elementSize be the Number value of the Element Size value specified in Table 49 for + // arrayTypeName. + uint32_t elementSize = TypedArrayHelper::GetElementSize(typedarrayObj); + // 11. Let indexedPosition = (index × elementSize) + offset. + JSTaggedNumber integerValue = JSTaggedValue::ToInteger(thread, indexHandle); + RETURN_VALUE_IF_ABRUPT_COMPLETION( + thread, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false))); + uint32_t k = static_cast(integerValue.ToInt32()); + uint32_t byteIndex = k * elementSize + offset; + // 12. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName. + DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj); + // 13. Return GetValueFromBuffer(buffer, indexedPosition, elementType). + JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true); + return OperationResult(thread, result, PropertyMetaData(true)); +} + // s12 10.4.5.9 IsValidIntegerIndex ( O, index ) bool JSTypedArray::IsValidIntegerIndex(JSThread *thread, const JSHandle &typedArray, JSTaggedValue index) { diff --git a/ecmascript/js_typed_array.h b/ecmascript/js_typed_array.h index c2e196c438902ca551c01b81bc1458b3f3a2c496..61f5a5b734533768d7fe8b488d3133f8f371a3ac 100644 --- a/ecmascript/js_typed_array.h +++ b/ecmascript/js_typed_array.h @@ -85,6 +85,8 @@ public: // 9.4.5.8 IntegerIndexedElementGet ( O, index ) static OperationResult IntegerIndexedElementGet(JSThread *thread, const JSHandle &typedarray, JSTaggedValue index); + static OperationResult IntegerIndexedElementGetForNum(JSThread *thread, const JSHandle &typedarray, + JSTaggedValue index); static OperationResult FastElementGet(JSThread *thread, const JSHandle &typedarray, uint32_t index); static bool FastCopyElementToArray(JSThread *thread, const JSHandle &typedArray, JSHandle &array); diff --git a/test/moduletest/typearray/typearray.js b/test/moduletest/typearray/typearray.js index e460d20fc2b034146343200ae7de98b3a78f6ee9..cd1d1aa28747807d4d4293ec8153e92ec6a2ce6b 100644 --- a/test/moduletest/typearray/typearray.js +++ b/test/moduletest/typearray/typearray.js @@ -1689,4 +1689,11 @@ assert_equal(typedArrEleAssertLengthRes,typedArrEleAssertLengthEqual); assert_equal(Number.isNaN(v2[0]), false); } +{ + for (let i = 0; i <= 100000; ++i) { } + let typedArray = new Float32Array(3) + typedArray[0] = 6; + assert_equal(typedArray[-0.0], 6); +} + test_end(); \ No newline at end of file