mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 17:47:36 +00:00
LibJS+LibWeb: Implement resizable ArrayBuffer support for TypedArray
This is (part of) a normative change in the ECMA-262 spec. See:
a9ae96e
This commit is contained in:
parent
c7fec9424c
commit
9258d7b98a
47 changed files with 2059 additions and 884 deletions
|
@ -49,13 +49,17 @@ WebIDL::ExceptionOr<JS::Handle<WebIDL::ArrayBufferView>> Crypto::get_random_valu
|
|||
if (!array->is_typed_array_base())
|
||||
return WebIDL::TypeMismatchError::create(realm(), "array must be one of Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, or BigUint64Array"_fly_string);
|
||||
|
||||
auto const& typed_array = *array->bufferable_object().get<JS::NonnullGCPtr<JS::TypedArrayBase>>();
|
||||
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(typed_array, JS::ArrayBuffer::Order::SeqCst);
|
||||
|
||||
// IMPLEMENTATION DEFINED: If the viewed array buffer is out-of-bounds, throw a InvalidStateError and terminate the algorithm.
|
||||
if (JS::is_typed_array_out_of_bounds(typed_array_record))
|
||||
return WebIDL::InvalidStateError::create(realm(), MUST(String::formatted(JS::ErrorType::BufferOutOfBounds.message(), "TypedArray"sv)));
|
||||
|
||||
// 2. If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
|
||||
if (array->viewed_array_buffer()->byte_length() > 65536)
|
||||
if (JS::typed_array_byte_length(typed_array_record) > 65536)
|
||||
return WebIDL::QuotaExceededError::create(realm(), "array's byteLength may not be greater than 65536"_fly_string);
|
||||
|
||||
// IMPLEMENTATION DEFINED: If the viewed array buffer is detached, throw a InvalidStateError and terminate the algorithm.
|
||||
if (array->viewed_array_buffer()->is_detached())
|
||||
return WebIDL::InvalidStateError::create(realm(), "array is detached"_fly_string);
|
||||
// FIXME: Handle SharedArrayBuffers
|
||||
|
||||
// 3. Overwrite all elements of array with cryptographically strong random values of the appropriate type.
|
||||
|
|
|
@ -526,9 +526,7 @@ private:
|
|||
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;
|
||||
return JS::make_typed_array_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
|
||||
}
|
||||
}();
|
||||
|
||||
|
@ -537,7 +535,8 @@ private:
|
|||
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.
|
||||
if (JS::is_typed_array_out_of_bounds(view_record))
|
||||
return WebIDL::DataCloneError::create(*m_vm.current_realm(), MUST(String::formatted(JS::ErrorType::BufferOutOfBounds.message(), "TypedArray"sv)));
|
||||
}
|
||||
|
||||
// 2. Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.
|
||||
|
@ -570,9 +569,9 @@ private:
|
|||
vector.append(ValueTag::ArrayBufferView);
|
||||
vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
|
||||
TRY(serialize_string(vector, view.element_name())); // [[Constructor]]
|
||||
vector.append(view.byte_length());
|
||||
vector.append(JS::typed_array_byte_length(view_record));
|
||||
vector.append(view.byte_offset());
|
||||
vector.append(view.array_length());
|
||||
vector.append(JS::typed_array_length(view_record));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -2041,14 +2041,17 @@ WebIDL::ExceptionOr<void> readable_byte_stream_controller_enqueue(ReadableByteSt
|
|||
// 4. Let byteOffset be chunk.[[ByteOffset]].
|
||||
auto byte_offset = typed_array->byte_offset();
|
||||
|
||||
// 5. Let byteLength be chunk.[[ByteLength]].
|
||||
auto byte_length = typed_array->byte_length();
|
||||
|
||||
// 6. If ! IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (buffer->is_detached()) {
|
||||
auto error = JS::TypeError::create(realm, "Buffer is detached"sv);
|
||||
return JS::throw_completion(error);
|
||||
}
|
||||
// FIXME: The streams spec has not been updated for resizable ArrayBuffer objects. We must perform step 6 before
|
||||
// invoking TypedArrayByteLength in step 5. We also must check if the array is out-of-bounds, rather than
|
||||
// just detached.
|
||||
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(*typed_array, JS::ArrayBuffer::Order::SeqCst);
|
||||
|
||||
if (JS::is_typed_array_out_of_bounds(typed_array_record))
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::BufferOutOfBounds, "TypedArray"sv);
|
||||
|
||||
// 5. Let byteLength be chunk.[[ByteLength]].
|
||||
auto byte_length = JS::typed_array_byte_length(typed_array_record);
|
||||
|
||||
// 7. Let transferredBuffer be ? TransferArrayBuffer(buffer).
|
||||
auto transferred_buffer = TRY(transfer_array_buffer(realm, *buffer));
|
||||
|
|
|
@ -309,7 +309,12 @@ JS::ThrowCompletionOr<size_t> parse_module(JS::VM& vm, JS::Object* buffer_object
|
|||
data = buffer.buffer();
|
||||
} else if (is<JS::TypedArrayBase>(buffer_object)) {
|
||||
auto& buffer = static_cast<JS::TypedArrayBase&>(*buffer_object);
|
||||
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), buffer.byte_length());
|
||||
|
||||
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(buffer, JS::ArrayBuffer::Order::SeqCst);
|
||||
if (JS::is_typed_array_out_of_bounds(typed_array_record))
|
||||
return vm.throw_completion<JS::TypeError>(JS::ErrorType::BufferOutOfBounds, "TypedArray"sv);
|
||||
|
||||
data = buffer.viewed_array_buffer()->buffer().span().slice(buffer.byte_offset(), JS::typed_array_byte_length(typed_array_record));
|
||||
} else if (is<JS::DataView>(buffer_object)) {
|
||||
auto& buffer = static_cast<JS::DataView&>(*buffer_object);
|
||||
|
||||
|
|
|
@ -38,6 +38,12 @@ ErrorOr<ByteBuffer> get_buffer_source_copy(JS::Object const& buffer_source)
|
|||
if (is<JS::TypedArrayBase>(buffer_source)) {
|
||||
auto const& es_buffer_source = static_cast<JS::TypedArrayBase const&>(buffer_source);
|
||||
|
||||
auto typed_array_record = JS::make_typed_array_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_typed_array_out_of_bounds(typed_array_record))
|
||||
return ByteBuffer {};
|
||||
|
||||
// 1. Set esArrayBuffer to esBufferSource.[[ViewedArrayBuffer]].
|
||||
es_array_buffer = es_buffer_source.viewed_array_buffer();
|
||||
|
||||
|
@ -45,7 +51,7 @@ 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::typed_array_byte_length(typed_array_record);
|
||||
} else if (is<JS::DataView>(buffer_source)) {
|
||||
auto const& es_buffer_source = static_cast<JS::DataView const&>(buffer_source);
|
||||
|
||||
|
|
|
@ -13,7 +13,16 @@ namespace Web::WebIDL {
|
|||
|
||||
u32 BufferableObjectBase::byte_length() const
|
||||
{
|
||||
return m_bufferable_object.visit([](auto& obj) { return static_cast<u32>(obj->byte_length()); });
|
||||
return m_bufferable_object.visit(
|
||||
[](JS::NonnullGCPtr<JS::TypedArrayBase> typed_array) {
|
||||
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(typed_array, JS::ArrayBuffer::Order::SeqCst);
|
||||
return JS::typed_array_byte_length(typed_array_record);
|
||||
},
|
||||
[](JS::NonnullGCPtr<JS::DataView> data_view) {
|
||||
auto view_record = JS::make_data_view_with_buffer_witness_record(data_view, JS::ArrayBuffer::Order::SeqCst);
|
||||
return JS::get_view_byte_length(view_record);
|
||||
},
|
||||
[](JS::NonnullGCPtr<JS::ArrayBuffer> array_buffer) { return static_cast<u32>(array_buffer->byte_length()); });
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<JS::Object> BufferableObjectBase::raw_object()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue