1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 19:57:44 +00:00

LibJS+LibWeb: Implement resizable ArrayBuffer support for DataView

This is (part of) a normative change in the ECMA-262 spec. See:
a9ae96e
This commit is contained in:
Timothy Flynn 2023-10-15 09:46:09 -04:00 committed by Andreas Kling
parent 29ac6e3689
commit c7fec9424c
12 changed files with 377 additions and 94 deletions

View file

@ -522,7 +522,23 @@ private:
{
// 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
// FIXME: 1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.
auto view_record = [&]() {
if constexpr (IsSame<ViewType, JS::DataView>) {
return JS::make_data_view_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
} else {
// FIXME: Create a TypedArray record when TypedArray supports resizable ArrayBuffer objects.
TODO();
return 0;
}
}();
// 1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.
if constexpr (IsSame<ViewType, JS::DataView>) {
if (JS::is_view_out_of_bounds(view_record))
return WebIDL::DataCloneError::create(*m_vm.current_realm(), MUST(String::formatted(JS::ErrorType::BufferOutOfBounds.message(), "DataView"sv)));
} else {
// FIXME: Check TypedArray bounds when TypedArray supports resizable ArrayBuffer objects.
}
// 2. Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.
auto* buffer = view.viewed_array_buffer();
@ -540,7 +556,7 @@ private:
vector.append(ValueTag::ArrayBufferView);
vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
TRY(serialize_string(vector, "DataView"_string)); // [[Constructor]]
vector.append(view.byte_length());
vector.append(JS::get_view_byte_length(view_record));
vector.append(view.byte_offset());
}

View file

@ -312,7 +312,12 @@ JS::ThrowCompletionOr<size_t> parse_module(JS::VM& vm, JS::Object* buffer_object
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length());
} else if (is<JS::DataView>(buffer_object)) {
auto& buffer = static_cast<JS::DataView&>(*buffer_object);
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length());
auto view_record = JS::make_data_view_with_buffer_witness_record(buffer, JS::ArrayBuffer::Order::SeqCst);
if (JS::is_view_out_of_bounds(view_record))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::BufferOutOfBounds, "DataView"sv);
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), JS::get_view_byte_length(view_record));
} else {
return vm.throw_completion<JS::TypeError>("Not a BufferSource"sv);
}

View file

@ -49,6 +49,12 @@ ErrorOr<ByteBuffer> get_buffer_source_copy(JS::Object const& buffer_source)
} else if (is<JS::DataView>(buffer_source)) {
auto const& es_buffer_source = static_cast<JS::DataView const&>(buffer_source);
auto view_record = JS::make_data_view_with_buffer_witness_record(es_buffer_source, JS::ArrayBuffer::Order::SeqCst);
// AD-HOC: The WebIDL spec has not been updated for resizable ArrayBuffer objects. This check follows the behavior of step 7.
if (JS::is_view_out_of_bounds(view_record))
return ByteBuffer {};
// 1. Set esArrayBuffer to esBufferSource.[[ViewedArrayBuffer]].
es_array_buffer = es_buffer_source.viewed_array_buffer();
@ -56,13 +62,13 @@ ErrorOr<ByteBuffer> get_buffer_source_copy(JS::Object const& buffer_source)
offset = es_buffer_source.byte_offset();
// 3. Set length to esBufferSource.[[ByteLength]].
length = es_buffer_source.byte_length();
length = JS::get_view_byte_length(view_record);
}
// 6. Otherwise:
else {
// 1. Assert: esBufferSource is an ArrayBuffer or SharedArrayBuffer object.
auto const& es_buffer_source = static_cast<JS::ArrayBuffer const&>(buffer_source);
es_array_buffer = &const_cast<JS ::ArrayBuffer&>(es_buffer_source);
es_array_buffer = &const_cast<JS::ArrayBuffer&>(es_buffer_source);
// 2. Set length to esBufferSource.[[ArrayBufferByteLength]].
length = es_buffer_source.byte_length();