瀏覽代碼

LibWeb: Move serialize_* methods outside scope of Serializer class

These methods are useful independent of the class Serializer, so let's
move their declarations to the header file and and outside the scope of
the Serializer class.
Kenneth Myhra 1 年之前
父節點
當前提交
dcf5ff5178
共有 2 個文件被更改,包括 149 次插入136 次删除
  1. 138 136
      Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp
  2. 11 0
      Userland/Libraries/LibWeb/HTML/StructuredSerialize.h

+ 138 - 136
Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright (c) 2022, Daniel Ehrenberg <dan@littledan.dev>
  * Copyright (c) 2022, Daniel Ehrenberg <dan@littledan.dev>
  * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
  * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
- * Copyright (c) 2023, Kenneth Myhra <kennethmyhra@serenityos.org>
+ * Copyright (c) 2023-2024, Kenneth Myhra <kennethmyhra@serenityos.org>
  * Copyright (c) 2023, Idan Horowitz <idan.horowitz@serenityos.org>
  * Copyright (c) 2023, Idan Horowitz <idan.horowitz@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
@@ -170,10 +170,10 @@ public:
         } else if (value.is_bigint()) {
         } else if (value.is_bigint()) {
             m_serialized.append(ValueTag::BigIntPrimitive);
             m_serialized.append(ValueTag::BigIntPrimitive);
             auto& val = value.as_bigint();
             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()) {
         } else if (value.is_string()) {
             m_serialized.append(ValueTag::StringPrimitive);
             m_serialized.append(ValueTag::StringPrimitive);
-            TRY(serialize_string(m_serialized, value.as_string()));
+            TRY(serialize_string(m_vm, m_serialized, value.as_string()));
         } else {
         } else {
             return_primitive_type = false;
             return_primitive_type = false;
         }
         }
@@ -206,14 +206,14 @@ public:
         else if (value.is_object() && is<JS::BigIntObject>(value.as_object())) {
         else if (value.is_object() && is<JS::BigIntObject>(value.as_object())) {
             m_serialized.append(ValueTag::BigIntObject);
             m_serialized.append(ValueTag::BigIntObject);
             auto& bigint_object = static_cast<JS::BigIntObject&>(value.as_object());
             auto& bigint_object = static_cast<JS::BigIntObject&>(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]] }.
         // 10. Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.
         else if (value.is_object() && is<JS::StringObject>(value.as_object())) {
         else if (value.is_object() && is<JS::StringObject>(value.as_object())) {
             m_serialized.append(ValueTag::StringObject);
             m_serialized.append(ValueTag::StringObject);
             auto& string_object = static_cast<JS::StringObject&>(value.as_object());
             auto& string_object = static_cast<JS::StringObject&>(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]] }.
         // 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<ECMA262> object is perfectly happy to be reconstructed with just the source+flags
             // Note: A Regex<ECMA262> 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
             //       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)
             //       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:
         // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
         else if (value.is_object() && is<JS::ArrayBuffer>(value.as_object())) {
         else if (value.is_object() && is<JS::ArrayBuffer>(value.as_object())) {
-            TRY(serialize_array_buffer(m_serialized, static_cast<JS::ArrayBuffer&>(value.as_object())));
+            TRY(serialize_array_buffer(m_vm, m_serialized, static_cast<JS::ArrayBuffer&>(value.as_object()), m_for_storage));
         }
         }
 
 
         // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
         // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
         else if (value.is_object() && is<JS::TypedArrayBase>(value.as_object())) {
         else if (value.is_object() && is<JS::TypedArrayBase>(value.as_object())) {
-            TRY(serialize_viewed_array_buffer(m_serialized, static_cast<JS::TypedArrayBase&>(value.as_object())));
+            TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast<JS::TypedArrayBase&>(value.as_object()), m_for_storage, m_memory));
         } else if (value.is_object() && is<JS::DataView>(value.as_object())) {
         } else if (value.is_object() && is<JS::DataView>(value.as_object())) {
-            TRY(serialize_viewed_array_buffer(m_serialized, static_cast<JS::DataView&>(value.as_object())));
+            TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast<JS::DataView&>(value.as_object()), m_for_storage, m_memory));
         }
         }
 
 
         // 15. Otherwise, if value has [[MapData]] internal slot, then:
         // 15. Otherwise, if value has [[MapData]] internal slot, then:
@@ -291,7 +291,7 @@ public:
             m_serialized.append(type);
             m_serialized.append(type);
             m_serialized.append(message.has_value());
             m_serialized.append(message.has_value());
             if (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:
         // 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));
                         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]].
                         // 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);
                         m_serialized.extend(output_value);
 
 
                         property_count++;
                         property_count++;
@@ -427,155 +427,157 @@ private:
     u32 m_next_id { 0 };
     u32 m_next_id { 0 };
     SerializationRecord m_serialized;
     SerializationRecord m_serialized;
     bool m_for_storage { false };
     bool m_for_storage { false };
+};
 
 
-    WebIDL::ExceptionOr<void> serialize_bytes(Vector<u32>& 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<u32*>(&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));
+WebIDL::ExceptionOr<void> serialize_bytes(JS::VM& vm, Vector<u32>& 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<u32*>(&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;
         }
         }
-        return {};
+        TRY_OR_THROW_OOM(vm, vector.try_append(combined_value));
     }
     }
