Changeset 241198 in webkit


Ignore:
Timestamp:
Feb 8, 2019 10:18:28 AM (5 years ago)
Author:
aestes@apple.com
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:
Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r241190 r241198  
     12019-02-08  Andy Estes  <aestes@apple.com>
     2
     3        [WebIDL] Support serializing sequences and FrozenArrays of non-interfaces
     4        https://bugs.webkit.org/show_bug.cgi?id=190997
     5        <rdar://problem/35983035>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        * http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html:
     10
    1112019-02-08  Eric Liang  <ericliang@apple.com>
    212
  • trunk/LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html

    r237597 r241198  
    3939      "Array must be frozen"
    4040    );
    41     for (let [attr, expectedValue] of Object.entries(expected)) {
     41    const expectedEntries = Object.entries(expected);
     42    for (let [attr, expectedValue] of expectedEntries) {
    4243      assert_idl_attribute(addr, attr);
    4344      const msg = `Expected paymentAddress.${attr} to equal ${expectedValue}.`;
     
    4950    }
    5051    // Check toJSON result
    51     for (let [prop, jsonValue] of Object.entries(addr.toJSON())) {
     52    const jsonAddress = addr.toJSON();
     53    const jsonAddressEntries = Object.entries(jsonAddress);
     54    for (let [prop, jsonValue] of jsonAddressEntries) {
    5255      const actualValue = jsonValue.toString().toLowerCase();
    5356      const expectedValue = expected[prop].toString().toLowerCase();
     
    5558      assert_equals(actualValue, expectedValue, msg);
    5659    }
     60    assert_equals(jsonAddressEntries.length, expectedEntries.length);
     61    // Check that .toJSON() created a frozen array
     62    assert_throws(
     63      new TypeError(),
     64      () => {
     65        jsonAddress.addressLine.push("this must throw");
     66      },
     67    );
    5768  }, button.textContent.trim());
    5869  done();
  • trunk/Source/WebCore/ChangeLog

    r241196 r241198  
     12019-02-08  Andy Estes  <aestes@apple.com>
     2
     3        [WebIDL] Support serializing sequences and FrozenArrays of non-interfaces
     4        https://bugs.webkit.org/show_bug.cgi?id=190997
     5        <rdar://problem/35983035>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Support serializing sequences and FrozenArrays of types that aren't interfaces. This is
     10        needed to properly serialize PaymentAddress, which has a FrozenArray of DOMStrings.
     11
     12        We should support serializing sequences of interfaces too, but that's slightly more
     13        complicated since it involves iterating the sequence and serializing each of its items. I
     14        left that as a follow-up task, since I don't see any IDLs that currently need this.
     15
     16        We also don't support serializing sequences with the CachedAttribute or CustomGetter
     17        extended attributes, because WebIDL specifies that a new array should be created when
     18        converting an IDL sequence into an ECMAScript value.
     19
     20        Added bindings test cases to TestSerialization.idl and PaymentAddress test cases to
     21        http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html.
     22
     23        * bindings/scripts/CodeGenerator.pm:
     24        (GetInterfaceForType): Renamed from GetInterfaceForAttribute.
     25        (IsSerializableType): Modified to allow sequences and FrozenArrays of non-interface types.
     26        (hasCachedAttributeOrCustomGetterExtendedAttribute): Added a helper to determine if an
     27        attribute has the CachedAttribute or CustomGetter extended attributes.
     28        (IsSerializableAttribute): Checked for sequences with the CachedAttribute or CustomGetter
     29        extended attributes before calling IsSerializableType.
     30        (GetInterfaceForAttribute): Renamed to GetInterfaceForType.
     31        * bindings/scripts/test/JS/JSTestSerialization.cpp:
     32        * bindings/scripts/test/TestSerialization.idl:
     33
    1342019-02-08  Sihui Liu  <sihui_liu@apple.com>
    235
  • trunk/Source/WebCore/bindings/scripts/CodeGenerator.pm

    r237268 r241198  
    318318}
    319319
    320 sub GetInterfaceForAttribute
    321 {
    322     my ($object, $currentInterface, $attribute) = @_;
    323 
    324     return undef unless $object->IsInterfaceType($attribute->type);
    325 
    326     return $object->ParseInterface($currentInterface, $attribute->type->name);
     320sub GetInterfaceForType
     321{
     322    my ($object, $currentInterface, $type) = @_;
     323
     324    return undef unless $object->IsInterfaceType($type);
     325
     326    return $object->ParseInterface($currentInterface, $type->name);
    327327}
    328328
     
    936936}
    937937
    938 sub IsSerializableAttribute
    939 {
    940     my ($object, $interface, $attribute) = @_;
     938sub IsSerializableType
     939{
     940    my ($object, $interface, $type) = @_;
    941941
    942942    # https://heycam.github.io/webidl/#dfn-serializable-type
    943943
    944     my $type = $attribute->type;
    945944    return 1 if $type->name eq "boolean";
    946945    return 1 if $object->IsNumericType($type);
     
    949948    return 0 if $type->name eq "EventHandler";
    950949
    951     if ($type->isUnion || $object->IsSequenceType($type) || $object->IsDictionaryType($type)) {
    952         die "Serializer for non-primitive types is not currently supported\n";
     950    if ($type->isUnion || $object->IsDictionaryType($type)) {
     951        die "Serializers for union and dictionary types are not currently supported.\n";
     952    }
     953
     954    if ($object->IsSequenceOrFrozenArrayType($type)) {
     955        my $subtype = @{$type->subtypes}[0];
     956
     957        # FIXME: webkit.org/b/194439 [WebIDL] Support serializing sequences and FrozenArrays of interfaces
     958        return 0 if $object->IsInterfaceType($subtype);
     959
     960        return $object->IsSerializableType($interface, $subtype);
    953961    }
    954962
    955963    return 0 if !$object->IsInterfaceType($type);
    956964
    957     my $interfaceForAttribute = $object->GetInterfaceForAttribute($interface, $attribute);
    958     if ($interfaceForAttribute) {
    959         return 1 if $interfaceForAttribute->serializable;
    960         return $object->InheritsSerializable($interfaceForAttribute);
     965    my $interfaceForType = $object->GetInterfaceForType($interface, $type);
     966    if ($interfaceForType) {
     967        return 1 if $interfaceForType->serializable;
     968        return $object->InheritsSerializable($interfaceForType);
    961969    }
    962970
    963971    return 0;
     972}
     973
     974sub hasCachedAttributeOrCustomGetterExtendedAttribute
     975{
     976    my ($attribute) = @_;
     977    return $attribute->extendedAttributes->{CachedAttribute} || $attribute->extendedAttributes->{CustomGetter};
     978}
     979
     980sub IsSerializableAttribute
     981{
     982    my ($object, $interface, $attribute) = @_;
     983
     984    if ($object->IsSequenceType($attribute->type) && hasCachedAttributeOrCustomGetterExtendedAttribute($attribute)) {
     985        die "Serializers for sequence types with CachedAttribute or CustomGetter extended attributes are not currently supported.\n";
     986    }
     987
     988    return $object->IsSerializableType($interface, $attribute->type);
    964989}
    965990
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp

    r240557 r241198  
    2525#include "JSDOMBinding.h"
    2626#include "JSDOMConstructorNotConstructable.h"
     27#include "JSDOMConvertBoolean.h"
    2728#include "JSDOMConvertInterface.h"
    2829#include "JSDOMConvertNullable.h"
    2930#include "JSDOMConvertNumbers.h"
     31#include "JSDOMConvertSequences.h"
    3032#include "JSDOMConvertStrings.h"
    3133#include "JSDOMExceptionHandling.h"
     
    3941#include <JavaScriptCore/FunctionPrototype.h>
    4042#include <JavaScriptCore/HeapSnapshotBuilder.h>
     43#include <JavaScriptCore/JSArray.h>
    4144#include <JavaScriptCore/JSCInlines.h>
    4245#include <JavaScriptCore/ObjectConstructor.h>
     
    7578JSC::EncodedJSValue jsTestSerializationNinthOptionalDirectlySerializableAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
    7679bool setJSTestSerializationNinthOptionalDirectlySerializableAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     80JSC::EncodedJSValue jsTestSerializationTenthFrozenArrayAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     81bool setJSTestSerializationTenthFrozenArrayAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     82JSC::EncodedJSValue jsTestSerializationEleventhSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     83bool setJSTestSerializationEleventhSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     84JSC::EncodedJSValue jsTestSerializationTwelfthInterfaceSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     85bool setJSTestSerializationTwelfthInterfaceSequenceAttribute(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
    7786
    7887class JSTestSerializationPrototype : public JSC::JSNonFinalObject {
     
    132141    { "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) } },
    133142    { "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) } },
     143    { "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) } },
     144    { "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) } },
     145    { "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) } },
    134146    { "toJSON", static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(jsTestSerializationPrototypeFunctionToJSON), (intptr_t) (0) } },
    135147};
     
    490502}
    491503
     504static inline JSValue jsTestSerializationTenthFrozenArrayAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
     505{
     506    UNUSED_PARAM(throwScope);
     507    UNUSED_PARAM(state);
     508    auto& impl = thisObject.wrapped();
     509    JSValue result = toJS<IDLFrozenArray<IDLBoolean>>(state, *thisObject.globalObject(), throwScope, impl.tenthFrozenArrayAttribute());
     510    return result;
     511}
     512
     513EncodedJSValue jsTestSerializationTenthFrozenArrayAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
     514{
     515    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationTenthFrozenArrayAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "tenthFrozenArrayAttribute");
     516}
     517
     518static inline bool setJSTestSerializationTenthFrozenArrayAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
     519{
     520    UNUSED_PARAM(throwScope);
     521    auto& impl = thisObject.wrapped();
     522    auto nativeValue = convert<IDLFrozenArray<IDLBoolean>>(state, value);
     523    RETURN_IF_EXCEPTION(throwScope, false);
     524    AttributeSetter::call(state, throwScope, [&] {
     525        return impl.setTenthFrozenArrayAttribute(WTFMove(nativeValue));
     526    });
     527    return true;
     528}
     529
     530bool setJSTestSerializationTenthFrozenArrayAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
     531{
     532    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationTenthFrozenArrayAttributeSetter>(*state, thisValue, encodedValue, "tenthFrozenArrayAttribute");
     533}
     534
     535static inline JSValue jsTestSerializationEleventhSequenceAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
     536{
     537    UNUSED_PARAM(throwScope);
     538    UNUSED_PARAM(state);
     539    auto& impl = thisObject.wrapped();
     540    JSValue result = toJS<IDLSequence<IDLDOMString>>(state, *thisObject.globalObject(), throwScope, impl.eleventhSequenceAttribute());
     541    return result;
     542}
     543
     544EncodedJSValue jsTestSerializationEleventhSequenceAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
     545{
     546    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationEleventhSequenceAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "eleventhSequenceAttribute");
     547}
     548
     549static inline bool setJSTestSerializationEleventhSequenceAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
     550{
     551    UNUSED_PARAM(throwScope);
     552    auto& impl = thisObject.wrapped();
     553    auto nativeValue = convert<IDLSequence<IDLDOMString>>(state, value);
     554    RETURN_IF_EXCEPTION(throwScope, false);
     555    AttributeSetter::call(state, throwScope, [&] {
     556        return impl.setEleventhSequenceAttribute(WTFMove(nativeValue));
     557    });
     558    return true;
     559}
     560
     561bool setJSTestSerializationEleventhSequenceAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
     562{
     563    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationEleventhSequenceAttributeSetter>(*state, thisValue, encodedValue, "eleventhSequenceAttribute");
     564}
     565
     566static inline JSValue jsTestSerializationTwelfthInterfaceSequenceAttributeGetter(ExecState& state, JSTestSerialization& thisObject, ThrowScope& throwScope)
     567{
     568    UNUSED_PARAM(throwScope);
     569    UNUSED_PARAM(state);
     570    auto& impl = thisObject.wrapped();
     571    JSValue result = toJS<IDLSequence<IDLInterface<TestSerializationInheritFinal>>>(state, *thisObject.globalObject(), throwScope, impl.twelfthInterfaceSequenceAttribute());
     572    return result;
     573}
     574
     575EncodedJSValue jsTestSerializationTwelfthInterfaceSequenceAttribute(ExecState* state, EncodedJSValue thisValue, PropertyName)
     576{
     577    return IDLAttribute<JSTestSerialization>::get<jsTestSerializationTwelfthInterfaceSequenceAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "twelfthInterfaceSequenceAttribute");
     578}
     579
     580static inline bool setJSTestSerializationTwelfthInterfaceSequenceAttributeSetter(ExecState& state, JSTestSerialization& thisObject, JSValue value, ThrowScope& throwScope)
     581{
     582    UNUSED_PARAM(throwScope);
     583    auto& impl = thisObject.wrapped();
     584    auto nativeValue = convert<IDLSequence<IDLInterface<TestSerializationInheritFinal>>>(state, value);
     585    RETURN_IF_EXCEPTION(throwScope, false);
     586    AttributeSetter::call(state, throwScope, [&] {
     587        return impl.setTwelfthInterfaceSequenceAttribute(WTFMove(nativeValue));
     588    });
     589    return true;
     590}
     591
     592bool setJSTestSerializationTwelfthInterfaceSequenceAttribute(ExecState* state, EncodedJSValue thisValue, EncodedJSValue encodedValue)
     593{
     594    return IDLAttribute<JSTestSerialization>::set<setJSTestSerializationTwelfthInterfaceSequenceAttributeSetter>(*state, thisValue, encodedValue, "twelfthInterfaceSequenceAttribute");
     595}
     596
    492597JSC::JSObject* JSTestSerialization::serialize(ExecState& state, JSTestSerialization& thisObject, JSDOMGlobalObject& globalObject, ThrowScope& throwScope)
    493598{
     
    532637    } else
    533638        result->putDirect(vm, Identifier::fromString(&vm, "ninthOptionalDirectlySerializableAttribute"), ninthOptionalDirectlySerializableAttributeValue);
     639
     640    auto tenthFrozenArrayAttributeValue = jsTestSerializationTenthFrozenArrayAttributeGetter(state, thisObject, throwScope);
     641    throwScope.assertNoException();
     642    result->putDirect(vm, Identifier::fromString(&vm, "tenthFrozenArrayAttribute"), tenthFrozenArrayAttributeValue);
     643
     644    auto eleventhSequenceAttributeValue = jsTestSerializationEleventhSequenceAttributeGetter(state, thisObject, throwScope);
     645    throwScope.assertNoException();
     646    result->putDirect(vm, Identifier::fromString(&vm, "eleventhSequenceAttribute"), eleventhSequenceAttributeValue);
    534647
    535648    return result;
  • trunk/Source/WebCore/bindings/scripts/test/TestSerialization.idl

    r223780 r241198  
    3838    attribute TestSerializationInheritFinal? ninthOptionalDirectlySerializableAttribute;
    3939
     40    attribute FrozenArray<boolean> tenthFrozenArrayAttribute;
     41    attribute sequence<DOMString> eleventhSequenceAttribute;
     42    attribute sequence<TestSerializationInheritFinal> twelfthInterfaceSequenceAttribute;
     43
    4044    serializer = { attribute };
    4145};
Note: See TracChangeset for help on using the changeset viewer.