Bug 1268798 part 3 - Add LenientSetter extended attribute. r?khuey draft
authorXidorn Quan <quanxunzhen@gmail.com>
Thu, 05 May 2016 20:31:02 +1000
changeset 363678 7e661883c87ffee39bd783632749966bdb37d1c6
parent 363677 5bbdb0e996c29867a16e59747d64f4947bf0af93
child 363679 2bebff003e9110b190378c57dec1f1549f7a3001
push id17285
push userxquan@mozilla.com
push dateThu, 05 May 2016 10:34:05 +0000
reviewerskhuey
bugs1268798
milestone49.0a1
Bug 1268798 part 3 - Add LenientSetter extended attribute. r?khuey MozReview-Commit-ID: 61wybyS36KE
dom/base/nsDeprecatedOperationList.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_lenientSetter.py
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -39,8 +39,9 @@ DEPRECATED_OPERATION(SyncXMLHttpRequest)
 DEPRECATED_OPERATION(DataContainerEvent)
 DEPRECATED_OPERATION(Window_Controllers)
 DEPRECATED_OPERATION(ImportXULIntoContent)
 DEPRECATED_OPERATION(PannerNodeDoppler)
 DEPRECATED_OPERATION(NavigatorGetUserMedia)
 DEPRECATED_OPERATION(WebrtcDeprecatedPrefix)
 DEPRECATED_OPERATION(AppCache)
 DEPRECATED_OPERATION(PrefixedFullscreenAPI)
+DEPRECATED_OPERATION(LenientSetter)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2543,17 +2543,18 @@ class AttrDefiner(PropertyDefiner):
                 jitinfo = ("&%s_getterinfo" %
                            IDLToCIdentifier(attr.identifier.name))
             return "{ { %s, %s } }" % \
                    (accessor, jitinfo)
 
         def setter(attr):
             if (attr.readonly and
                 attr.getExtendedAttribute("PutForwards") is None and
-                attr.getExtendedAttribute("Replaceable") is None):
+                attr.getExtendedAttribute("Replaceable") is None and
+                attr.getExtendedAttribute("LenientSetter") is None):
                 return "JSNATIVE_WRAPPER(nullptr)"
             if self.static:
                 accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
                 jitinfo = "nullptr"
             else:
                 if attr.hasLenientThis():
                     accessor = "genericLenientSetter"
                 elif IsCrossOriginWritable(attr, self.descriptor):
