diff --git a/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Libraries/LibWeb/HTML/StructuredSerialize.cpp
index 8ee29134f9f..765babe642d 100644
--- a/Libraries/LibWeb/HTML/StructuredSerialize.cpp
+++ b/Libraries/LibWeb/HTML/StructuredSerialize.cpp
@@ -567,8 +567,8 @@ WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector
{
// 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
- // FIXME: 1. If IsSharedArrayBuffer(value) is true, then:
- if (false) {
+ // 1. If IsSharedArrayBuffer(value) is true, then:
+ if (array_buffer.is_shared_array_buffer()) {
// 1. If the current principal 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.
@@ -579,12 +579,23 @@ WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector
if (for_storage)
return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot serialize SharedArrayBuffer for storage"_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 }.
+ if (!array_buffer.is_fixed_length()) {
+ // 3. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "GrowableSharedArrayBuffer",
+ // [[ArrayBufferData]]: value.[[ArrayBufferData]], [[ArrayBufferByteLengthData]]: value.[[ArrayBufferByteLengthData]],
+ // [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]],
+ // FIXME: [[AgentCluster]]: the surrounding agent's agent cluster }.
+ serialize_enum(vector, ValueTag::GrowableSharedArrayBuffer);
+ TRY(serialize_bytes(vm, vector, array_buffer.buffer().bytes()));
+ serialize_primitive_type(vector, array_buffer.max_byte_length());
+ } else {
+ // 4. Otherwise, set serialized to { [[Type]]: "SharedArrayBuffer", [[ArrayBufferData]]: value.[[ArrayBufferData]],
+ // [[ArrayBufferByteLength]]: value.[[ArrayBufferByteLength]],
+ // FIXME: [[AgentCluster]]: the surrounding agent's agent cluster }.
+ serialize_enum(vector, ValueTag::SharedArrayBuffer);
+ TRY(serialize_bytes(vm, vector, array_buffer.buffer().bytes()));
+ }
}
+
// 2. Otherwise:
else {
// 1. If IsDetachedBuffer(value) is true, then throw a "DataCloneError" DOMException.
@@ -601,9 +612,12 @@ WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector
// 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",
+ // 5. If value has an [[ArrayBufferMaxByteLength]] internal slot, then set serialized to { [[Type]]: "ResizableArrayBuffer",
// [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size, [[ArrayBufferMaxByteLength]]: value.[[ArrayBufferMaxByteLength]] }.
- if (false) {
+ if (!array_buffer.is_fixed_length()) {
+ serialize_enum(vector, ValueTag::ResizeableArrayBuffer);
+ TRY(serialize_bytes(vm, vector, data_copy.buffer().bytes()));
+ serialize_primitive_type(vector, array_buffer.max_byte_length());
}
// 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
else {
@@ -643,10 +657,13 @@ WebIDL::ExceptionOr serialize_viewed_array_buffer(JS::VM& vm, Vector&
auto buffer_serialized = TRY(structured_serialize_internal(vm, buffer, for_storage, memory));
// 4. Assert: bufferSerialized.[[Type]] is "ArrayBuffer", "ResizableArrayBuffer", "SharedArrayBuffer", or "GrowableSharedArrayBuffer".
- // NOTE: We currently only implement this for ArrayBuffer
// NOTE: Object reference + memory check is required when ArrayBuffer is transfered.
auto tag = buffer_serialized[0];
- VERIFY(tag == ValueTag::ArrayBuffer || (tag == ValueTag::ObjectReference && memory.contains(buffer)));
+ VERIFY(tag == ValueTag::ArrayBuffer
+ || tag == ValueTag::ResizeableArrayBuffer
+ || tag == ValueTag::SharedArrayBuffer
+ || tag == ValueTag::GrowableSharedArrayBuffer
+ || (tag == ValueTag::ObjectReference && memory.contains(buffer)));
// 5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView",
// [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.
@@ -776,8 +793,39 @@ public:
value = TRY(deserialize_reg_exp_object(*m_vm.current_realm(), m_serialized, m_position));
break;
}
- // FIXME: 12. Otherwise, if serialized.[[Type]] is "SharedArrayBuffer", then:
- // FIXME: 13. Otherwise, if serialized.[[Type]] is "GrowableSharedArrayBuffer", then:
+ // 12. Otherwise, if serialized.[[Type]] is "SharedArrayBuffer", then:
+ case ValueTag::SharedArrayBuffer: {
+ // FIXME: 1. If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then throw a "DataCloneError" DOMException.
+ // 2. Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]]
+ // and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].
+ auto* realm = m_vm.current_realm();
+ auto bytes_or_error = deserialize_bytes(m_vm, m_serialized, m_position);
+ if (bytes_or_error.is_error())
+ return WebIDL::DataCloneError::create(*realm, "out of memory"_string);
+ auto bytes = bytes_or_error.release_value();
+ JS::ArrayBuffer* buffer = TRY(JS::allocate_shared_array_buffer(m_vm, realm->intrinsics().array_buffer_constructor(), bytes.size()));
+ bytes.span().copy_to(buffer->buffer().span());
+ value = buffer;
+ break;
+ }
+ // 13. Otherwise, if serialized.[[Type]] is "GrowableSharedArrayBuffer", then:
+ case ValueTag::GrowableSharedArrayBuffer: {
+ // FIXME: 1. If targetRealm's corresponding agent cluster is not serialized.[[AgentCluster]], then throw a "DataCloneError" DOMException.
+ // 2. Otherwise, set value to a new SharedArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]],
+ // whose [[ArrayBufferByteLengthData]] internal slot value is serialized.[[ArrayBufferByteLengthData]],
+ // and whose [[ArrayBufferMaxByteLength]] internal slot value is serialized.[[ArrayBufferMaxByteLength]].
+ auto* realm = m_vm.current_realm();
+ auto bytes_or_error = deserialize_bytes(m_vm, m_serialized, m_position);
+ if (bytes_or_error.is_error())
+ return WebIDL::DataCloneError::create(*realm, "out of memory"_string);
+ size_t max_byte_length = deserialize_primitive_type(m_serialized, m_position);
+ auto bytes = bytes_or_error.release_value();
+ JS::ArrayBuffer* buffer = TRY(JS::allocate_shared_array_buffer(m_vm, realm->intrinsics().array_buffer_constructor(), bytes.size()));
+ bytes.span().copy_to(buffer->buffer().span());
+ buffer->set_max_byte_length(max_byte_length);
+ value = buffer;
+ break;
+ }
// 14. Otherwise, if serialized.[[Type]] is "ArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], and whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]].
case ValueTag::ArrayBuffer: {
auto* realm = m_vm.current_realm();
@@ -788,7 +836,19 @@ public:
value = JS::ArrayBuffer::create(*realm, bytes_or_error.release_value());
break;
}
- // FIXME: 15. Otherwise, if serialized.[[Type]] is "ResizableArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]], and whose [[ArrayBufferMaxByteLength]] internal slot value is a serialized.[[ArrayBufferMaxByteLength]].
+ // 15. Otherwise, if serialized.[[Type]] is "ResizableArrayBuffer", then set value to a new ArrayBuffer object in targetRealm whose [[ArrayBufferData]] internal slot value is serialized.[[ArrayBufferData]], whose [[ArrayBufferByteLength]] internal slot value is serialized.[[ArrayBufferByteLength]], and whose [[ArrayBufferMaxByteLength]] internal slot value is a serialized.[[ArrayBufferMaxByteLength]].
+ case ValueTag::ResizeableArrayBuffer: {
+ auto* realm = m_vm.current_realm();
+ // If this throws an exception, catch it, and then throw a "DataCloneError" DOMException.
+ auto bytes_or_error = deserialize_bytes(m_vm, m_serialized, m_position);
+ if (bytes_or_error.is_error())
+ return WebIDL::DataCloneError::create(*m_vm.current_realm(), "out of memory"_string);
+ size_t max_byte_length = deserialize_primitive_type(m_serialized, m_position);
+ auto buffer = JS::ArrayBuffer::create(*realm, bytes_or_error.release_value());
+ buffer->set_max_byte_length(max_byte_length);
+ value = buffer;
+ break;
+ }
// 16. Otherwise, if serialized.[[Type]] is "ArrayBufferView", then:
case ValueTag::ArrayBufferView: {
auto* realm = m_vm.current_realm();
diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.txt b/Tests/LibWeb/Text/expected/wpt-import/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.txt
index 996071f6794..cf819fd63e0 100644
--- a/Tests/LibWeb/Text/expected/wpt-import/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.txt
+++ b/Tests/LibWeb/Text/expected/wpt-import/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.txt
@@ -2,8 +2,8 @@ Harness status: OK
Found 150 tests
-133 Pass
-16 Fail
+134 Pass
+15 Fail
1 Optional Feature Unsupported
Pass primitive undefined
Pass primitive null
@@ -137,7 +137,7 @@ Pass ObjectPrototype must lose its exotic-ness when cloned
Pass Serializing a non-serializable platform object fails
Pass An object whose interface is deleted from the global must still deserialize
Pass A subclass instance will deserialize as its closest serializable superclass
-Fail Resizable ArrayBuffer
+Pass Resizable ArrayBuffer
Fail Growable SharedArrayBuffer
Pass Length-tracking TypedArray
Pass Length-tracking DataView