Title: [241198] trunk
Revision
241198
Author
[email protected]
Date
2019-02-08 10:18:28 -0800 (Fri, 08 Feb 2019)

Log Message

[WebIDL] Support serializing sequences and FrozenArrays of non-interfaces
https://bugs.webkit.org/show_bug.cgi?id=190997
<rdar://problem/35983035>

Reviewed by Brent Fulgham.

Source/WebCore:

Support serializing sequences and FrozenArrays of types that aren't interfaces. This is
needed to properly serialize PaymentAddress, which has a FrozenArray of DOMStrings.

We should support serializing sequences of interfaces too, but that's slightly more
complicated since it involves iterating the sequence and serializing each of its items. I
left that as a follow-up task, since I don't see any IDLs that currently need this.

We also don't support serializing sequences with the CachedAttribute or CustomGetter
extended attributes, because WebIDL specifies that a new array should be created when
converting an IDL sequence into an ECMAScript value.

Added bindings test cases to TestSerialization.idl and PaymentAddress test cases to
http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html.

* bindings/scripts/CodeGenerator.pm:
(GetInterfaceForType): Renamed from GetInterfaceForAttribute.
(IsSerializableType): Modified to allow sequences and FrozenArrays of non-interface types.
(hasCachedAttributeOrCustomGetterExtendedAttribute): Added a helper to determine if an
attribute has the CachedAttribute or CustomGetter extended attributes.
(IsSerializableAttribute): Checked for sequences with the CachedAttribute or CustomGetter
extended attributes before calling IsSerializableType.
(GetInterfaceForAttribute): Renamed to GetInterfaceForType.
* bindings/scripts/test/JS/JSTestSerialization.cpp:
* bindings/scripts/test/TestSerialization.idl:

LayoutTests:

* http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (241197 => 241198)


--- trunk/LayoutTests/ChangeLog	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/LayoutTests/ChangeLog	2019-02-08 18:18:28 UTC (rev 241198)
@@ -1,3 +1,13 @@
+2019-02-08  Andy Estes  <[email protected]>
+
+        [WebIDL] Support serializing sequences and FrozenArrays of non-interfaces
+        https://bugs.webkit.org/show_bug.cgi?id=190997
+        <rdar://problem/35983035>
+
+        Reviewed by Brent Fulgham.
+
+        * http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html:
+
 2019-02-08  Eric Liang  <[email protected]>
 
         Check if receive AXPressDidFail notification when performing AXPress action on disabled MenuList.

Modified: trunk/LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html (241197 => 241198)


--- trunk/LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html	2019-02-08 18:18:28 UTC (rev 241198)
@@ -38,7 +38,8 @@
       },
       "Array must be frozen"
     );
-    for (let [attr, expectedValue] of Object.entries(expected)) {
+    const expectedEntries = Object.entries(expected);
+    for (let [attr, expectedValue] of expectedEntries) {
       assert_idl_attribute(addr, attr);
       const msg = `Expected paymentAddress.${attr} to equal ${expectedValue}.`;
       //.toString() flattens array addressLine,
@@ -48,12 +49,22 @@
       assert_equals(actualValue, expectedValue, msg);
     }
     // Check toJSON result
-    for (let [prop, jsonValue] of Object.entries(addr.toJSON())) {
+    const jsonAddress = addr.toJSON();
+    const jsonAddressEntries = Object.entries(jsonAddress);
+    for (let [prop, jsonValue] of jsonAddressEntries) {
       const actualValue = jsonValue.toString().toLowerCase();
       const expectedValue = expected[prop].toString().toLowerCase();
       const msg = `Expected JSON ${prop} to be ${expectedValue}`;
       assert_equals(actualValue, expectedValue, msg);
     }
+    assert_equals(jsonAddressEntries.length, expectedEntries.length);
+    // Check that .toJSON() created a frozen array
+    assert_throws(
+      new TypeError(),
+      () => {
+        jsonAddress.addressLine.push("this must throw");
+      },
+    );
   }, button.textContent.trim());
   done();
 }

Modified: trunk/Source/WebCore/ChangeLog (241197 => 241198)


