diff options
author | Luke <luke.wilde@live.co.uk> | 2021-06-17 00:45:31 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-17 02:20:03 +0100 |
commit | 9c2eff8859a73e47a784beada75b2c2fedf4167f (patch) | |
tree | e25535e9e998068ee0ad36e99c640279220d5e6e | |
parent | 80edf6f5b62f3ff8bfa198943a09e08769cd6ff9 (diff) | |
download | serenity-9c2eff8859a73e47a784beada75b2c2fedf4167f.zip |
LibJS: Make TypedArray use numeric_to_raw_bytes and raw_bytes_to_numeric
It was previously writing directly to the underlying buffer instead of
using these methods. This has a benefit of dealing with BigInt64 and
BigUint64 for us already.
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/TypedArray.h | 92 |
1 files changed, 55 insertions, 37 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.h b/Userland/Libraries/LibJS/Runtime/TypedArray.h index c38b01c644..18b076d361 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.h +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.h @@ -51,51 +51,53 @@ class TypedArray : public TypedArrayBase { using UnderlyingBufferDataType = Conditional<IsSame<ClampedU8, T>, u8, T>; public: + // 10.4.5.11 IntegerIndexedElementSet ( O, index, value ), https://tc39.es/ecma262/#sec-integerindexedelementset + // NOTE: In error cases, the function will return as if it succeeded. virtual bool put_by_index(u32 property_index, Value value) override { - if (property_index >= m_array_length) - return Base::put_by_index(property_index, value); - - if constexpr (sizeof(UnderlyingBufferDataType) < 4) { - auto number = value.to_i32(global_object()); - if (vm().exception()) - return {}; - if constexpr (IsSame<T, ClampedU8>) - number = clamp(number, 0, 255); - data()[property_index] = number; - } else if constexpr (sizeof(UnderlyingBufferDataType) == 4 || sizeof(UnderlyingBufferDataType) == 8) { - auto number = value.to_double(global_object()); - if (vm().exception()) - return {}; - data()[property_index] = number; - } else { - static_assert(DependentFalse<T>, "TypedArray::put_by_index with unhandled type size"); + // FIXME: If O.[[ContentType]] is BigInt, let numValue be ? ToBigInt(value). + // Otherwise, let numValue be ? ToNumber(value). + // (set_value currently takes value by itself) + + if (!is_valid_integer_index(property_index)) + return true; + + auto offset = byte_offset(); + + // FIXME: Not exactly sure what we should do when overflow occurs. + // Just return as if it succeeded for now. + Checked<size_t> indexed_position = property_index; + indexed_position *= sizeof(UnderlyingBufferDataType); + indexed_position += offset; + if (indexed_position.has_overflow()) { + dbgln("TypedArray::put_by_index: indexed_position overflowed, returning as if succeeded."); + return true; } + + viewed_array_buffer()->template set_value<T>(indexed_position.value(), value, true, ArrayBuffer::Order::Unordered); + return true; } - virtual Value get_by_index(u32 property_index, bool without_side_effects = false) const override + // 10.4.5.10 IntegerIndexedElementGet ( O, index ), https://tc39.es/ecma262/#sec-integerindexedelementget + virtual Value get_by_index(u32 property_index, [[maybe_unused]] bool without_side_effects = false) const override { - if (property_index >= m_array_length) - return Base::get_by_index(property_index, without_side_effects); - - if constexpr (sizeof(UnderlyingBufferDataType) < 4) { - return Value((i32)data()[property_index]); - } else if constexpr (sizeof(UnderlyingBufferDataType) == 4 || sizeof(UnderlyingBufferDataType) == 8) { - auto value = data()[property_index]; - if constexpr (IsFloatingPoint<UnderlyingBufferDataType>) { - return Value((double)value); - } else if constexpr (NumericLimits<UnderlyingBufferDataType>::is_signed()) { - if (value > NumericLimits<i32>::max() || value < NumericLimits<i32>::min()) - return Value((double)value); - } else { - if (value > NumericLimits<i32>::max()) - return Value((double)value); - } - return Value((i32)value); - } else { - static_assert(DependentFalse<T>, "TypedArray::get_by_index with unhandled type size"); + if (!is_valid_integer_index(property_index)) + return js_undefined(); + + auto offset = byte_offset(); + + // FIXME: Not exactly sure what we should do when overflow occurs. + // Just return as if it's an invalid index for now. + Checked<size_t> indexed_position = property_index; + indexed_position *= sizeof(UnderlyingBufferDataType); + indexed_position += offset; + if (indexed_position.has_overflow()) { + dbgln("TypedArray::get_by_index: indexed_position overflowed, returning as if it's an invalid index."); + return js_undefined(); } + + return viewed_array_buffer()->template get_value<T>(indexed_position.value(), true, ArrayBuffer::Order::Unordered); } Span<const UnderlyingBufferDataType> data() const @@ -123,6 +125,22 @@ protected: private: virtual bool is_typed_array() const final { return true; } + + // 10.4.5.9 IsValidIntegerIndex ( O, index ), https://tc39.es/ecma262/#sec-isvalidintegerindex + bool is_valid_integer_index(u32 property_index) const + { + if (viewed_array_buffer()->is_detached()) + return false; + + // FIXME: If ! IsIntegralNumber(index) is false, return false. + + // FIXME: If index is -0𝔽, return false. + + if (property_index >= m_array_length /* FIXME: or less than 0 (index is currently unsigned) */) + return false; + + return true; + } }; #define JS_DECLARE_TYPED_ARRAY(ClassName, snake_name, PrototypeName, ConstructorName, Type) \ |