Title: [206766] trunk/Source/WebCore
Revision
206766
Author
[email protected]
Date
2016-10-03 23:28:55 -0700 (Mon, 03 Oct 2016)

Log Message

Bindings do not throw a TypeError if a required dictionary member is missing
https://bugs.webkit.org/show_bug.cgi?id=162734

Reviewed by Geoffrey Garen.

Bindings should throw a TypeError if a required dictionary member is missing.
For example, if there is a "required long id" member in a dictionary that is
missing, our bindings would prevously pass 0 to the implementation instead
of throwing a TypeError.

Relevant specification:
- https://heycam.github.io/webidl/#es-dictionary

I aligned our bindings generator implementation with the specification,
except for the support for dictionary inheritance that is still missing
and will be addressed in a follow-up patch.

No new tests, I rebaselined the bindings tests and this is already covered
by fast/events/touch/touch-constructor.html on iOS.

* bindings/js/JSCustomElementRegistryCustom.cpp:
(WebCore::JSCustomElementRegistry::define):
* bindings/js/JSDOMConvert.h:
(WebCore::convert): Deleted.
(WebCore::Converter<bool>::convert): Deleted.
(WebCore::Converter<String>::convert): Deleted.
(WebCore::Converter<IDLDOMString>::convert): Deleted.
(WebCore::Converter<IDLUSVString>::convert): Deleted.
(WebCore::Converter<JSC::JSValue>::convert): Deleted.
(WebCore::Converter<int8_t>::convert): Deleted.
(WebCore::Converter<uint8_t>::convert): Deleted.
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateDictionaryImplementationContent):
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::convertDictionary<TestObj::Dictionary>):
(WebCore::convertDictionary<TestObj::DictionaryThatShouldNotTolerateNull>):
(WebCore::convertDictionary<TestObj::DictionaryThatShouldTolerateNull>):
(WebCore::convertDictionary<AlternateDictionaryName>):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (206765 => 206766)


--- trunk/Source/WebCore/ChangeLog	2016-10-04 03:33:57 UTC (rev 206765)
+++ trunk/Source/WebCore/ChangeLog	2016-10-04 06:28:55 UTC (rev 206766)
@@ -1,3 +1,44 @@
+2016-10-03  Chris Dumez  <[email protected]>
+
+        Bindings do not throw a TypeError if a required dictionary member is missing
+        https://bugs.webkit.org/show_bug.cgi?id=162734
+
+        Reviewed by Geoffrey Garen.
+
+        Bindings should throw a TypeError if a required dictionary member is missing.
+        For example, if there is a "required long id" member in a dictionary that is
+        missing, our bindings would prevously pass 0 to the implementation instead
+        of throwing a TypeError.
+
+        Relevant specification:
+        - https://heycam.github.io/webidl/#es-dictionary
+
+        I aligned our bindings generator implementation with the specification,
+        except for the support for dictionary inheritance that is still missing
+        and will be addressed in a follow-up patch.
+
+        No new tests, I rebaselined the bindings tests and this is already covered
+        by fast/events/touch/touch-constructor.html on iOS.
+
+        * bindings/js/JSCustomElementRegistryCustom.cpp:
+        (WebCore::JSCustomElementRegistry::define):
+        * bindings/js/JSDOMConvert.h:
+        (WebCore::convert): Deleted.
+        (WebCore::Converter<bool>::convert): Deleted.
+        (WebCore::Converter<String>::convert): Deleted.
+        (WebCore::Converter<IDLDOMString>::convert): Deleted.
+        (WebCore::Converter<IDLUSVString>::convert): Deleted.
+        (WebCore::Converter<JSC::JSValue>::convert): Deleted.
+        (WebCore::Converter<int8_t>::convert): Deleted.
+        (WebCore::Converter<uint8_t>::convert): Deleted.
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateDictionaryImplementationContent):
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::convertDictionary<TestObj::Dictionary>):
+        (WebCore::convertDictionary<TestObj::DictionaryThatShouldNotTolerateNull>):
+        (WebCore::convertDictionary<TestObj::DictionaryThatShouldTolerateNull>):
+        (WebCore::convertDictionary<AlternateDictionaryName>):
+
 2016-10-03  Zalan Bujtas  <[email protected]>
 
         [ListItems] Render tree should be all clean by the end of FrameView::layout().

Modified: trunk/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp (206765 => 206766)