--- trunk/Source/WebCore/ChangeLog	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/Source/WebCore/ChangeLog	2019-02-08 18:18:28 UTC (rev 241198)
@@ -1,3 +1,36 @@
+2019-02-08  Andy Estes  <[email protected]>
+
+        [WebIDL] Support serializing sequences and FrozenArrays of non-interfaces
+        https://bugs.webkit.org/show_bug.cgi?id=190997
+        <rdar://problem/35983035>
+
+        Reviewed by Brent Fulgham.
+
+        Support serializing sequences and FrozenArrays of types that aren't interfaces. This is
+        needed to properly serialize PaymentAddress, which has a FrozenArray of DOMStrings.
+
+        We should support serializing sequences of interfaces too, but that's slightly more
+        complicated since it involves iterating the sequence and serializing each of its items. I
+        left that as a follow-up task, since I don't see any IDLs that currently need this.
+
+        We also don't support serializing sequences with the CachedAttribute or CustomGetter
+        extended attributes, because WebIDL specifies that a new array should be created when
+        converting an IDL sequence into an ECMAScript value.
+
+        Added bindings test cases to TestSerialization.idl and PaymentAddress test cases to
+        http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html.
+
+        * bindings/scripts/CodeGenerator.pm:
+        (GetInterfaceForType): Renamed from GetInterfaceForAttribute.
+        (IsSerializableType): Modified to allow sequences and FrozenArrays of non-interface types.
+        (hasCachedAttributeOrCustomGetterExtendedAttribute): Added a helper to determine if an
+        attribute has the CachedAttribute or CustomGetter extended attributes.
+        (IsSerializableAttribute): Checked for sequences with the CachedAttribute or CustomGetter
+        extended attributes before calling IsSerializableType.
+        (GetInterfaceForAttribute): Renamed to GetInterfaceForType.
+        * bindings/scripts/test/JS/JSTestSerialization.cpp:
+        * bindings/scripts/test/TestSerialization.idl:
+
 2019-02-08  Sihui Liu  <[email protected]>
 
         IndexedDB tests leak documents

Modified: trunk/Source/WebCore/bindings/scripts/CodeGenerator.pm (241197 => 241198)


--- trunk/Source/WebCore/bindings/scripts/CodeGenerator.pm	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/Source/WebCore/bindings/scripts/CodeGenerator.pm	2019-02-08 18:18:28 UTC (rev 241198)
@@ -317,13 +317,13 @@
     return $idlFiles->{$interfaceName};
 }
 
-sub GetInterfaceForAttribute
+sub GetInterfaceForType
 {
-    my ($object, $currentInterface, $attribute) = @_;
+    my ($object, $currentInterface, $type) = @_;
 
-    return undef unless $object->IsInterfaceType($attribute->type);
+    return undef unless $object->IsInterfaceType($type);
 
-    return $object->ParseInterface($currentInterface, $attribute->type->name);
+    return $object->ParseInterface($currentInterface, $type->name);
 }
 
 sub GetAttributeFromInterface
@@ -935,13 +935,12 @@
     return $anyParentIsSerializable;
 }
 
