diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp
index 9b823ed519..5eb084058e 100644
--- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp
+++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2022, Daniel Ehrenberg
* Copyright (c) 2022, Andrew Kaster
- * Copyright (c) 2023, Kenneth Myhra
+ * Copyright (c) 2023-2024, Kenneth Myhra
* Copyright (c) 2023, Idan Horowitz
*
* SPDX-License-Identifier: BSD-2-Clause
@@ -170,10 +170,10 @@ public:
} else if (value.is_bigint()) {
m_serialized.append(ValueTag::BigIntPrimitive);
auto& val = value.as_bigint();
- TRY(serialize_string(m_serialized, TRY_OR_THROW_OOM(m_vm, val.to_string())));
+ TRY(serialize_string(m_vm, m_serialized, TRY_OR_THROW_OOM(m_vm, val.to_string())));
} else if (value.is_string()) {
m_serialized.append(ValueTag::StringPrimitive);
- TRY(serialize_string(m_serialized, value.as_string()));
+ TRY(serialize_string(m_vm, m_serialized, value.as_string()));
} else {
return_primitive_type = false;
}
@@ -206,14 +206,14 @@ public:
else if (value.is_object() && is(value.as_object())) {
m_serialized.append(ValueTag::BigIntObject);
auto& bigint_object = static_cast(value.as_object());
- TRY(serialize_string(m_serialized, TRY_OR_THROW_OOM(m_vm, bigint_object.bigint().to_string())));
+ TRY(serialize_string(m_vm, m_serialized, TRY_OR_THROW_OOM(m_vm, bigint_object.bigint().to_string())));
}
// 10. Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.
else if (value.is_object() && is(value.as_object())) {
m_serialized.append(ValueTag::StringObject);
auto& string_object = static_cast(value.as_object());
- TRY(serialize_string(m_serialized, string_object.primitive_string()));
+ TRY(serialize_string(m_vm, m_serialized, string_object.primitive_string()));
}
// 11. Otherwise, if value has a [[DateValue]] internal slot, then set serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.
@@ -233,20 +233,20 @@ public:
// Note: A Regex object is perfectly happy to be reconstructed with just the source+flags
// In the future, we could optimize the work being done on the deserialize step by serializing
// more of the internal state (the [[RegExpMatcher]] internal slot)
- TRY(serialize_string(m_serialized, TRY_OR_THROW_OOM(m_vm, String::from_byte_string(regexp_object.pattern()))));
- TRY(serialize_string(m_serialized, TRY_OR_THROW_OOM(m_vm, String::from_byte_string(regexp_object.flags()))));
+ TRY(serialize_string(m_vm, m_serialized, TRY_OR_THROW_OOM(m_vm, String::from_byte_string(regexp_object.pattern()))));
+ TRY(serialize_string(m_vm, m_serialized, TRY_OR_THROW_OOM(m_vm, String::from_byte_string(regexp_object.flags()))));
}
// 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_array_buffer(m_serialized, static_cast(value.as_object())));
+ TRY(serialize_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage));
}
// 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_viewed_array_buffer(m_serialized, static_cast(value.as_object())));
+ TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage, m_memory));
} else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_viewed_array_buffer(m_serialized, static_cast(value.as_object())));
+ TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage, m_memory));
}
// 15. Otherwise, if value has [[MapData]] internal slot, then:
@@ -291,7 +291,7 @@ public:
m_serialized.append(type);
m_serialized.append(message.has_value());
if (message.has_value())
- TRY(serialize_string(m_serialized, *message));
+ TRY(serialize_string(m_vm, m_serialized, *message));
}
// 18. Otherwise, if value is an Array exotic object, then:
@@ -407,7 +407,7 @@ public:
auto output_value = TRY(structured_serialize_internal(m_vm, input_value, m_for_storage, m_memory));
// 3. Append { [[Key]]: key, [[Value]]: outputValue } to serialized.[[Properties]].
- TRY(serialize_string(m_serialized, key.as_string()));
+ TRY(serialize_string(m_vm, m_serialized, key.as_string()));
m_serialized.extend(output_value);
property_count++;
@@ -427,156 +427,158 @@ private:
u32 m_next_id { 0 };
SerializationRecord m_serialized;
bool m_for_storage { false };
-
- WebIDL::ExceptionOr serialize_bytes(Vector& vector, ReadonlyBytes bytes)
- {
- // Append size of the buffer to the serialized structure.
- u64 const size = bytes.size();
- TRY_OR_THROW_OOM(m_vm, vector.try_append(bit_cast(&size), 2));
- // Append the bytes of the buffer to the serialized structure.
- u64 byte_position = 0;
- while (byte_position < size) {
- u32 combined_value = 0;
- for (u8 i = 0; i < 4; ++i) {
- u8 const byte = bytes[byte_position];
- combined_value |= byte << (i * 8);
- byte_position++;
- if (byte_position == size)
- break;
- }
- TRY_OR_THROW_OOM(m_vm, vector.try_append(combined_value));
- }
- return {};
- }
-
- WebIDL::ExceptionOr serialize_string(Vector& vector, DeprecatedFlyString const& string)
- {
- return serialize_bytes(vector, string.view().bytes());
- }
-
- WebIDL::ExceptionOr serialize_string(Vector& vector, String const& string)
- {
- return serialize_bytes(vector, { string.code_points().bytes(), string.code_points().byte_length() });
- }
-
- WebIDL::ExceptionOr serialize_string(Vector& vector, JS::PrimitiveString const& primitive_string)
- {
- auto string = primitive_string.utf8_string();
- TRY(serialize_string(vector, string));
- return {};
- }
-
- WebIDL::ExceptionOr serialize_array_buffer(Vector& vector, JS::ArrayBuffer const& array_buffer)
- {
- // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
-
- // FIXME: 1. If IsSharedArrayBuffer(value) is true, then:
- if (false) {
- // 1. If the current settings object's cross-origin isolated capability is false, then throw a "DataCloneError" DOMException.
- // NOTE: This check is only needed when serializing (and not when deserializing) as the cross-origin isolated capability cannot change
- // over time and a SharedArrayBuffer cannot leave an agent cluster.
- if (current_settings_object().cross_origin_isolated_capability() == CanUseCrossOriginIsolatedAPIs::No)
- return WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize SharedArrayBuffer when cross-origin isolated"_fly_string);
-
- // 2. If forStorage is true, then throw a "DataCloneError" DOMException.
- if (m_for_storage)
- return WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize SharedArrayBuffer for storage"_fly_string);
-
- // FIXME: 3. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "GrowableSharedArrayBuffer",
- // [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLengthData]]: value.[[ArrayBufferByteLengthData]],
- // [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.
- // FIXME: 4. Otherwise, set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]],
- // [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.
- }
- // 2. Otherwise:
- else {
- // 1. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.
- if (array_buffer.is_detached())
- return WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize detached ArrayBuffer"_fly_string);
-
- // 2. Let size be value.[[ArrayBufferByteLength]].
- auto size = array_buffer.byte_length();
-
- // 3. Let dataCopy be ? CreateByteDataBlock(size).
- // NOTE: This can throw a RangeError exception upon allocation failure.
- auto data_copy = TRY(JS::create_byte_data_block(m_vm, size));
-
- // 4. Perform CopyDataBlockBytes(dataCopy, 0, value.[[ArrayBufferData]], 0, size).
- JS::copy_data_block_bytes(data_copy.buffer(), 0, array_buffer.buffer(), 0, size);
-
- // FIXME: 5. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "ResizableArrayBuffer",
- // [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size, [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]] }.
- if (false) {
- }
- // 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
- else {
- vector.append(ValueTag::ArrayBuffer);
- TRY(serialize_bytes(vector, data_copy.buffer().bytes()));
- }
- }
- return {};
- }
-
- template ViewType>
- WebIDL::ExceptionOr serialize_viewed_array_buffer(Vector& vector, ViewType const& view)
- {
- // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
-
- auto view_record = [&]() {
- if constexpr (IsSame) {
- return JS::make_data_view_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
- } else {
- return JS::make_typed_array_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
- }
- }();
-
- // 1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.
- if constexpr (IsSame) {
- 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 {
- 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.
- auto* buffer = view.viewed_array_buffer();
-
- // 3. Let bufferSerialized be ? StructuredSerializeInternal(buffer, forStorage, memory).
- auto buffer_serialized = TRY(structured_serialize_internal(m_vm, JS::Value(buffer), m_for_storage, m_memory));
-
- // 4. Assert: bufferSerialized.[[Type]] is "ArrayBuffer", "ResizableArrayBuffer", "SharedArrayBuffer", or "GrowableSharedArrayBuffer".
- // NOTE: We currently only implement this for ArrayBuffer
- VERIFY(buffer_serialized[0] == ValueTag::ArrayBuffer);
-
- // 5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView",
- // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.
- if constexpr (IsSame) {
- vector.append(ValueTag::ArrayBufferView);
- vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
- TRY(serialize_string(vector, "DataView"_string)); // [[Constructor]]
- vector.append(JS::get_view_byte_length(view_record));
- vector.append(view.byte_offset());
- }
-
- // 6. Otherwise:
- else {
- // 1. Assert: value has a [[TypedArrayName]] internal slot.
- // NOTE: Handled by constexpr check and template constraints
- // 2. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]],
- // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]],
- // [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.
- vector.append(ValueTag::ArrayBufferView);
- vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
- TRY(serialize_string(vector, view.element_name())); // [[Constructor]]
- vector.append(JS::typed_array_byte_length(view_record));
- vector.append(view.byte_offset());
- vector.append(JS::typed_array_length(view_record));
- }
- return {};
- }
};
+WebIDL::ExceptionOr serialize_bytes(JS::VM& vm, Vector& vector, ReadonlyBytes bytes)
+{
+ // Append size of the buffer to the serialized structure.
+ u64 const size = bytes.size();
+ TRY_OR_THROW_OOM(vm, vector.try_append(bit_cast(&size), 2));
+ // Append the bytes of the buffer to the serialized structure.
+ u64 byte_position = 0;
+ while (byte_position < size) {
+ u32 combined_value = 0;
+ for (u8 i = 0; i < 4; ++i) {
+ u8 const byte = bytes[byte_position];
+ combined_value |= byte << (i * 8);
+ byte_position++;
+ if (byte_position == size)
+ break;
+ }
+ TRY_OR_THROW_OOM(vm, vector.try_append(combined_value));
+ }
+ return {};
+}
+
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, DeprecatedFlyString const& string)
+{
+ return serialize_bytes(vm, vector, string.view().bytes());
+}
+
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, String const& string)
+{
+ return serialize_bytes(vm, vector, { string.code_points().bytes(), string.code_points().byte_length() });
+}
+
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, JS::PrimitiveString const& primitive_string)
+{
+ auto string = primitive_string.utf8_string();
+ TRY(serialize_string(vm, vector, string));
+ return {};
+}
+
+WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector, JS::ArrayBuffer const& array_buffer, bool for_storage)
+{
+ // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
+
+ // FIXME: 1. If IsSharedArrayBuffer(value) is true, then:
+ if (false) {
+ // 1. If the current settings object's cross-origin isolated capability is false, then throw a "DataCloneError" DOMException.
+ // NOTE: This check is only needed when serializing (and not when deserializing) as the cross-origin isolated capability cannot change
+ // over time and a SharedArrayBuffer cannot leave an agent cluster.
+ if (current_settings_object().cross_origin_isolated_capability() == CanUseCrossOriginIsolatedAPIs::No)
+ return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot serialize SharedArrayBuffer when cross-origin isolated"_fly_string);
+
+ // 2. If forStorage is true, then throw a "DataCloneError" DOMException.
+ if (for_storage)
+ return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot serialize SharedArrayBuffer for storage"_fly_string);
+
+ // FIXME: 3. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "GrowableSharedArrayBuffer",
+ // [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLengthData]]: value.[[ArrayBufferByteLengthData]],
+ // [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.
+ // FIXME: 4. Otherwise, set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]],
+ // [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]], [[AgentCluster]]: the surrounding agent's agent cluster }.
+ }
+ // 2. Otherwise:
+ else {
+ // 1. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.
+ if (array_buffer.is_detached())
+ return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot serialize detached ArrayBuffer"_fly_string);
+
+ // 2. Let size be value.[[ArrayBufferByteLength]].
+ auto size = array_buffer.byte_length();
+
+ // 3. Let dataCopy be ? CreateByteDataBlock(size).
+ // NOTE: This can throw a RangeError exception upon allocation failure.
+ auto data_copy = TRY(JS::create_byte_data_block(vm, size));
+
+ // 4. Perform CopyDataBlockBytes(dataCopy, 0, value.[[ArrayBufferData]], 0, size).
+ JS::copy_data_block_bytes(data_copy.buffer(), 0, array_buffer.buffer(), 0, size);
+
+ // FIXME: 5. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "ResizableArrayBuffer",
+ // [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size, [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]] }.
+ if (false) {
+ }
+ // 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
+ else {
+ vector.append(ValueTag::ArrayBuffer);
+ TRY(serialize_bytes(vm, vector, data_copy.buffer().bytes()));
+ }
+ }
+ return {};
+}
+
+template ViewType>
+WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector, ViewType const& view, bool for_storage, SerializationMemory& memory)
+{
+ // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
+
+ auto view_record = [&]() {
+ if constexpr (IsSame) {
+ return JS::make_data_view_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
+ } else {
+ return JS::make_typed_array_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
+ }
+ }();
+
+ // 1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.
+ if constexpr (IsSame) {
+ if (JS::is_view_out_of_bounds(view_record))
+ return WebIDL::DataCloneError::create(*vm.current_realm(), MUST(String::formatted(JS::ErrorType::BufferOutOfBounds.message(), "DataView"sv)));
+ } else {
+ if (JS::is_typed_array_out_of_bounds(view_record))
+ return WebIDL::DataCloneError::create(*vm.current_realm(), MUST(String::formatted(JS::ErrorType::BufferOutOfBounds.message(), "TypedArray"sv)));
+ }
+
+ // 2. Let buffer be the value of value's [[ViewedArrayBuffer]] internal slot.
+ auto* buffer = view.viewed_array_buffer();
+
+ // 3. Let bufferSerialized be ? StructuredSerializeInternal(buffer, forStorage, memory).
+ auto buffer_serialized = TRY(structured_serialize_internal(vm, JS::Value(buffer), for_storage, memory));
+
+ // 4. Assert: bufferSerialized.[[Type]] is "ArrayBuffer", "ResizableArrayBuffer", "SharedArrayBuffer", or "GrowableSharedArrayBuffer".
+ // NOTE: We currently only implement this for ArrayBuffer
+ VERIFY(buffer_serialized[0] == ValueTag::ArrayBuffer);
+
+ // 5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView",
+ // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.
+ if constexpr (IsSame) {
+ vector.append(ValueTag::ArrayBufferView);
+ vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
+ TRY(serialize_string(vm, vector, "DataView"_string)); // [[Constructor]]
+ vector.append(JS::get_view_byte_length(view_record));
+ vector.append(view.byte_offset());
+ }
+
+ // 6. Otherwise:
+ else {
+ // 1. Assert: value has a [[TypedArrayName]] internal slot.
+ // NOTE: Handled by constexpr check and template constraints
+ // 2. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]],
+ // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]],
+ // [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.
+ vector.append(ValueTag::ArrayBufferView);
+ vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
+ TRY(serialize_string(vm, vector, view.element_name())); // [[Constructor]]
+ vector.append(JS::typed_array_byte_length(view_record));
+ vector.append(view.byte_offset());
+ vector.append(JS::typed_array_length(view_record));
+ }
+ return {};
+}
+template WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector, JS::TypedArrayBase const& view, bool for_storage, SerializationMemory& memory);
+template WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector, JS::DataView const& view, bool for_storage, SerializationMemory& memory);
+
class Deserializer {
public:
Deserializer(JS::VM& vm, JS::Realm& target_realm, ReadonlySpan serialized, DeserializationMemory& memory)
diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h
index bdf48c342d..0ffb13eb6e 100644
--- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h
+++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2022, Daniel Ehrenberg
* Copyright (c) 2022, Andrew Kaster
+ * Copyright (c) 2024, Kenneth Myhra
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -12,6 +13,8 @@
#include
#include
#include
+#include
+#include
#include
// Structured serialize is an entirely different format from IPC because:
@@ -50,6 +53,14 @@ WebIDL::ExceptionOr structured_serialize_internal(JS::VM& v
WebIDL::ExceptionOr structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional);
+WebIDL::ExceptionOr serialize_bytes(JS::VM& vm, Vector& vector, ReadonlyBytes bytes);
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, DeprecatedFlyString const& string);
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, String const& string);
+WebIDL::ExceptionOr serialize_string(JS::VM& vm, Vector& vector, JS::PrimitiveString const& primitive_string);
+WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector, JS::ArrayBuffer const& array_buffer, bool for_storage);
+template ViewType>
+WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector& vector, ViewType const& view, bool for_storage, SerializationMemory& memory);
+
WebIDL::ExceptionOr deserialize_bytes(JS::VM& vm, ReadonlySpan vector, size_t& position);
WebIDL::ExceptionOr deserialize_string(JS::VM& vm, ReadonlySpan vector, size_t& position);
WebIDL::ExceptionOr> deserialize_string_primitive(JS::VM& vm, ReadonlySpan vector, size_t& position);