--- trunk/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp	2016-10-04 03:33:57 UTC (rev 206765)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp	2016-10-04 06:28:55 UTC (rev 206766)
@@ -139,10 +139,13 @@
     auto* attributeChangedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "attributeChangedCallback"));
     RETURN_IF_EXCEPTION(scope, JSValue());
     if (attributeChangedCallback) {
-        auto value = convertOptional<Vector<String>>(state, constructor->get(&state, Identifier::fromString(&state, "observedAttributes")));
+        auto observedAttributesValue = constructor->get(&state, Identifier::fromString(&state, "observedAttributes"));
         RETURN_IF_EXCEPTION(scope, JSValue());
-        if (value)
-            elementInterface->setAttributeChangedCallback(attributeChangedCallback, *value);
+        if (!observedAttributesValue.isUndefined()) {
+            auto observedAttributes = convert<Vector<String>>(state, observedAttributesValue);
+            RETURN_IF_EXCEPTION(scope, JSValue());
+            elementInterface->setAttributeChangedCallback(attributeChangedCallback, observedAttributes);
+        }
     }
 
     PrivateName uniquePrivateName;

Modified: trunk/Source/WebCore/bindings/js/JSDOMConvert.h (206765 => 206766)


--- trunk/Source/WebCore/bindings/js/JSDOMConvert.h	2016-10-04 03:33:57 UTC (rev 206765)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvert.h	2016-10-04 06:28:55 UTC (rev 206766)
@@ -41,14 +41,6 @@
 template<typename T> EnableIfIntegralType<T> convert(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration);
 template<typename T> EnableIfFloatingPointType<T> convert(JSC::ExecState&, JSC::JSValue, ShouldAllowNonFinite);
 
-template<typename T> typename Converter<T>::OptionalValue convertOptional(JSC::ExecState&, JSC::JSValue);
-template<typename T, typename U> T convertOptional(JSC::ExecState&, JSC::JSValue, U&& defaultValue);
-
-template<typename T> EnableIfIntegralType<T, Optional<T>> convertOptional(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration);
-template<typename T> EnableIfFloatingPointType<T, Optional<T>> convertOptional(JSC::ExecState&, JSC::JSValue, ShouldAllowNonFinite);
-template<typename T, typename U> EnableIfIntegralType<T> convertOptional(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration, U&& defaultValue);
-template<typename T, typename U> EnableIfFloatingPointType<T> convertOptional(JSC::ExecState&, JSC::JSValue, ShouldAllowNonFinite, U&& defaultValue);
-
 template<typename T> Optional<T> convertDictionary(JSC::ExecState&, JSC::JSValue);
 
 enum class IsNullable { No, Yes };
@@ -81,36 +73,6 @@
     return object;
 }
 
-template<typename T> inline typename Converter<T>::OptionalValue convertOptional(JSC::ExecState& state, JSC::JSValue value)
-{
-    return value.isUndefined() ? typename Converter<T>::OptionalValue() : convert<T>(state, value);
-}
-
-template<typename T, typename U> inline T convertOptional(JSC::ExecState& state, JSC::JSValue value, U&& defaultValue)
-{
-    return value.isUndefined() ? std::forward<U>(defaultValue) : convert<T>(state, value);
-}
-
-template<typename T> inline EnableIfFloatingPointType<T, Optional<T>> convertOptional(JSC::ExecState& state, JSC::JSValue value, ShouldAllowNonFinite allow)
-{
-    return value.isUndefined() ? Optional<T>() : convert<T>(state, value, allow);
-}
-
-template<typename T, typename U> inline EnableIfFloatingPointType<T> convertOptional(JSC::ExecState& state, JSC::JSValue value, ShouldAllowNonFinite allow, U&& defaultValue)
-{
-    return value.isUndefined() ? std::forward<U>(defaultValue) : convert<T>(state, value, allow);
-}
-
-template<typename T> inline EnableIfIntegralType<T, Optional<T>> convertOptional(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration)
-{
-    return value.isUndefined() ? Optional<T>() : convert<T>(state, value, configuration);
-}
-
-template<typename T, typename U> inline EnableIfIntegralType<T> convertOptional(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration, U&& defaultValue)
-{
-    return value.isUndefined() ? std::forward<U>(defaultValue) : convert<T>(state, value, configuration);
-}
-
 template<typename T> struct DefaultConverter {
     using OptionalValue = Optional<T>;
 };

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (206765 => 206766)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-04 03:33:57 UTC (rev 206765)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-04 06:28:55 UTC (rev 206766)
@@ -951,14 +951,6 @@
     return "";
 }
 
