Jelajahi Sumber

LibWeb: Make StructuredSerialize/Deserialize friendlier to recursion

Make the internal calls take objects by reference, and take writable
spans into data rather than const& to the underlying vector type.
Andrew Kaster 1 tahun lalu
induk
melakukan
bddf3fbf2d

+ 34 - 16
Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp

@@ -26,6 +26,8 @@
 
 namespace Web::HTML {
 
+static WebIDL::ExceptionOr<JS::Value> structured_deserialize_impl(JS::VM& vm, ReadonlySpan<u32> serialized, JS::Realm& target_realm, SerializationMemory& memory);
+
 // Binary format:
 // A list of adjacent shallow values, which may contain references to other
 // values (noted by their position in the list, one value following another).
@@ -309,11 +311,13 @@ private:
 
 class Deserializer {
 public:
-    Deserializer(JS::VM& vm, JS::Realm& target_realm, SerializationRecord const& v)
+    Deserializer(JS::VM& vm, JS::Realm& target_realm, ReadonlySpan<u32> v, SerializationMemory& serialization_memory)
         : m_vm(vm)
         , m_vector(v)
         , m_memory(target_realm.heap())
+        , m_serialization_memory(serialization_memory)
     {
+        VERIFY(vm.current_realm() == &target_realm);
     }
 
     WebIDL::ExceptionOr<void> deserialize()
@@ -417,11 +421,12 @@ public:
 
 private:
     JS::VM& m_vm;
-    SerializationRecord const& m_vector;
+    ReadonlySpan<u32> m_vector;
     JS::MarkedVector<JS::Value> m_memory; // Index -> JS value
     Optional<FlyString> m_error;
+    SerializationMemory& m_serialization_memory;
 
-    static WebIDL::ExceptionOr<ByteBuffer> deserialize_bytes(JS::VM& vm, Vector<u32> const& vector, u32& position)
+    static WebIDL::ExceptionOr<ByteBuffer> deserialize_bytes(JS::VM& vm, ReadonlySpan<u32> vector, u32& position)
     {
         u32 size_bits[2];
         size_bits[0] = vector[position++];
@@ -441,7 +446,13 @@ private:
         return bytes;
     }
 
-    static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::PrimitiveString>> deserialize_string_primitive(JS::VM& vm, Vector<u32> const& vector, u32& position)
+    static WebIDL::ExceptionOr<String> deserialize_string(JS::VM& vm, ReadonlySpan<u32> vector, u32& position)
+    {
+        auto bytes = TRY(deserialize_bytes(vm, vector, position));
+        return TRY_OR_THROW_OOM(vm, String::from_utf8(StringView { bytes }));
+    }
+
+    static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::PrimitiveString>> deserialize_string_primitive(JS::VM& vm, ReadonlySpan<u32> vector, u32& position)
     {
         auto bytes = TRY(deserialize_bytes(vm, vector, position));
 
@@ -450,7 +461,7 @@ private:
         }));
     }
 
-    static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::BigInt>> deserialize_big_int_primitive(JS::VM& vm, Vector<u32> const& vector, u32& position)
+    static WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::BigInt>> deserialize_big_int_primitive(JS::VM& vm, ReadonlySpan<u32> vector, u32& position)
     {
         auto string = TRY(deserialize_string_primitive(vm, vector, position));
         auto string_view = TRY(Bindings::throw_dom_exception_if_needed(vm, [&string]() {
@@ -464,36 +475,43 @@ private:
 WebIDL::ExceptionOr<SerializationRecord> structured_serialize(JS::VM& vm, JS::Value value)
 {
     // 1. Return ? StructuredSerializeInternal(value, false).
-    return structured_serialize_internal(vm, value, false, {});
+    SerializationMemory memory = {};
+    return structured_serialize_internal(vm, value, false, memory);
 }
 
 // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeforstorage
 WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(JS::VM& vm, JS::Value value)
 {
     // 1. Return ? StructuredSerializeInternal(value, true).
-    return structured_serialize_internal(vm, value, true, {});
+    SerializationMemory memory = {};
+    return structured_serialize_internal(vm, value, true, memory);
 }
 
 // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal
-WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value value, bool for_storage, Optional<SerializationMemory> memory)
+WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value value, bool for_storage, SerializationMemory& memory)
 {
     // 1. If memory was not supplied, let memory be an empty map.
-    if (!memory.has_value())
-        memory = SerializationMemory {};
+    // IMPLEMENTATION DEFINED: We move this requirement up to the callers to make recursion easier
 
-    Serializer serializer(vm, *memory, for_storage);
+    Serializer serializer(vm, memory, for_storage);
     return serializer.serialize(value);
 }
 
-// https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize
-WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<SerializationMemory> memory)
+WebIDL::ExceptionOr<JS::Value> structured_deserialize_impl(JS::VM& vm, ReadonlySpan<u32> serialized, JS::Realm& target_realm, SerializationMemory& memory)
 {
     // FIXME: Do the spec steps
-    (void)memory;
-
-    Deserializer deserializer(vm, target_realm, serialized);
+    Deserializer deserializer(vm, target_realm, serialized, memory);
     TRY(deserializer.deserialize());
     return deserializer.result();
 }
 
+// https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize
+WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<SerializationMemory> memory)
+{
+    if (!memory.has_value())
+        memory = SerializationMemory {};
+
+    return structured_deserialize_impl(vm, serialized.span(), target_realm, *memory);
+}
+
 }

+ 1 - 1
Userland/Libraries/LibWeb/HTML/StructuredSerialize.h

@@ -29,7 +29,7 @@ using SerializationMemory = HashMap<JS::Handle<JS::Value>, SerializationRange>;
 
 WebIDL::ExceptionOr<SerializationRecord> structured_serialize(JS::VM& vm, JS::Value);
 WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(JS::VM& vm, JS::Value);
-WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value, bool for_storage, Optional<SerializationMemory>);
+WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value, bool for_storage, SerializationMemory&);
 
 WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<SerializationMemory>);