@@ -8827,16 +8828,34 @@ class CGSpecializedReplaceableSetter(CGS
     def definition_body(self):
         attrName = self.attr.identifier.name
         # JS_DefineProperty can only deal with ASCII
         assert all(ord(c) < 128 for c in attrName)
         return ('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
                 attrName)
 
 
+class CGSpecializedLenientSetter(CGSpecializedSetter):
+    """
+    A class for generating the code for a specialized attribute setter with
+    LenientSetter that the JIT can call with lower overhead.
+    """
+    def __init__(self, descriptor, attr):
+        CGSpecializedSetter.__init__(self, descriptor, attr)
+
+    def definition_body(self):
+        attrName = self.attr.identifier.name
+        # JS_DefineProperty can only deal with ASCII
+        assert all(ord(c) < 128 for c in attrName)
+        return dedent("""
+            DeprecationWarning(cx, obj, nsIDocument::eLenientSetter);
+            return true;
+            """)
+
+
 def memberReturnsNewObject(member):
     return member.getExtendedAttribute("NewObject") is not None
 
 
 class CGMemberJITInfo(CGThing):
     """
     A class for generating the JITInfo for a property that points to
     our specialized getter and setter.
@@ -8964,17 +8983,18 @@ class CGMemberJITInfo(CGThing):
 
             result = self.defineJitInfo(getterinfo, getter, "Getter",
                                         getterinfal, movable, eliminatable,
                                         aliasSet, isAlwaysInSlot,
                                         isLazilyCachedInSlot, slotIndex,
                                         [self.member.type], None)
             if (not self.member.readonly or
                 self.member.getExtendedAttribute("PutForwards") is not None or
-                self.member.getExtendedAttribute("Replaceable") is not None):
+                self.member.getExtendedAttribute("Replaceable") is not None or
+                self.member.getExtendedAttribute("LenientSetter") is not None):
                 setterinfo = ("%s_setterinfo" %
                               IDLToCIdentifier(self.member.identifier.name))
                 # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
                 # union.
                 setter = ("(JSJitGetterOp)set_%s" %
                           IDLToCIdentifier(self.member.identifier.name))
                 # Setters are always fallible, since they have to do a typed unwrap.
                 result += self.defineJitInfo(setterinfo, setter, "Setter",
@@ -11834,17 +11854,18 @@ def memberProperties(m, descriptor):
                     props.isCrossOriginSetter = True
                 elif descriptor.needsSpecialGenericOps():
                     props.isGenericSetter = True
         elif m.getExtendedAttribute("PutForwards"):
             if IsCrossOriginWritable(m, descriptor):
                 props.isCrossOriginSetter = True
             elif descriptor.needsSpecialGenericOps():
                 props.isGenericSetter = True
-        elif m.getExtendedAttribute("Replaceable"):
+        elif (m.getExtendedAttribute("Replaceable") or
+              m.getExtendedAttribute("LenientSetter")):
             if descriptor.needsSpecialGenericOps():
                 props.isGenericSetter = True
 
     return props
 
 
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
@@ -11946,16 +11967,18 @@ class CGDescriptor(CGThing):
                         if props.isCrossOriginSetter:
                             crossOriginSetters.add(m.identifier.name)
                 elif m.getExtendedAttribute("PutForwards"):
                     cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
                     if props.isCrossOriginSetter:
                         crossOriginSetters.add(m.identifier.name)
                 elif m.getExtendedAttribute("Replaceable"):
                     cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
+                elif m.getExtendedAttribute("LenientSetter"):
+                    cgThings.append(CGSpecializedLenientSetter(descriptor, m))
                 if (not m.isStatic() and
                     descriptor.interface.hasInterfacePrototypeObject()):
                     cgThings.append(CGMemberJITInfo(descriptor, m))
 
             hasMethod = hasMethod or props.isGenericMethod
             hasPromiseReturningMethod = (hasPromiseReturningMethod or
                                          props.isPromiseReturningMethod)
             hasGetter = hasGetter or props.isGenericGetter
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4057,16 +4057,34 @@ class IDLAttribute(IDLInterfaceMember):
                                   "attributes", [attr.location, self.location])
             if self.isStatic():
                 raise WebIDLError("[Replaceable] is only allowed on non-static "
                                   "attributes", [attr.location, self.location])
             if self.getExtendedAttribute("PutForwards") is not None:
                 raise WebIDLError("[PutForwards] and [Replaceable] can't both "
                                   "appear on the same attribute",
                                   [attr.location, self.location])
+        elif identifier == "LenientSetter":
+            if not attr.noArguments():
+                raise WebIDLError("[LenientSetter] must take no arguments",
+                                  [attr.location])
+            if not self.readonly:
+                raise WebIDLError("[LenientSetter] is only allowed on readonly "
+                                  "attributes", [attr.location, self.location])
+            if self.isStatic():
+                raise WebIDLError("[LenientSetter] is only allowed on non-static "
+                                  "attributes", [attr.location, self.location])
+            if self.getExtendedAttribute("PutForwards") is not None:
+                raise WebIDLError("[LenientSetter] and [PutForwards] can't both "
+                                  "appear on the same attribute",
+                                  [attr.location, self.location])
+            if self.getExtendedAttribute("Replaceable") is not None:
+                raise WebIDLError("[LenientSetter] and [Replaceable] can't both "
+                                  "appear on the same attribute",
+                                  [attr.location, self.location])
         elif identifier == "LenientFloat":
             if self.readonly:
                 raise WebIDLError("[LenientFloat] used on a readonly attribute",
                                   [attr.location, self.location])
             if not self.type.includesRestrictedFloat():
                 raise WebIDLError("[LenientFloat] used on an attribute with a "
                                   "non-restricted-float type",
                                   [attr.location, self.location])
@@ -4795,16 +4813,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
             raise WebIDLError("Methods must not be flagged as [SameObject]",
                               [attr.location, self.location])
         elif identifier == "Constant":
             raise WebIDLError("Methods must not be flagged as [Constant]",
                               [attr.location, self.location])
         elif identifier == "PutForwards":
             raise WebIDLError("Only attributes support [PutForwards]",
                               [attr.location, self.location])
+        elif identifier == "LenientSetter":
+            raise WebIDLError("Only attributes support [LenientSetter]",
+                              [attr.location, self.location])
         elif identifier == "LenientFloat":
             # This is called before we've done overload resolution
             assert len(self.signatures()) == 1
             sig = self.signatures()[0]
             if not sig[0].isVoid():
                 raise WebIDLError("[LenientFloat] used on a non-void method",
                                   [attr.location, self.location])
             if not any(arg.type.includesRestrictedFloat() for arg in sig[1]):
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_lenientSetter.py
@@ -0,0 +1,58 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+def should_throw(parser, harness, message, code):
+    parser = parser.reset();
+    threw = False
+    try:
+        parser.parse(code)
+        parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Should have thrown: %s" % message)
+
+
+def WebIDLTest(parser, harness):
+    # The [LenientSetter] extended attribute MUST take no arguments.
+    should_throw(parser, harness, "no arguments", """
+        interface I {
+          [LenientSetter=X] readonly attribute long A;
+        };
+    """)
+
+    # An attribute with the [LenientSetter] extended attribute MUST NOT
+    # also be declared with the [PutForwards] extended attribute.
+    should_throw(parser, harness, "PutForwards", """
+        interface I {
+          [PutForwards=B, LenientSetter] readonly attribute J A;
+        };
+        interface J {
+          attribute long B;
+        };
+    """)
+
+    # An attribute with the [LenientSetter] extended attribute MUST NOT
+    # also be declared with the [Replaceable] extended attribute.
+    should_throw(parser, harness, "Replaceable", """
+        interface I {
+          [Replaceable, LenientSetter] readonly attribute J A;
+        };
+    """)
+
+    # The [LenientSetter] extended attribute MUST NOT be used on an
+    # attribute that is not read only.
+    should_throw(parser, harness, "writable attribute", """
+        interface I {
+          [LenientSetter] attribute long A;
+        };
+    """)
+
+    # The [LenientSetter] extended attribute MUST NOT be used on a
+    # static attribute.
+    should_throw(parser, harness, "static attribute", """
+        interface I {
+          [LenientSetter] static readonly attribute long A;
+        };
+    """)