1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 07:45:07 +00:00

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.
This commit is contained in:
Andrew Kaster 2023-09-12 16:41:13 -06:00 committed by Andreas Kling
parent e0fe77d012
commit bddf3fbf2d
2 changed files with 35 additions and 17 deletions

View file

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

View file

@ -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(JS::VM& vm, JS::Value);
WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(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>); WebIDL::ExceptionOr<JS::Value> structured_deserialize(JS::VM& vm, SerializationRecord const& serialized, JS::Realm& target_realm, Optional<SerializationMemory>);