-sub GenerateDefaultValueWithLeadingComma
-{
-    my ($interface, $member) = @_;
-
-    return "" unless $member->isOptional && defined $member->default;
-    return ", " . GenerateDefaultValue($interface, $member);
-}
-
 sub GenerateDictionaryImplementationContent
 {
     my ($interface, $dictionaries) = @_;
@@ -975,58 +967,84 @@
         # FIXME: A little ugly to have this be a side effect instead of a return value.
         AddToImplIncludes("JSDOMConvert.h");
 
-        my $defaultValues = "";
-        my $comma = "";
-        foreach my $member (@{$dictionary->members}) {
-            if (!$member->isOptional) {
-                $defaultValues = "";
-                last;
-            }
-            $member->default("undefined") if $member->type eq "any"; # Use undefined as default value for member of type 'any'.
-            $defaultValues .= $comma . (defined $member->default ? GenerateDefaultValue($interface, $member) : "{ }");
-            $comma = ", ";
-        }
-
+        # https://heycam.github.io/webidl/#es-dictionary
         $result .= "template<> Optional<$className> convertDictionary<$className>(ExecState& state, JSValue value)\n";
         $result .= "{\n";
         $result .= "    VM& vm = state.vm();\n";
         $result .= "    auto throwScope = DECLARE_THROW_SCOPE(vm);\n";
-        $result .= "    if (value.isUndefinedOrNull())\n" if $defaultValues;
-        $result .= "        return $className { " . $defaultValues . " };\n" if $defaultValues;
-        $result .= "    auto* object = value.getObject();\n";
-        $result .= "    if (UNLIKELY(!object || object->type() == RegExpObjectType)) {\n";
+        $result .= "    bool isNullOrUndefined = value.isUndefinedOrNull();\n";
+        $result .= "    auto* object = isNullOrUndefined ? nullptr : value.getObject();\n";
+        # 1. If Type(V) is not Undefined, Null or Object, then throw a TypeError.
+        $result .= "    if (UNLIKELY(!isNullOrUndefined && !object)) {\n";
         $result .= "        throwTypeError(&state, throwScope);\n";
         $result .= "        return Nullopt;\n";
         $result .= "    }\n";
 
-        my $needExceptionCheck = 0;
+        # 2. If V is a native RegExp object, then throw a TypeError.
+        # FIXME: This RegExp special handling is likely to go away in the specification.
+        $result .= "    if (UNLIKELY(object && object->type() == RegExpObjectType)) {\n";
+        $result .= "        throwTypeError(&state, throwScope);\n";
+        $result .= "        return Nullopt;\n";
+        $result .= "    }\n";
+
+        # 3. Let dict be an empty dictionary value of type D; every dictionary member is initially considered to be not present.
+        # 4. Let dictionaries be a list consisting of D and all of D’s inherited dictionaries, in order from least to most derived.
+        # FIXME: We do not support dictionary inheritence yet.
+
+        # 5. For each dictionary dictionary in dictionaries, in order:
         foreach my $member (@{$dictionary->members}) {
-            if ($needExceptionCheck) {
-                $result .= "    RETURN_IF_EXCEPTION(throwScope, Nullopt);\n";
+            $member->default("undefined") if $member->type eq "any"; # Use undefined as default value for member of type 'any'.
+
+            my $type = $member->type;
+
+            # 5.1. Let key be the identifier of member.
+            my $key = $member->name;
+
+            # 5.2. Let value be an ECMAScript value, depending on Type(V):
+            $result .= "    JSValue ${key}Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, \"${key}\"));\n";
+
+            my $nativeType = GetNativeTypeFromSignature($interface, $member);
+            if ($member->isOptional && !defined $member->default) {
+                $result .= "    Converter<$nativeType>::OptionalValue $key;\n";
+            } else {
+                $result .= "    $nativeType $key;\n";
             }
+
+            # 5.3. If value is not undefined, then:
+            $result .= "    if (!${key}Value.isUndefined()) {\n";
             # FIXME: Eventually we will want this to share a lot more code with JSValueToNative.
-            my $type = $member->type;
-            my $name = $member->name;
-            my $value = "object->get(&state, Identifier::fromString(&state, \"${name}\"))";
             if ($codeGenerator->IsWrapperType($type)) {
                 AddToImplIncludes("JS${type}.h");
                 die "Dictionary members of non-nullable wrapper types must be marked as required" if !$member->isNullable && $member->isOptional;
                 my $nullableParameter = $member->isNullable ? "IsNullable::Yes" : "IsNullable::No";
-                $result .= "    auto* $name = convertWrapperType<$type, JS${type}>(state, $value, $nullableParameter);\n";
+                $result .= "        $key = convertWrapperType<$type, JS${type}>(state, ${key}Value, $nullableParameter);\n";
             } elsif ($codeGenerator->IsDictionaryType($type)) {
                 my $nativeType = GetNativeType($interface, $type);
-                $result .= "    auto $name = convertDictionary<$nativeType>(state, $value);\n";
+                $result .= "        $key = convertDictionary<${nativeType}>(state, ${key}Value);\n";
             } else {
-                my $function = $member->isOptional ? "convertOptional" : "convert";
-                $result .= "    auto $name = ${function}<" . GetNativeTypeFromSignature($interface, $member) . ">(state, $value"
-                    . GenerateConversionRuleWithLeadingComma($interface, $member)
-                    . GenerateDefaultValueWithLeadingComma($interface, $member) . ");\n";
+                my $conversionRuleWithLeadingComma = GenerateConversionRuleWithLeadingComma($interface, $member);
+                $result .= "        $key = convert<${nativeType}>(state, ${key}Value${conversionRuleWithLeadingComma});\n";
             }
-            $needExceptionCheck = 1;
+            $result .= "        RETURN_IF_EXCEPTION(throwScope, Nullopt);\n";
+            # Value is undefined.
+            # 5.4. Otherwise, if value is undefined but the dictionary member has a default value, then:
+            if ($member->isOptional && defined $member->default) {
+                $result .= "    } else\n";
+                $result .= "        $key = " . GenerateDefaultValue($interface, $member) . ";\n";
+            } elsif (!$member->isOptional) {
+                # 5.5. Otherwise, if value is undefined and the dictionary member is a required dictionary member, then throw a TypeError.
+                $result .= "    } else {\n";
+                $result .= "        throwTypeError(&state, throwScope);\n";
+                $result .= "        return Nullopt;\n";
+                $result .= "    }\n";
+            } else {
+                $result .= "    }\n";
+            }
         }
 
+        # 6. Return dict.
         my $arguments = "";
-        $comma = "";
+        my $comma = "";
         foreach my $member (@{$dictionary->members}) {
             my $value;
             if ($codeGenerator->IsWrapperType($member->type) && !$member->isNullable) {

Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp (206765 => 206766)


--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp	2016-10-04 03:33:57 UTC (rev 206765)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp	2016-10-04 06:28:55 UTC (rev 206766)
@@ -520,76 +520,224 @@
 {
     VM& vm = state.vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
-    if (value.isUndefinedOrNull())
-        return TestObj::Dictionary { { }, TestObj::EnumType::EnumValue1, TestObj::EnumType::EmptyString, "defaultString", { }, false, { }, { }, { }, { }, 0, 0, { }, { }, 0, 0, { }, { }, { }, 0, { }, 0, { }, 0, { }, 0, { }, 0, nullptr, jsUndefined(), jsUndefined(), { } };
-    auto* object = value.getObject();
-    if (UNLIKELY(!object || object->type() == RegExpObjectType)) {
+    bool isNullOrUndefined = value.isUndefinedOrNull();
+    auto* object = isNullOrUndefined ? nullptr : value.getObject();
+    if (UNLIKELY(!isNullOrUndefined && !object)) {
         throwTypeError(&state, throwScope);
         return Nullopt;
     }
-    auto enumerationValueWithoutDefault = convertOptional<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "enumerationValueWithoutDefault")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto enumerationValueWithDefault = convertOptional<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "enumerationValueWithDefault")), TestObj::EnumType::EnumValue1);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto enumerationValueWithEmptyStringDefault = convertOptional<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "enumerationValueWithEmptyStringDefault")), TestObj::EnumType::EmptyString);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto stringWithDefault = convertOptional<String>(state, object->get(&state, Identifier::fromString(&state, "stringWithDefault")), "defaultString");
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto stringWithoutDefault = convertOptional<String>(state, object->get(&state, Identifier::fromString(&state, "stringWithoutDefault")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto booleanWithDefault = convertOptional<bool>(state, object->get(&state, Identifier::fromString(&state, "booleanWithDefault")), false);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto booleanWithoutDefault = convertOptional<bool>(state, object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto sequenceOfStrings = convertOptional<Vector<String>>(state, object->get(&state, Identifier::fromString(&state, "sequenceOfStrings")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto restrictedDouble = convertOptional<double>(state, object->get(&state, Identifier::fromString(&state, "restrictedDouble")), ShouldAllowNonFinite::No);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unrestrictedDouble = convertOptional<double>(state, object->get(&state, Identifier::fromString(&state, "unrestrictedDouble")), ShouldAllowNonFinite::Yes);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto restrictedDoubleWithDefault = convertOptional<double>(state, object->get(&state, Identifier::fromString(&state, "restrictedDoubleWithDefault")), ShouldAllowNonFinite::No, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unrestrictedDoubleWithDefault = convertOptional<double>(state, object->get(&state, Identifier::fromString(&state, "unrestrictedDoubleWithDefault")), ShouldAllowNonFinite::Yes, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto restrictedFloat = convertOptional<float>(state, object->get(&state, Identifier::fromString(&state, "restrictedFloat")), ShouldAllowNonFinite::No);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unrestrictedFloat = convertOptional<float>(state, object->get(&state, Identifier::fromString(&state, "unrestrictedFloat")), ShouldAllowNonFinite::Yes);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto restrictedFloatWithDefault = convertOptional<float>(state, object->get(&state, Identifier::fromString(&state, "restrictedFloatWithDefault")), ShouldAllowNonFinite::No, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unrestrictedFloatWithDefault = convertOptional<float>(state, object->get(&state, Identifier::fromString(&state, "unrestrictedFloatWithDefault")), ShouldAllowNonFinite::Yes, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto smallIntegerClamped = convertOptional<int8_t>(state, object->get(&state, Identifier::fromString(&state, "smallIntegerClamped")), Clamp);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto smallIntegerWithDefault = convertOptional<int8_t>(state, object->get(&state, Identifier::fromString(&state, "smallIntegerWithDefault")), NormalConversion);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto smallUnsignedIntegerEnforcedRange = convertOptional<uint8_t>(state, object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerEnforcedRange")), EnforceRange);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto smallUnsignedIntegerWithDefault = convertOptional<uint8_t>(state, object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerWithDefault")), NormalConversion, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto integer = convertOptional<int32_t>(state, object->get(&state, Identifier::fromString(&state, "integer")), NormalConversion);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto integerWithDefault = convertOptional<int32_t>(state, object->get(&state, Identifier::fromString(&state, "integerWithDefault")), NormalConversion, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unsignedInteger = convertOptional<uint32_t>(state, object->get(&state, Identifier::fromString(&state, "unsignedInteger")), NormalConversion);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unsignedIntegerWithDefault = convertOptional<uint32_t>(state, object->get(&state, Identifier::fromString(&state, "unsignedIntegerWithDefault")), NormalConversion, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto largeInteger = convertOptional<int64_t>(state, object->get(&state, Identifier::fromString(&state, "largeInteger")), NormalConversion);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto largeIntegerWithDefault = convertOptional<int64_t>(state, object->get(&state, Identifier::fromString(&state, "largeIntegerWithDefault")), NormalConversion, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unsignedLargeInteger = convertOptional<uint64_t>(state, object->get(&state, Identifier::fromString(&state, "unsignedLargeInteger")), NormalConversion);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto unsignedLargeIntegerWithDefault = convertOptional<uint64_t>(state, object->get(&state, Identifier::fromString(&state, "unsignedLargeIntegerWithDefault")), NormalConversion, 0);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto* nullableNode = convertWrapperType<Node, JSNode>(state, object->get(&state, Identifier::fromString(&state, "nullableNode")), IsNullable::Yes);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto anyValue = convertOptional<JSC::JSValue>(state, object->get(&state, Identifier::fromString(&state, "anyValue")), jsUndefined());
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto anyTypedefValue = convertOptional<JSC::JSValue>(state, object->get(&state, Identifier::fromString(&state, "anyTypedefValue")), jsUndefined());
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto dictionaryMember = convertDictionary<TestObj::DictionaryThatShouldTolerateNull>(state, object->get(&state, Identifier::fromString(&state, "dictionaryMember")));
+    if (UNLIKELY(object && object->type() == RegExpObjectType)) {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue enumerationValueWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "enumerationValueWithoutDefault"));
+    Converter<TestObj::EnumType>::OptionalValue enumerationValueWithoutDefault;
+    if (!enumerationValueWithoutDefaultValue.isUndefined()) {
+        enumerationValueWithoutDefault = convert<TestObj::EnumType>(state, enumerationValueWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue enumerationValueWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "enumerationValueWithDefault"));
+    TestObj::EnumType enumerationValueWithDefault;
+    if (!enumerationValueWithDefaultValue.isUndefined()) {
+        enumerationValueWithDefault = convert<TestObj::EnumType>(state, enumerationValueWithDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        enumerationValueWithDefault = TestObj::EnumType::EnumValue1;
+    JSValue enumerationValueWithEmptyStringDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "enumerationValueWithEmptyStringDefault"));
+    TestObj::EnumType enumerationValueWithEmptyStringDefault;
+    if (!enumerationValueWithEmptyStringDefaultValue.isUndefined()) {
+        enumerationValueWithEmptyStringDefault = convert<TestObj::EnumType>(state, enumerationValueWithEmptyStringDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        enumerationValueWithEmptyStringDefault = TestObj::EnumType::EmptyString;
+    JSValue stringWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithDefault"));
+    String stringWithDefault;
+    if (!stringWithDefaultValue.isUndefined()) {
+        stringWithDefault = convert<String>(state, stringWithDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        stringWithDefault = "defaultString";
+    JSValue stringWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithoutDefault"));
+    Converter<String>::OptionalValue stringWithoutDefault;
+    if (!stringWithoutDefaultValue.isUndefined()) {
+        stringWithoutDefault = convert<String>(state, stringWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue booleanWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "booleanWithDefault"));
+    bool booleanWithDefault;
+    if (!booleanWithDefaultValue.isUndefined()) {
+        booleanWithDefault = convert<bool>(state, booleanWithDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        booleanWithDefault = false;
+    JSValue booleanWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault"));
+    Converter<bool>::OptionalValue booleanWithoutDefault;
+    if (!booleanWithoutDefaultValue.isUndefined()) {
+        booleanWithoutDefault = convert<bool>(state, booleanWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue sequenceOfStringsValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "sequenceOfStrings"));
+    Converter<Vector<String>>::OptionalValue sequenceOfStrings;
+    if (!sequenceOfStringsValue.isUndefined()) {
+        sequenceOfStrings = convert<Vector<String>>(state, sequenceOfStringsValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue restrictedDoubleValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "restrictedDouble"));
+    Converter<double>::OptionalValue restrictedDouble;
+    if (!restrictedDoubleValue.isUndefined()) {
+        restrictedDouble = convert<double>(state, restrictedDoubleValue, ShouldAllowNonFinite::No);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue unrestrictedDoubleValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unrestrictedDouble"));
+    Converter<double>::OptionalValue unrestrictedDouble;
+    if (!unrestrictedDoubleValue.isUndefined()) {
+        unrestrictedDouble = convert<double>(state, unrestrictedDoubleValue, ShouldAllowNonFinite::Yes);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue restrictedDoubleWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "restrictedDoubleWithDefault"));
+    double restrictedDoubleWithDefault;
+    if (!restrictedDoubleWithDefaultValue.isUndefined()) {
+        restrictedDoubleWithDefault = convert<double>(state, restrictedDoubleWithDefaultValue, ShouldAllowNonFinite::No);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        restrictedDoubleWithDefault = 0;
+    JSValue unrestrictedDoubleWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unrestrictedDoubleWithDefault"));
+    double unrestrictedDoubleWithDefault;
+    if (!unrestrictedDoubleWithDefaultValue.isUndefined()) {
+        unrestrictedDoubleWithDefault = convert<double>(state, unrestrictedDoubleWithDefaultValue, ShouldAllowNonFinite::Yes);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        unrestrictedDoubleWithDefault = 0;
+    JSValue restrictedFloatValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "restrictedFloat"));
+    Converter<float>::OptionalValue restrictedFloat;
+    if (!restrictedFloatValue.isUndefined()) {
+        restrictedFloat = convert<float>(state, restrictedFloatValue, ShouldAllowNonFinite::No);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue unrestrictedFloatValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unrestrictedFloat"));
+    Converter<float>::OptionalValue unrestrictedFloat;
+    if (!unrestrictedFloatValue.isUndefined()) {
+        unrestrictedFloat = convert<float>(state, unrestrictedFloatValue, ShouldAllowNonFinite::Yes);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue restrictedFloatWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "restrictedFloatWithDefault"));
+    float restrictedFloatWithDefault;
+    if (!restrictedFloatWithDefaultValue.isUndefined()) {
+        restrictedFloatWithDefault = convert<float>(state, restrictedFloatWithDefaultValue, ShouldAllowNonFinite::No);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        restrictedFloatWithDefault = 0;
+    JSValue unrestrictedFloatWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unrestrictedFloatWithDefault"));
+    float unrestrictedFloatWithDefault;
+    if (!unrestrictedFloatWithDefaultValue.isUndefined()) {
+        unrestrictedFloatWithDefault = convert<float>(state, unrestrictedFloatWithDefaultValue, ShouldAllowNonFinite::Yes);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        unrestrictedFloatWithDefault = 0;
+    JSValue smallIntegerClampedValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallIntegerClamped"));
+    Converter<int8_t>::OptionalValue smallIntegerClamped;
+    if (!smallIntegerClampedValue.isUndefined()) {
+        smallIntegerClamped = convert<int8_t>(state, smallIntegerClampedValue, Clamp);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue smallIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallIntegerWithDefault"));
+    Converter<int8_t>::OptionalValue smallIntegerWithDefault;
+    if (!smallIntegerWithDefaultValue.isUndefined()) {
+        smallIntegerWithDefault = convert<int8_t>(state, smallIntegerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue smallUnsignedIntegerEnforcedRangeValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerEnforcedRange"));
+    Converter<uint8_t>::OptionalValue smallUnsignedIntegerEnforcedRange;
+    if (!smallUnsignedIntegerEnforcedRangeValue.isUndefined()) {
+        smallUnsignedIntegerEnforcedRange = convert<uint8_t>(state, smallUnsignedIntegerEnforcedRangeValue, EnforceRange);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue smallUnsignedIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerWithDefault"));
+    uint8_t smallUnsignedIntegerWithDefault;
+    if (!smallUnsignedIntegerWithDefaultValue.isUndefined()) {
+        smallUnsignedIntegerWithDefault = convert<uint8_t>(state, smallUnsignedIntegerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        smallUnsignedIntegerWithDefault = 0;
+    JSValue integerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "integer"));
+    Converter<int32_t>::OptionalValue integer;
+    if (!integerValue.isUndefined()) {
+        integer = convert<int32_t>(state, integerValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue integerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "integerWithDefault"));
+    int32_t integerWithDefault;
+    if (!integerWithDefaultValue.isUndefined()) {
+        integerWithDefault = convert<int32_t>(state, integerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        integerWithDefault = 0;
+    JSValue unsignedIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedInteger"));
+    Converter<uint32_t>::OptionalValue unsignedInteger;
+    if (!unsignedIntegerValue.isUndefined()) {
+        unsignedInteger = convert<uint32_t>(state, unsignedIntegerValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue unsignedIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedIntegerWithDefault"));
+    uint32_t unsignedIntegerWithDefault;
+    if (!unsignedIntegerWithDefaultValue.isUndefined()) {
+        unsignedIntegerWithDefault = convert<uint32_t>(state, unsignedIntegerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        unsignedIntegerWithDefault = 0;
+    JSValue largeIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "largeInteger"));
+    Converter<int64_t>::OptionalValue largeInteger;
+    if (!largeIntegerValue.isUndefined()) {
+        largeInteger = convert<int64_t>(state, largeIntegerValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue largeIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "largeIntegerWithDefault"));
+    int64_t largeIntegerWithDefault;
+    if (!largeIntegerWithDefaultValue.isUndefined()) {
+        largeIntegerWithDefault = convert<int64_t>(state, largeIntegerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        largeIntegerWithDefault = 0;
+    JSValue unsignedLargeIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedLargeInteger"));
+    Converter<uint64_t>::OptionalValue unsignedLargeInteger;
+    if (!unsignedLargeIntegerValue.isUndefined()) {
+        unsignedLargeInteger = convert<uint64_t>(state, unsignedLargeIntegerValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue unsignedLargeIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedLargeIntegerWithDefault"));
+    uint64_t unsignedLargeIntegerWithDefault;
+    if (!unsignedLargeIntegerWithDefaultValue.isUndefined()) {
+        unsignedLargeIntegerWithDefault = convert<uint64_t>(state, unsignedLargeIntegerWithDefaultValue, NormalConversion);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        unsignedLargeIntegerWithDefault = 0;
+    JSValue nullableNodeValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "nullableNode"));
+    Node* nullableNode;
+    if (!nullableNodeValue.isUndefined()) {
+        nullableNode = convertWrapperType<Node, JSNode>(state, nullableNodeValue, IsNullable::Yes);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        nullableNode = nullptr;
+    JSValue anyValueValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "anyValue"));
+    JSC::JSValue anyValue;
+    if (!anyValueValue.isUndefined()) {
+        anyValue = convert<JSC::JSValue>(state, anyValueValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        anyValue = jsUndefined();
+    JSValue anyTypedefValueValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "anyTypedefValue"));
+    JSC::JSValue anyTypedefValue;
+    if (!anyTypedefValueValue.isUndefined()) {
+        anyTypedefValue = convert<JSC::JSValue>(state, anyTypedefValueValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else
+        anyTypedefValue = jsUndefined();
+    JSValue dictionaryMemberValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "dictionaryMember"));
+    Converter<TestObj::DictionaryThatShouldTolerateNull>::OptionalValue dictionaryMember;
+    if (!dictionaryMemberValue.isUndefined()) {
+        dictionaryMember = convertDictionary<TestObj::DictionaryThatShouldTolerateNull>(state, dictionaryMemberValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
     return TestObj::Dictionary { WTFMove(enumerationValueWithoutDefault), WTFMove(enumerationValueWithDefault), WTFMove(enumerationValueWithEmptyStringDefault), WTFMove(stringWithDefault), WTFMove(stringWithoutDefault), WTFMove(booleanWithDefault), WTFMove(booleanWithoutDefault), WTFMove(sequenceOfStrings), WTFMove(restrictedDouble), WTFMove(unrestrictedDouble), WTFMove(restrictedDoubleWithDefault), WTFMove(unrestrictedDoubleWithDefault), WTFMove(restrictedFloat), WTFMove(unrestrictedFloat), WTFMove(restrictedFloatWithDefault), WTFMove(unrestrictedFloatWithDefault), WTFMove(smallIntegerClamped), WTFMove(smallIntegerWithDefault), WTFMove(smallUnsignedIntegerEnforcedRange), WTFMove(smallUnsignedIntegerWithDefault), WTFMove(integer), WTFMove(integerWithDefault), WTFMove(unsignedInteger), WTFMove(unsignedIntegerWithDefault), WTFMove(largeInteger), WTFMove(largeIntegerWithDefault), WTFMove(unsignedLargeInteger), WTFMove(unsignedLargeIntegerWithDefault), WTF
 Move(nullableNode), WTFMove(anyValue), WTFMove(anyTypedefValue), dictionaryMember.value() };
 }
 
@@ -597,18 +745,49 @@
 {
     VM& vm = state.vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
-    auto* object = value.getObject();
-    if (UNLIKELY(!object || object->type() == RegExpObjectType)) {
+    bool isNullOrUndefined = value.isUndefinedOrNull();
+    auto* object = isNullOrUndefined ? nullptr : value.getObject();
+    if (UNLIKELY(!isNullOrUndefined && !object)) {
         throwTypeError(&state, throwScope);
         return Nullopt;
     }
-    auto requiredEnumerationValue = convert<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "requiredEnumerationValue")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto booleanWithoutDefault = convertOptional<bool>(state, object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto* nonNullableNode = convertWrapperType<Node, JSNode>(state, object->get(&state, Identifier::fromString(&state, "nonNullableNode")), IsNullable::No);
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto requiredDictionaryMember = convertDictionary<TestObj::Dictionary>(state, object->get(&state, Identifier::fromString(&state, "requiredDictionaryMember")));
+    if (UNLIKELY(object && object->type() == RegExpObjectType)) {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue requiredEnumerationValueValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "requiredEnumerationValue"));
+    TestObj::EnumType requiredEnumerationValue;
+    if (!requiredEnumerationValueValue.isUndefined()) {
+        requiredEnumerationValue = convert<TestObj::EnumType>(state, requiredEnumerationValueValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue booleanWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault"));
+    Converter<bool>::OptionalValue booleanWithoutDefault;
+    if (!booleanWithoutDefaultValue.isUndefined()) {
+        booleanWithoutDefault = convert<bool>(state, booleanWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue nonNullableNodeValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "nonNullableNode"));
+    Node* nonNullableNode;
+    if (!nonNullableNodeValue.isUndefined()) {
+        nonNullableNode = convertWrapperType<Node, JSNode>(state, nonNullableNodeValue, IsNullable::No);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue requiredDictionaryMemberValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "requiredDictionaryMember"));
+    TestObj::Dictionary requiredDictionaryMember;
+    if (!requiredDictionaryMemberValue.isUndefined()) {
+        requiredDictionaryMember = convertDictionary<TestObj::Dictionary>(state, requiredDictionaryMemberValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    } else {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
     return TestObj::DictionaryThatShouldNotTolerateNull { WTFMove(requiredEnumerationValue), WTFMove(booleanWithoutDefault), *nonNullableNode, requiredDictionaryMember.value() };
 }
 
@@ -616,16 +795,28 @@
 {
     VM& vm = state.vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
-    if (value.isUndefinedOrNull())
-        return TestObj::DictionaryThatShouldTolerateNull { { }, { } };
-    auto* object = value.getObject();
-    if (UNLIKELY(!object || object->type() == RegExpObjectType)) {
+    bool isNullOrUndefined = value.isUndefinedOrNull();
+    auto* object = isNullOrUndefined ? nullptr : value.getObject();
+    if (UNLIKELY(!isNullOrUndefined && !object)) {
         throwTypeError(&state, throwScope);
         return Nullopt;
     }
-    auto enumerationValue = convertOptional<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "enumerationValue")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto booleanWithoutDefault = convertOptional<bool>(state, object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault")));
+    if (UNLIKELY(object && object->type() == RegExpObjectType)) {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue enumerationValueValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "enumerationValue"));
+    Converter<TestObj::EnumType>::OptionalValue enumerationValue;
+    if (!enumerationValueValue.isUndefined()) {
+        enumerationValue = convert<TestObj::EnumType>(state, enumerationValueValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue booleanWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault"));
+    Converter<bool>::OptionalValue booleanWithoutDefault;
+    if (!booleanWithoutDefaultValue.isUndefined()) {
+        booleanWithoutDefault = convert<bool>(state, booleanWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
     return TestObj::DictionaryThatShouldTolerateNull { WTFMove(enumerationValue), WTFMove(booleanWithoutDefault) };
 }
 
@@ -633,16 +824,28 @@
 {
     VM& vm = state.vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
-    if (value.isUndefinedOrNull())
-        return AlternateDictionaryName { { }, { } };
-    auto* object = value.getObject();
-    if (UNLIKELY(!object || object->type() == RegExpObjectType)) {
+    bool isNullOrUndefined = value.isUndefinedOrNull();
+    auto* object = isNullOrUndefined ? nullptr : value.getObject();
+    if (UNLIKELY(!isNullOrUndefined && !object)) {
         throwTypeError(&state, throwScope);
         return Nullopt;
     }
-    auto enumerationValue = convertOptional<TestObj::EnumType>(state, object->get(&state, Identifier::fromString(&state, "enumerationValue")));
-    RETURN_IF_EXCEPTION(throwScope, Nullopt);
-    auto booleanWithoutDefault = convertOptional<bool>(state, object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault")));
+    if (UNLIKELY(object && object->type() == RegExpObjectType)) {
+        throwTypeError(&state, throwScope);
+        return Nullopt;
+    }
+    JSValue enumerationValueValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "enumerationValue"));
+    Converter<TestObj::EnumType>::OptionalValue enumerationValue;
+    if (!enumerationValueValue.isUndefined()) {
+        enumerationValue = convert<TestObj::EnumType>(state, enumerationValueValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
+    JSValue booleanWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "booleanWithoutDefault"));
+    Converter<bool>::OptionalValue booleanWithoutDefault;
+    if (!booleanWithoutDefaultValue.isUndefined()) {
+        booleanWithoutDefault = convert<bool>(state, booleanWithoutDefaultValue);
+        RETURN_IF_EXCEPTION(throwScope, Nullopt);
+    }
     return AlternateDictionaryName { WTFMove(enumerationValue), WTFMove(booleanWithoutDefault) };
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to