LibWeb: Add and use serialize_enum()

This commit is contained in:
Kenneth Myhra 2024-03-15 21:32:51 +01:00 committed by Andreas Kling
commit 49d7719a04
Notes: sideshowbarker 2024-07-17 23:07:41 +09:00
2 changed files with 32 additions and 25 deletions

View file

@ -168,20 +168,20 @@ public:
bool return_primitive_type = true; bool return_primitive_type = true;
// 4. If Type(value) is Undefined, Null, Boolean, Number, BigInt, or String, then return { [[Type]]: "primitive", [[Value]]: value }. // 4. If Type(value) is Undefined, Null, Boolean, Number, BigInt, or String, then return { [[Type]]: "primitive", [[Value]]: value }.
if (value.is_undefined()) { if (value.is_undefined()) {
m_serialized.append(ValueTag::UndefinedPrimitive); serialize_enum(m_serialized, ValueTag::UndefinedPrimitive);
} else if (value.is_null()) { } else if (value.is_null()) {
m_serialized.append(ValueTag::NullPrimitive); serialize_enum(m_serialized, ValueTag::NullPrimitive);
} else if (value.is_boolean()) { } else if (value.is_boolean()) {
m_serialized.append(ValueTag::BooleanPrimitive); serialize_enum(m_serialized, ValueTag::BooleanPrimitive);
serialize_boolean_primitive(m_serialized, value); serialize_boolean_primitive(m_serialized, value);
} else if (value.is_number()) { } else if (value.is_number()) {
m_serialized.append(ValueTag::NumberPrimitive); serialize_enum(m_serialized, ValueTag::NumberPrimitive);
serialize_number_primitive(m_serialized, value); serialize_number_primitive(m_serialized, value);
} else if (value.is_bigint()) { } else if (value.is_bigint()) {
m_serialized.append(ValueTag::BigIntPrimitive); serialize_enum(m_serialized, ValueTag::BigIntPrimitive);
TRY(serialize_big_int_primitive(m_vm, m_serialized, value)); TRY(serialize_big_int_primitive(m_vm, m_serialized, value));
} else if (value.is_string()) { } else if (value.is_string()) {
m_serialized.append(ValueTag::StringPrimitive); serialize_enum(m_serialized, ValueTag::StringPrimitive);
TRY(serialize_string_primitive(m_vm, m_serialized, value)); TRY(serialize_string_primitive(m_vm, m_serialized, value));
} else { } else {
return_primitive_type = false; return_primitive_type = false;
@ -198,31 +198,31 @@ public:
// 7. If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }. // 7. If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.
if (value.is_object() && is<JS::BooleanObject>(value.as_object())) { if (value.is_object() && is<JS::BooleanObject>(value.as_object())) {
m_serialized.append(ValueTag::BooleanObject); serialize_enum(m_serialized, ValueTag::BooleanObject);
serialize_boolean_object(m_serialized, value); serialize_boolean_object(m_serialized, value);
} }
// 8. Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }. // 8. Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.
else if (value.is_object() && is<JS::NumberObject>(value.as_object())) { else if (value.is_object() && is<JS::NumberObject>(value.as_object())) {
m_serialized.append(ValueTag::NumberObject); serialize_enum(m_serialized, ValueTag::NumberObject);
serialize_number_object(m_serialized, value); serialize_number_object(m_serialized, value);
} }
// 9. Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }. // 9. Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }.
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); serialize_enum(m_serialized, ValueTag::BigIntObject);
TRY(serialize_big_int_object(m_vm, m_serialized, value)); TRY(serialize_big_int_object(m_vm, m_serialized, value));
} }
// 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); serialize_enum(m_serialized, ValueTag::StringObject);
TRY(serialize_string_object(m_vm, m_serialized, value)); TRY(serialize_string_object(m_vm, m_serialized, value));
} }
// 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]] }.
else if (value.is_object() && is<JS::Date>(value.as_object())) { else if (value.is_object() && is<JS::Date>(value.as_object())) {
m_serialized.append(ValueTag::DateObject); serialize_enum(m_serialized, ValueTag::DateObject);
serialize_date_object(m_serialized, value); serialize_date_object(m_serialized, value);
} }
@ -230,7 +230,7 @@ public:
// { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]], // { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]],
// [[OriginalFlags]]: value.[[OriginalFlags]] }. // [[OriginalFlags]]: value.[[OriginalFlags]] }.
else if (value.is_object() && is<JS::RegExpObject>(value.as_object())) { else if (value.is_object() && is<JS::RegExpObject>(value.as_object())) {
m_serialized.append(ValueTag::RegExpObject); serialize_enum(m_serialized, ValueTag::RegExpObject);
TRY(serialize_reg_exp_object(m_vm, m_serialized, value)); TRY(serialize_reg_exp_object(m_vm, m_serialized, value));
} }
@ -249,7 +249,7 @@ public:
// 15. Otherwise, if value has [[MapData]] internal slot, then: // 15. Otherwise, if value has [[MapData]] internal slot, then:
else if (value.is_object() && is<JS::Map>(value.as_object())) { else if (value.is_object() && is<JS::Map>(value.as_object())) {
// 1. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }. // 1. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.
m_serialized.append(ValueTag::MapObject); serialize_enum(m_serialized, ValueTag::MapObject);
// 2. Set deep to true. // 2. Set deep to true.
deep = true; deep = true;
} }
@ -257,7 +257,7 @@ public:
// 16. Otherwise, if value has [[SetData]] internal slot, then: // 16. Otherwise, if value has [[SetData]] internal slot, then:
else if (value.is_object() && is<JS::Set>(value.as_object())) { else if (value.is_object() && is<JS::Set>(value.as_object())) {
// 1. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }. // 1. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.
m_serialized.append(ValueTag::SetObject); serialize_enum(m_serialized, ValueTag::SetObject);
// 2. Set deep to true. // 2. Set deep to true.
deep = true; deep = true;
} }
@ -284,8 +284,8 @@ public:
// 5. Set serialized to { [[Type]]: "Error", [[Name]]: name, [[Message]]: message }. // 5. Set serialized to { [[Type]]: "Error", [[Name]]: name, [[Message]]: message }.
// FIXME: 6. User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized. // FIXME: 6. User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized.
m_serialized.append(ValueTag::ErrorObject); serialize_enum(m_serialized, ValueTag::ErrorObject);
m_serialized.append(type); serialize_enum(m_serialized, type);
serialize_primitive_type(m_serialized, message.has_value()); serialize_primitive_type(m_serialized, message.has_value());
if (message.has_value()) if (message.has_value())
TRY(serialize_string(m_vm, m_serialized, *message)); TRY(serialize_string(m_vm, m_serialized, *message));
@ -299,7 +299,7 @@ public:
u64 length = MUST(JS::length_of_array_like(m_vm, value.as_object())); u64 length = MUST(JS::length_of_array_like(m_vm, value.as_object()));
// 3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }. // 3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }.
m_serialized.append(ValueTag::ArrayObject); serialize_enum(m_serialized, ValueTag::ArrayObject);
serialize_primitive_type(m_serialized, length); serialize_primitive_type(m_serialized, length);
// 4. Set deep to true. // 4. Set deep to true.
@ -310,7 +310,7 @@ public:
else if (value.is_object() && is<Bindings::Serializable>(value.as_object())) { else if (value.is_object() && is<Bindings::Serializable>(value.as_object())) {
auto& serializable = dynamic_cast<Bindings::Serializable&>(value.as_object()); auto& serializable = dynamic_cast<Bindings::Serializable&>(value.as_object());
m_serialized.append(ValueTag::SerializableObject); serialize_enum(m_serialized, ValueTag::SerializableObject);
TRY(serialize_string(m_vm, m_serialized, serializable.interface_name())); TRY(serialize_string(m_vm, m_serialized, serializable.interface_name()));
@ -335,7 +335,7 @@ public:
// 24. Otherwise: // 24. Otherwise:
else { else {
// 1. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }. // 1. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.
m_serialized.append(ValueTag::Object); serialize_enum(m_serialized, ValueTag::Object);
// 2. Set deep to true. // 2. Set deep to true.
deep = true; deep = true;
@ -593,7 +593,7 @@ WebIDL::ExceptionOr<void> serialize_array_buffer(JS::VM& vm, Vector<u32>& vector
} }
// 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }. // 6. Otherwise, set serialized to { [[Type]]: "ArrayBuffer", [[ArrayBufferData]]: dataCopy, [[ArrayBufferByteLength]]: size }.
else { else {
vector.append(ValueTag::ArrayBuffer); serialize_enum(vector, ValueTag::ArrayBuffer);
TRY(serialize_bytes(vm, vector, data_copy.buffer().bytes())); TRY(serialize_bytes(vm, vector, data_copy.buffer().bytes()));
} }
} }
@ -635,7 +635,7 @@ WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>&
// 5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView", // 5. If value has a [[DataView]] internal slot, then set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: "DataView",
// [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }. // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], [[ByteOffset]]: value.[[ByteOffset]] }.
if constexpr (IsSame<ViewType, JS::DataView>) { if constexpr (IsSame<ViewType, JS::DataView>) {
vector.append(ValueTag::ArrayBufferView); serialize_enum(vector, ValueTag::ArrayBufferView);
vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]] vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
TRY(serialize_string(vm, vector, "DataView"_string)); // [[Constructor]] TRY(serialize_string(vm, vector, "DataView"_string)); // [[Constructor]]
serialize_primitive_type(vector, JS::get_view_byte_length(view_record)); serialize_primitive_type(vector, JS::get_view_byte_length(view_record));
@ -649,7 +649,7 @@ WebIDL::ExceptionOr<void> serialize_viewed_array_buffer(JS::VM& vm, Vector<u32>&
// 2. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]], // 2. Set serialized to { [[Type]]: "ArrayBufferView", [[Constructor]]: value.[[TypedArrayName]],
// [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]], // [[ArrayBufferSerialized]]: bufferSerialized, [[ByteLength]]: value.[[ByteLength]],
// [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }. // [[ByteOffset]]: value.[[ByteOffset]], [[ArrayLength]]: value.[[ArrayLength]] }.
vector.append(ValueTag::ArrayBufferView); serialize_enum(vector, ValueTag::ArrayBufferView);
vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]] vector.extend(move(buffer_serialized)); // [[ArrayBufferSerialized]]
TRY(serialize_string(vm, vector, view.element_name())); // [[Constructor]] TRY(serialize_string(vm, vector, view.element_name())); // [[Constructor]]
serialize_primitive_type(vector, JS::typed_array_byte_length(view_record)); serialize_primitive_type(vector, JS::typed_array_byte_length(view_record));
@ -674,7 +674,7 @@ public:
// https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize // https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize
WebIDL::ExceptionOr<JS::Value> deserialize() WebIDL::ExceptionOr<JS::Value> deserialize()
{ {
auto tag = m_serialized[m_position++]; auto tag = deserialize_primitive_type<ValueTag>(m_serialized, m_position);
// 2. If memory[serialized] exists, then return memory[serialized]. // 2. If memory[serialized] exists, then return memory[serialized].
if (tag == ValueTag::ObjectReference) { if (tag == ValueTag::ObjectReference) {
@ -840,7 +840,7 @@ public:
// 21. Otherwise, if serialized.[[Type]] is "Error", then: // 21. Otherwise, if serialized.[[Type]] is "Error", then:
case ValueTag::ErrorObject: { case ValueTag::ErrorObject: {
auto& realm = *m_vm.current_realm(); auto& realm = *m_vm.current_realm();
auto type = static_cast<ErrorType>(m_serialized[m_position++]); auto type = deserialize_primitive_type<ErrorType>(m_serialized, m_position);
auto has_message = deserialize_primitive_type<bool>(m_serialized, m_position); auto has_message = deserialize_primitive_type<bool>(m_serialized, m_position);
if (has_message) { if (has_message) {
auto message = TRY(deserialize_string(m_vm, m_serialized, m_position)); auto message = TRY(deserialize_string(m_vm, m_serialized, m_position));

View file

@ -74,6 +74,13 @@ void serialize_primitive_type(SerializationRecord& serialized, T value)
serialized.append(bit_cast<u32*>(&value), sizeof(T) / 4); serialized.append(bit_cast<u32*>(&value), sizeof(T) / 4);
} }
template<typename T>
requires(IsEnum<T>)
void serialize_enum(SerializationRecord& serialized, T value)
{
serialize_primitive_type<UnderlyingType<T>>(serialized, to_underlying(value));
}
WebIDL::ExceptionOr<void> serialize_bytes(JS::VM& vm, Vector<u32>& vector, ReadonlyBytes bytes); 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, 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, String const& string);
@ -92,7 +99,7 @@ JS::NonnullGCPtr<JS::Date> deserialize_date_object(JS::Realm& realm, ReadonlySpa
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::RegExpObject>> deserialize_reg_exp_object(JS::Realm& realm, ReadonlySpan<u32> const& serialized, size_t& position); WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::RegExpObject>> deserialize_reg_exp_object(JS::Realm& realm, ReadonlySpan<u32> const& serialized, size_t& position);
template<typename T> template<typename T>
requires(IsIntegral<T> || IsFloatingPoint<T>) requires(IsIntegral<T> || IsFloatingPoint<T> || IsEnum<T>)
T deserialize_primitive_type(ReadonlySpan<u32> const& serialized, size_t& position) T deserialize_primitive_type(ReadonlySpan<u32> const& serialized, size_t& position)
{ {
T value; T value;