-sub IsSerializableAttribute
+sub IsSerializableType
 {
-    my ($object, $interface, $attribute) = @_;
+    my ($object, $interface, $type) = @_;
 
     # https://heycam.github.io/webidl/#dfn-serializable-type
 
-    my $type = $attribute->type;
     return 1 if $type->name eq "boolean";
     return 1 if $object->IsNumericType($type);
     return 1 if $object->IsEnumType($type);
@@ -948,21 +947,47 @@
     return 1 if $object->IsStringType($type);
     return 0 if $type->name eq "EventHandler";
 
-    if ($type->isUnion || $object->IsSequenceType($type) || $object->IsDictionaryType($type)) {
-        die "Serializer for non-primitive types is not currently supported\n";
+    if ($type->isUnion || $object->IsDictionaryType($type)) {
+        die "Serializers for union and dictionary types are not currently supported.\n";
     }
 
+    if ($object->IsSequenceOrFrozenArrayType($type)) {
+        my $subtype = @{$type->subtypes}[0];
+
+        # FIXME: webkit.org/b/194439 [WebIDL] Support serializing sequences and FrozenArrays of interfaces
+        return 0 if $object->IsInterfaceType($subtype);
+
+        return $object->IsSerializableType($interface, $subtype);
+    }
+
     return 0 if !$object->IsInterfaceType($type);
 
-    my $interfaceForAttribute = $object->GetInterfaceForAttribute($interface, $attribute);
-    if ($interfaceForAttribute) {
-        return 1 if $interfaceForAttribute->serializable;
-        return $object->InheritsSerializable($interfaceForAttribute);
+    my $interfaceForType = $object->GetInterfaceForType($interface, $type);
+    if ($interfaceForType) {
+        return 1 if $interfaceForType->serializable;
+        return $object->InheritsSerializable($interfaceForType);
     }
 
     return 0;
 }
 
+sub hasCachedAttributeOrCustomGetterExtendedAttribute
+{
+    my ($attribute) = @_;
+    return $attribute->extendedAttributes->{CachedAttribute} || $attribute->extendedAttributes->{CustomGetter};
+}
+
+sub IsSerializableAttribute
+{
+    my ($object, $interface, $attribute) = @_;
+
+    if ($object->IsSequenceType($attribute->type) && hasCachedAttributeOrCustomGetterExtendedAttribute($attribute)) {
+        die "Serializers for sequence types with CachedAttribute or CustomGetter extended attributes are not currently supported.\n";
+    }
+
+    return $object->IsSerializableType($interface, $attribute->type);
+}
+
 sub GetInterfaceExtendedAttributesFromName
 {
     # FIXME: It's bad to have a function like this that opens another IDL file to answer a question.

Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp (241197 => 241198)


--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp	2019-02-08 18:18:28 UTC (rev 241198)
@@ -24,9 +24,11 @@
 #include "JSDOMAttribute.h"
 #include "JSDOMBinding.h"
 #include "JSDOMConstructorNotConstructable.h"
+#include "JSDOMConvertBoolean.h"
 #include "JSDOMConvertInterface.h"
 #include "JSDOMConvertNullable.h"
 #include "JSDOMConvertNumbers.h"
+#include "JSDOMConvertSequences.h"
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMGlobalObject.h"
@@ -38,6 +40,7 @@
 #include "ScriptExecutionContext.h"
 #include <_javascript_Core/FunctionPrototype.h>
 #include <_javascript_Core/HeapSnapshotBuilder.h>
+#include <_javascript_Core/JSArray.h>
 #include <_javascript_Core/JSCInlines.h>
 #include <_javascript_Core/ObjectConstructor.h>
 #include <wtf/GetPtr.h>
@@ -74,6 +77,12 @@
 bool setJSTestSerializationEighthIndirectlyAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
 JSC::EncodedJSValue jsTestSerializationNinthOptionalDirectlySerializableAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
 bool setJSTestSerializationNinthOptionalDirectlySerializableAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
+JSC::EncodedJSValue jsTestSerializationTenthFrozenArrayAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
+bool setJSTestSerializationTenthFrozenArrayAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
+JSC::EncodedJSValue jsTestSerializationEleventhSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
+bool setJSTestSerializationEleventhSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
+JSC::EncodedJSValue jsTestSerializationTwelfthInterfaceSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
+bool setJSTestSerializationTwelfthInterfaceSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
 
 class JSTestSerializationPrototype : public JSC::JSNonFinalObject {
 public:
@@ -131,6 +140,9 @@
     { "seventhDirectlySerializableAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationSeventhDirectlySerializableAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationSeventhDirectlySerializableAttribute) } },
     { "eighthIndirectlyAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationEighthIndirectlyAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationEighthIndirectlyAttribute) } },
     { "ninthOptionalDirectlySerializableAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationNinthOptionalDirectlySerializableAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationNinthOptionalDirectlySerializableAttribute) } },
+    { "tenthFrozenArrayAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationTenthFrozenArrayAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationTenthFrozenArrayAttribute) } },
+    { "eleventhSequenceAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationEleventhSequenceAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationEleventhSequenceAttribute) } },
+    { "twelfthInterfaceSequenceAttribute", static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestSerializationTwelfthInterfaceSequenceAttribute), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestSerializationTwelfthInterfaceSequenceAttribute) } },
     { "toJSON", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(jsTestSerializationPrototypeFunctionToJSON), (intptr_t) (0) } },
 };
 
@@ -489,6 +501,99 @@
     return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationNinthOptionalDirectlySerializableAttributeSetter>(*state, thisValue, encodedValue, "ninthOptionalDirectlySerializableAttribute");
 }
 
+static inline JSValue jsTestSerializationTenthFrozenArrayAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    UNUSED_PARAM(state);
+    auto& impl = thisObject.wrapped();
+    JSValue result = toJS<IDLFrozenArray<IDLBoolean>>(state, *thisObject.globalObject(), throwScope, impl.tenthFrozenArrayAttribute());
+    return result;
+}
+
+EncodedJSValue jsTestSerializationTenthFrozenArrayAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
+{
+    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationTenthFrozenArrayAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "tenthFrozenArrayAttribute");
+}
+
+static inline bool setJSTestSerializationTenthFrozenArrayAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    auto& impl = thisObject.wrapped();
+    auto nativeValue = convert<IDLFrozenArray<IDLBoolean>>(state, value);
+    RETURN_IF_EXCEPTION(throwScope, false);
+    AttributeSetter::call(state, throwScope, [&] {
+        return impl.setTenthFrozenArrayAttribute(WTFMove(nativeValue));
+    });
+    return true;
+}
+
+bool setJSTestSerializationTenthFrozenArrayAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
+{
+    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationTenthFrozenArrayAttributeSetter>(*state, thisValue, encodedValue, "tenthFrozenArrayAttribute");
+}
+
+static inline JSValue jsTestSerializationEleventhSequenceAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    UNUSED_PARAM(state);
+    auto& impl = thisObject.wrapped();
+    JSValue result = toJS<IDLSequence<IDLDOMString>>(state, *thisObject.globalObject(), throwScope, impl.eleventhSequenceAttribute());
+    return result;
+}
+
+EncodedJSValue jsTestSerializationEleventhSequenceAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
+{
+    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationEleventhSequenceAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "eleventhSequenceAttribute");
+}
+
+static inline bool setJSTestSerializationEleventhSequenceAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    auto& impl = thisObject.wrapped();
+    auto nativeValue = convert<IDLSequence<IDLDOMString>>(state, value);
+    RETURN_IF_EXCEPTION(throwScope, false);
+    AttributeSetter::call(state, throwScope, [&] {
+        return impl.setEleventhSequenceAttribute(WTFMove(nativeValue));
+    });
+    return true;
+}
+
+bool setJSTestSerializationEleventhSequenceAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
+{
+    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationEleventhSequenceAttributeSetter>(*state, thisValue, encodedValue, "eleventhSequenceAttribute");
+}
+
+static inline JSValue jsTestSerializationTwelfthInterfaceSequenceAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    UNUSED_PARAM(state);
+    auto& impl = thisObject.wrapped();
+    JSValue result = toJS<IDLSequence<IDLInterface<TestSerializationInheritFinal>>>(state, *thisObject.globalObject(), throwScope, impl.twelfthInterfaceSequenceAttribute());
+    return result;
+}
+
+EncodedJSValue jsTestSerializationTwelfthInterfaceSequenceAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
+{
+    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationTwelfthInterfaceSequenceAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "twelfthInterfaceSequenceAttribute");
+}
+
+static inline bool setJSTestSerializationTwelfthInterfaceSequenceAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
+{
+    UNUSED_PARAM(throwScope);
+    auto& impl = thisObject.wrapped();
+    auto nativeValue = convert<IDLSequence<IDLInterface<TestSerializationInheritFinal>>>(state, value);
+    RETURN_IF_EXCEPTION(throwScope, false);
+    AttributeSetter::call(state, throwScope, [&] {
+        return impl.setTwelfthInterfaceSequenceAttribute(WTFMove(nativeValue));
+    });
+    return true;
+}
+
+bool setJSTestSerializationTwelfthInterfaceSequenceAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
+{
+    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationTwelfthInterfaceSequenceAttributeSetter>(*state, thisValue, encodedValue, "twelfthInterfaceSequenceAttribute");
+}
+
 JSC::JSObject* JSTestSerialization::serialize(ExecState& state, JSTestSerialization& thisObject, JSDOMGlobalObject& globalObject, ThrowScope& throwScope)
 {
     auto& vm = state.vm();
@@ -532,6 +637,14 @@
     } else
         result->putDirect(vm, Identifier::fromString(&vm, "ninthOptionalDirectlySerializableAttribute"), ninthOptionalDirectlySerializableAttributeValue);
 