+    return {};
+}
 
 
-    WebIDL::ExceptionOr<void> serialize_string(Vector<u32>& vector, DeprecatedFlyString const& string)
-    {
-        return serialize_bytes(vector, string.view().bytes());
-    }
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, DeprecatedFlyString const& string)
+{
+    return serialize_bytes(vm, vector, string.view().bytes());
+}
 
 
-    WebIDL::ExceptionOr<void> serialize_string(Vector<u32>& vector, String const& string)
-    {
-        return serialize_bytes(vector, { string.code_points().bytes(), string.code_points().byte_length() });
-    }
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, String const& string)
+{
+    return serialize_bytes(vm, vector, { string.code_points().bytes(), string.code_points().byte_length() });
+}
 
 
-    WebIDL::ExceptionOr<void> serialize_string(Vector<u32>& vector, JS::PrimitiveString const& primitive_string)
-    {
-        auto string = primitive_string.utf8_string();
-        TRY(serialize_string(vector, string));
-        return {};
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, JS::PrimitiveString const& primitive_string)
+{
+    auto string = primitive_string.utf8_string();
+    TRY(serialize_string(vm, vector, string));
+    return {};
+}
+
+WebIDL::ExceptionOr<void> serialize_array_buffer(JS::VM& vm, Vector<u32>& 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);
 
 
-    WebIDL::ExceptionOr<void> serialize_array_buffer(Vector<u32>& vector, JS::ArrayBuffer const& array_buffer)
-    {
-        // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
+        // 2. Let size be value.[[ArrayBufferByteLength]].
+        auto size = array_buffer.byte_length();
 
 
-        // FIXME: 1.  If IsSharedArrayBuffer(value) is true, then:
+        // 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) {
         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:
+        // 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
         else {
         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()));
-            }
+            vector.append(ValueTag::ArrayBuffer);
+            TRY(serialize_bytes(vm, vector, data_copy.buffer().bytes()));
         }
         }
-        return {};
     }
     }
+    return {};
+}
 
 
-    template<OneOf<JS::TypedArrayBase, JS::DataView> ViewType>
-    WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(Vector<u32>& vector, ViewType const& view)
-    {
-        // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
-
-        auto view_record = [&]() {
-            if constexpr (IsSame<ViewType, JS::DataView>) {
-                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);
-            }
-        }();
+template<OneOf<JS::TypedArrayBase, JS::DataView> ViewType>
+WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>& vector, ViewType const& view, bool for_storage, SerializationMemory& memory)
+{
+    // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
 
 
-        // 1. If IsArrayBufferViewOutOfBounds(value) is true, then throw a "DataCloneError" DOMException.
+    auto view_record = [&]() {
         if constexpr (IsSame<ViewType, JS::DataView>) {
         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)));
+            return JS::make_data_view_with_buffer_witness_record(view, JS::ArrayBuffer::Order::SeqCst);
         } else {
         } 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)));
+            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<ViewType, JS::DataView>) {
+        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();
+    // 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));
+    // 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);
+    // 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<ViewType, JS::DataView>) {
-            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());
-        }
+    // 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<ViewType, JS::DataView>) {
+        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(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 {};
+    // 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<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>& vector, JS::TypedArrayBase const& view, bool for_storage, SerializationMemory& memory);
+template WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>& vector, JS::DataView const& view, bool for_storage, SerializationMemory& memory);
 
 
 class Deserializer {
 class Deserializer {
 public:
 public:

+ 11 - 0
Userland/Libraries/LibWeb/HTML/StructuredSerialize.h

@@ -1,6 +1,7 @@
 /*
 /*
  * Copyright (c) 2022, Daniel Ehrenberg <dan@littledan.dev>
  * Copyright (c) 2022, Daniel Ehrenberg <dan@littledan.dev>
  * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
  * Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
+ * Copyright (c) 2024, Kenneth Myhra <kennethmyhra@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
@@ -12,6 +13,8 @@
 #include <AK/Vector.h>
 #include <AK/Vector.h>
 #include <LibIPC/Forward.h>
 #include <LibIPC/Forward.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Forward.h>
+#include <LibJS/Runtime/DataView.h>
+#include <LibJS/Runtime/TypedArray.h>
 #include <LibWeb/WebIDL/ExceptionOr.h>
 #include <LibWeb/WebIDL/ExceptionOr.h>
 
 
 // Structured serialize is an entirely different format from IPC because:
 // Structured serialize is an entirely different format from IPC because:
@@ -50,6 +53,14 @@ WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& v
 
 
 WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<DeserializationMemory>);
 WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<DeserializationMemory>);
 
 
+WebIDL::ExceptionOr<void> serialize_bytes(JS::VM& vm, Vector<u32>& vector, ReadonlyBytes bytes);
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, DeprecatedFlyString const& string);
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, String const& string);
+WebIDL::ExceptionOr<void> serialize_string(JS::VM& vm, Vector<u32>& vector, JS::PrimitiveString const& primitive_string);
+WebIDL::ExceptionOr<void> serialize_array_buffer(JS::VM& vm, Vector<u32>& vector, JS::ArrayBuffer const& array_buffer, bool for_storage);
+template<OneOf<JS::TypedArrayBase, JS::DataView> ViewType>
+WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>& vector, ViewType const& view, bool for_storage, SerializationMemory& memory);
+
 WebIDL::ExceptionOr<ByteBuffer> deserialize_bytes(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);
 WebIDL::ExceptionOr<ByteBuffer> deserialize_bytes(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);
 WebIDL::ExceptionOr<String> deserialize_string(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);
 WebIDL::ExceptionOr<String> deserialize_string(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);
 WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::PrimitiveString>> deserialize_string_primitive(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);
 WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::PrimitiveString>> deserialize_string_primitive(JS::VM& vm, ReadonlySpan<u32> vector, size_t& position);