diff --git a/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Libraries/LibWeb/HTML/StructuredSerialize.cpp
index d91bfbb2633..bb913516716 100644
--- a/Libraries/LibWeb/HTML/StructuredSerialize.cpp
+++ b/Libraries/LibWeb/HTML/StructuredSerialize.cpp
@@ -224,152 +224,154 @@ public:
// 6. Let serialized be an uninitialized value.
- // 7. If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.
- if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::BooleanObject);
- serialize_boolean_object(m_serialized, value);
- }
+ if (value.is_object()) {
+ auto const& object = value.as_object();
- // 8. Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.
- else if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::NumberObject);
- serialize_number_object(m_serialized, value);
- }
+ // 7. If value has a [[BooleanData]] internal slot, then set serialized to { [[Type]]: "Boolean", [[BooleanData]]: value.[[BooleanData]] }.
+ if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::BooleanObject);
+ serialize_boolean_object(m_serialized, value);
+ }
- // 9. Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }.
- else if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::BigIntObject);
- TRY(serialize_big_int_object(m_vm, m_serialized, value));
- }
+ // 8. Otherwise, if value has a [[NumberData]] internal slot, then set serialized to { [[Type]]: "Number", [[NumberData]]: value.[[NumberData]] }.
+ else if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::NumberObject);
+ serialize_number_object(m_serialized, value);
+ }
- // 10. Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.
- else if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::StringObject);
- TRY(serialize_string_object(m_vm, m_serialized, value));
- }
+ // 9. Otherwise, if value has a [[BigIntData]] internal slot, then set serialized to { [[Type]]: "BigInt", [[BigIntData]]: value.[[BigIntData]] }.
+ else if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::BigIntObject);
+ TRY(serialize_big_int_object(m_vm, m_serialized, value));
+ }
- // 11. Otherwise, if value has a [[DateValue]] internal slot, then set serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.
- else if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::DateObject);
- serialize_date_object(m_serialized, value);
- }
+ // 10. Otherwise, if value has a [[StringData]] internal slot, then set serialized to { [[Type]]: "String", [[StringData]]: value.[[StringData]] }.
+ else if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::StringObject);
+ TRY(serialize_string_object(m_vm, m_serialized, value));
+ }
- // 12. Otherwise, if value has a [[RegExpMatcher]] internal slot, then set serialized to
- // { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]],
- // [[OriginalFlags]]: value.[[OriginalFlags]] }.
- else if (value.is_object() && is(value.as_object())) {
- serialize_enum(m_serialized, ValueTag::RegExpObject);
- TRY(serialize_reg_exp_object(m_vm, m_serialized, value));
- }
+ // 11. Otherwise, if value has a [[DateValue]] internal slot, then set serialized to { [[Type]]: "Date", [[DateValue]]: value.[[DateValue]] }.
+ else if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::DateObject);
+ serialize_date_object(m_serialized, value);
+ }
- // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
- else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage));
- }
+ // 12. Otherwise, if value has a [[RegExpMatcher]] internal slot, then set serialized to
+ // { [[Type]]: "RegExp", [[RegExpMatcher]]: value.[[RegExpMatcher]], [[OriginalSource]]: value.[[OriginalSource]],
+ // [[OriginalFlags]]: value.[[OriginalFlags]] }.
+ else if (is(object)) {
+ serialize_enum(m_serialized, ValueTag::RegExpObject);
+ TRY(serialize_reg_exp_object(m_vm, m_serialized, value));
+ }
- // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
- else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage, m_memory));
- } else if (value.is_object() && is(value.as_object())) {
- TRY(serialize_viewed_array_buffer(m_vm, m_serialized, static_cast(value.as_object()), m_for_storage, m_memory));
- }
+ // 13. Otherwise, if value has an [[ArrayBufferData]] internal slot, then:
+ else if (auto const* array_buffer = as_if(object)) {
+ TRY(serialize_array_buffer(m_vm, m_serialized, *array_buffer, m_for_storage));
+ }
- // 15. Otherwise, if value has a [[MapData]] internal slot, then:
- else if (value.is_object() && is(value.as_object())) {
- // 1. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.
- serialize_enum(m_serialized, ValueTag::MapObject);
- // 2. Set deep to true.
- deep = true;
- }
+ // 14. Otherwise, if value has a [[ViewedArrayBuffer]] internal slot, then:
+ else if (auto const* typed_array_base = as_if(object)) {
+ TRY(serialize_viewed_array_buffer(m_vm, m_serialized, *typed_array_base, m_for_storage, m_memory));
+ } else if (auto const* data_view = as_if(object)) {
+ TRY(serialize_viewed_array_buffer(m_vm, m_serialized, *data_view, m_for_storage, m_memory));
+ }
- // 16. Otherwise, if value has a [[SetData]] internal slot, then:
- else if (value.is_object() && is(value.as_object())) {
- // 1. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.
- serialize_enum(m_serialized, ValueTag::SetObject);
- // 2. Set deep to true.
- deep = true;
- }
+ // 15. Otherwise, if value has a [[MapData]] internal slot, then:
+ else if (is(object)) {
+ // 1. Set serialized to { [[Type]]: "Map", [[MapData]]: a new empty List }.
+ serialize_enum(m_serialized, ValueTag::MapObject);
+ // 2. Set deep to true.
+ deep = true;
+ }
- // 17. Otherwise, if value has an [[ErrorData]] internal slot and value is not a platform object, then:
- else if (value.is_object() && is(value.as_object()) && !is(value.as_object())) {
- // 1. Let name be ? Get(value, "name").
- auto name_property = TRY(value.as_object().get(m_vm.names.name));
+ // 16. Otherwise, if value has a [[SetData]] internal slot, then:
+ else if (is(object)) {
+ // 1. Set serialized to { [[Type]]: "Set", [[SetData]]: a new empty List }.
+ serialize_enum(m_serialized, ValueTag::SetObject);
+ // 2. Set deep to true.
+ deep = true;
+ }
- // FIXME: Spec bug - https://github.com/whatwg/html/issues/9923
- // MISSING STEP: Set name to ? ToString(name).
- auto name = TRY(name_property.to_string(m_vm));
+ // 17. Otherwise, if value has an [[ErrorData]] internal slot and value is not a platform object, then:
+ else if (is(object) && !is(object)) {
+ // 1. Let name be ? Get(value, "name").
+ auto name_property = TRY(object.get(m_vm.names.name));
- // 2. If name is not one of "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", or "URIError", then set name to "Error".
- auto type = error_name_to_type(name);
+ // FIXME: Spec bug - https://github.com/whatwg/html/issues/9923
+ // MISSING STEP: Set name to ? ToString(name).
+ auto name = TRY(name_property.to_string(m_vm));
- // 3. Let valueMessageDesc be ? value.[[GetOwnProperty]]("message").
- auto value_message_descriptor = TRY(value.as_object().internal_get_own_property(m_vm.names.message));
+ // 2. If name is not one of "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", or "URIError", then set name to "Error".
+ auto type = error_name_to_type(name);
- // 4. Let message be undefined if IsDataDescriptor(valueMessageDesc) is false, and ? ToString(valueMessageDesc.[[Value]]) otherwise.
- Optional message;
- if (value_message_descriptor.has_value() && value_message_descriptor->is_data_descriptor())
- message = TRY(value_message_descriptor->value->to_string(m_vm));
+ // 3. Let valueMessageDesc be ? value.[[GetOwnProperty]]("message").
+ auto value_message_descriptor = TRY(object.internal_get_own_property(m_vm.names.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.
- serialize_enum(m_serialized, ValueTag::ErrorObject);
- serialize_enum(m_serialized, type);
- serialize_primitive_type(m_serialized, message.has_value());
- if (message.has_value())
- TRY(serialize_string(m_vm, m_serialized, *message));
- }
+ // 4. Let message be undefined if IsDataDescriptor(valueMessageDesc) is false, and ? ToString(valueMessageDesc.[[Value]]) otherwise.
+ Optional message;
+ if (value_message_descriptor.has_value() && value_message_descriptor->is_data_descriptor())
+ message = TRY(value_message_descriptor->value->to_string(m_vm));
- // 18. Otherwise, if value is an Array exotic object, then:
- else if (value.is_object() && is(value.as_object())) {
- // 1. Let valueLenDescriptor be ? OrdinaryGetOwnProperty(value, "length").
- // 2. Let valueLen be valueLenDescriptor.[[Value]].
- // NON-STANDARD: Array objects in LibJS do not have a real length property, so it must be accessed the usual way
- u64 length = MUST(JS::length_of_array_like(m_vm, value.as_object()));
+ // 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.
+ serialize_enum(m_serialized, ValueTag::ErrorObject);
+ serialize_enum(m_serialized, type);
+ serialize_primitive_type(m_serialized, message.has_value());
+ if (message.has_value())
+ TRY(serialize_string(m_vm, m_serialized, *message));
+ }
- // 3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }.
- serialize_enum(m_serialized, ValueTag::ArrayObject);
- serialize_primitive_type(m_serialized, length);
+ // 18. Otherwise, if value is an Array exotic object, then:
+ else if (is(object)) {
+ // 1. Let valueLenDescriptor be ? OrdinaryGetOwnProperty(value, "length").
+ // 2. Let valueLen be valueLenDescriptor.[[Value]].
+ // NON-STANDARD: Array objects in LibJS do not have a real length property, so it must be accessed the usual way
+ u64 length = MUST(JS::length_of_array_like(m_vm, object));
- // 4. Set deep to true.
- deep = true;
- }
+ // 3. Set serialized to { [[Type]]: "Array", [[Length]]: valueLen, [[Properties]]: a new empty List }.
+ serialize_enum(m_serialized, ValueTag::ArrayObject);
+ serialize_primitive_type(m_serialized, length);
- // 19. Otherwise, if value is a platform object that is a serializable object:
- else if (value.is_object() && is(value.as_object())) {
- auto& serializable = dynamic_cast(value.as_object());
+ // 4. Set deep to true.
+ deep = true;
+ }
- // FIXME: 1. If value has a [[Detached]] internal slot whose value is true, then throw a "DataCloneError" DOMException.
+ // 19. Otherwise, if value is a platform object that is a serializable object:
+ else if (auto const* serializable = as_if(object)) {
+ // FIXME: 1. If value has a [[Detached]] internal slot whose value is true, then throw a "DataCloneError" DOMException.
- // 2. Let typeString be the identifier of the primary interface of value.
- // 3. Set serialized to { [[Type]]: typeString }.
- serialize_enum(m_serialized, ValueTag::SerializableObject);
- serialize_enum(m_serialized, serializable.serialize_type());
+ // 2. Let typeString be the identifier of the primary interface of value.
+ // 3. Set serialized to { [[Type]]: typeString }.
+ serialize_enum(m_serialized, ValueTag::SerializableObject);
+ serialize_enum(m_serialized, serializable->serialize_type());
- // 4. Set deep to true
- deep = true;
- }
+ // 4. Set deep to true
+ deep = true;
+ }
- // 20. Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.
- else if (value.is_object() && is(value.as_object())) {
- return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize platform objects"_string));
- }
+ // 20. Otherwise, if value is a platform object, then throw a "DataCloneError" DOMException.
+ else if (is(object)) {
+ return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize platform objects"_string));
+ }
- // 21. Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.
- else if (value.is_function()) {
- return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize functions"_string));
- }
+ // 21. Otherwise, if IsCallable(value) is true, then throw a "DataCloneError" DOMException.
+ else if (value.is_function()) {
+ return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Cannot serialize functions"_string));
+ }
- // FIXME: 22. Otherwise, if value has any internal slot other than [[Prototype]] or [[Extensible]], then throw a "DataCloneError" DOMException.
+ // FIXME: 22. Otherwise, if value has any internal slot other than [[Prototype]] or [[Extensible]], then throw a "DataCloneError" DOMException.
- // FIXME: 23. Otherwise, if value is an exotic object and value is not the %Object.prototype% intrinsic object associated with any realm, then throw a "DataCloneError" DOMException.
+ // FIXME: 23. Otherwise, if value is an exotic object and value is not the %Object.prototype% intrinsic object associated with any realm, then throw a "DataCloneError" DOMException.
- // 24. Otherwise:
- else {
- // 1. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.
- serialize_enum(m_serialized, ValueTag::Object);
+ // 24. Otherwise:
+ else {
+ // 1. Set serialized to { [[Type]]: "Object", [[Properties]]: a new empty List }.
+ serialize_enum(m_serialized, ValueTag::Object);
- // 2. Set deep to true.
- deep = true;
+ // 2. Set deep to true.
+ deep = true;
+ }
}
// 25. Set memory[value] to serialized.
@@ -377,20 +379,22 @@ public:
// 26. If deep is true, then:
if (deep) {
+ auto& object = value.as_object();
+
// 1. If value has a [[MapData]] internal slot, then:
- if (value.is_object() && is(value.as_object())) {
- auto const& map = static_cast(value.as_object());
+ if (auto const* map = as_if(object)) {
// 1. Let copiedList be a new empty List.
Vector copied_list;
- copied_list.ensure_capacity(map.map_size() * 2);
+ copied_list.ensure_capacity(map->map_size() * 2);
+
// 2. For each Record { [[Key]], [[Value]] } entry of value.[[MapData]]:
- for (auto const& entry : static_cast(value.as_object())) {
+ for (auto const& entry : *map) {
// 1. Let copiedEntry be a new Record { [[Key]]: entry.[[Key]], [[Value]]: entry.[[Value]] }.
// 2. If copiedEntry.[[Key]] is not the special value empty, append copiedEntry to copiedList.
copied_list.append(entry.key);
copied_list.append(entry.value);
}
- u64 size = map.map_size();
+ u64 size = map->map_size();
m_serialized.append(bit_cast(&size), 2);
// 3. For each Record { [[Key]], [[Value]] } entry of copiedList:
for (auto copied_value : copied_list) {
@@ -404,17 +408,17 @@ public:
}
// 2. Otherwise, if value has a [[SetData]] internal slot, then:
- else if (value.is_object() && is(value.as_object())) {
- auto const& set = static_cast(value.as_object());
+ else if (auto const* set = as_if(object)) {
// 1. Let copiedList be a new empty List.
Vector copied_list;
- copied_list.ensure_capacity(set.set_size());
+ copied_list.ensure_capacity(set->set_size());
+
// 2. For each entry of value.[[SetData]]:
- for (auto const& entry : static_cast(value.as_object())) {
+ for (auto const& entry : *set) {
// 1. If entry is not the special value empty, append entry to copiedList.
copied_list.append(entry.key);
}
- serialize_primitive_type(m_serialized, set.set_size());
+ serialize_primitive_type(m_serialized, set->set_size());
// 3. For each entry of copiedList:
for (auto copied_value : copied_list) {
// 1. Let serializedEntry be ? StructuredSerializeInternal(entry, forStorage, memory).
@@ -426,9 +430,8 @@ public:
}
// 3. Otherwise, if value is a platform object that is a serializable object, then perform the serialization steps for value's primary interface, given value, serialized, and forStorage.
- else if (value.is_object() && is(value.as_object())) {
- auto& serializable = dynamic_cast(value.as_object());
- TRY(serializable.serialization_steps(m_serialized, m_for_storage, m_memory));
+ else if (auto* serializable = as_if(object)) {
+ TRY(serializable->serialization_steps(m_serialized, m_for_storage, m_memory));
}
// 4. Otherwise, for each key in ! EnumerableOwnProperties(value, key):
@@ -436,13 +439,13 @@ public:
u64 property_count = 0;
auto count_offset = m_serialized.size();
serialize_primitive_type(m_serialized, property_count);
- for (auto key : MUST(value.as_object().enumerable_own_property_names(JS::Object::PropertyKind::Key))) {
+ for (auto key : MUST(object.enumerable_own_property_names(JS::Object::PropertyKind::Key))) {
auto property_key = MUST(JS::PropertyKey::from_value(m_vm, key));
// 1. If ! HasOwnProperty(value, key) is true, then:
- if (MUST(value.as_object().has_own_property(property_key))) {
+ if (MUST(object.has_own_property(property_key))) {
// 1. Let inputValue be ? value.[[Get]](key, value).
- auto input_value = TRY(value.as_object().internal_get(property_key, value));
+ auto input_value = TRY(object.internal_get(property_key, value));
// 2. Let outputValue be ? StructuredSerializeInternal(inputValue, forStorage, memory).
auto output_value = TRY(structured_serialize_internal(m_vm, input_value, m_for_storage, m_memory));