+    auto tenthFrozenArrayAttributeValue = jsTestSerializationTenthFrozenArrayAttributeGetter(state, thisObject, throwScope);
+    throwScope.assertNoException();
+    result->putDirect(vm, Identifier::fromString(&vm, "tenthFrozenArrayAttribute"), tenthFrozenArrayAttributeValue);
+
+    auto eleventhSequenceAttributeValue = jsTestSerializationEleventhSequenceAttributeGetter(state, thisObject, throwScope);
+    throwScope.assertNoException();
+    result->putDirect(vm, Identifier::fromString(&vm, "eleventhSequenceAttribute"), eleventhSequenceAttributeValue);
+
     return result;
 }
 

Modified: trunk/Source/WebCore/bindings/scripts/test/TestSerialization.idl (241197 => 241198)


--- trunk/Source/WebCore/bindings/scripts/test/TestSerialization.idl	2019-02-08 17:18:08 UTC (rev 241197)
+++ trunk/Source/WebCore/bindings/scripts/test/TestSerialization.idl	2019-02-08 18:18:28 UTC (rev 241198)
@@ -37,5 +37,9 @@
     attribute TestSerializationIndirectInheritance eighthIndirectlyAttribute;
     attribute TestSerializationInheritFinal? ninthOptionalDirectlySerializableAttribute;
 
+    attribute FrozenArray<boolean> tenthFrozenArrayAttribute;
+    attribute sequence<DOMString> eleventhSequenceAttribute;
+    attribute sequence<TestSerializationInheritFinal> twelfthInterfaceSequenceAttribute;
+
     serializer = { attribute };
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to