Bug 1270601 part 3. Add a way to annotate and IDL namespace as needing a new plain object as its prototype, because using Object.prototype as the prototype of 'console' is not web-compatible. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 02 Jun 2016 10:34:39 -0400
changeset 339185 508c43bf55788e76bd05ee5bdffdbd3711d19132
parent 339184 1d761dc47c2d532b247288233025ae91593f83a3
child 339186 20835baaf80fb66a98261e0399b4a4ac5dd2672b
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs1270601
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1270601 part 3. Add a way to annotate and IDL namespace as needing a new plain object as its prototype, because using Object.prototype as the prototype of 'console' is not web-compatible. r=peterv
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3271,28 +3271,37 @@ template<class T>
 struct StrongPtrForMember
 {
   typedef typename Conditional<IsRefcounted<T>::value,
                                RefPtr<T>, nsAutoPtr<T>>::Type Type;
 };
 
 inline
 JSObject*
-GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
+GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*>)
 {
   return JS_GetErrorPrototype(aCx);
 }
 
 inline
 JSObject*
-GetIteratorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)
+GetIteratorPrototype(JSContext* aCx, JS::Handle<JSObject*>)
 {
   return JS_GetIteratorPrototype(aCx);
 }
 
+namespace binding_detail {
+inline
+JSObject*
+GetHackedNamespaceProtoObject(JSContext* aCx, JS::Handle<JSObject*>)
+{
+  return JS_NewPlainObject(aCx);
+}
+} // namespace binding_detail
+
 // Resolve an id on the given global object that wants to be included in
 // Exposed=System webidl annotations.  False return value means exception
 // thrown.
 bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
                          JS::Handle<jsid> id, bool* resolvedp);
 
 // Enumerate all ids on the given global object that wants to be included in
 // Exposed=System webidl annotations.  False return value means exception
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1907,16 +1907,21 @@ DOMInterfaces = {
         'register': False,
         },
 
 'TestRenamedNamespace' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False,
         },
 
+'TestProtoObjectHackedNamespace' : {
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        },
+
 }
 
 # These are temporary, until they've been converted to use new DOM bindings
 def addExternalIface(iface, nativeType=None, headerFile=None,
                      notflattened=False):
     if iface in DOMInterfaces:
         raise Exception('Interface declared both as WebIDL and External interface')
     domInterface = {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -620,17 +620,17 @@ class CGPrototypeJSClass(CGThing):
             protoGetter=protoGetter)
 
 
 def NeedsGeneratedHasInstance(descriptor):
     assert descriptor.interface.hasInterfaceObject()
     return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
 
 
-def InterfaceObjectProtoGetter(descriptor):
+def InterfaceObjectProtoGetter(descriptor, forXrays=False):
     """
     Returns a tuple with two elements:
 
         1) The name of the function to call to get the prototype to use for the
            interface object as a JSObject*.
 
         2) The name of the function to call to get the prototype to use for the
            interface prototype as a JS::Handle<JSObject*> or None if no such
@@ -640,17 +640,21 @@ def InterfaceObjectProtoGetter(descripto
     if parentInterface:
         assert not descriptor.interface.isNamespace()
         parentIfaceName = parentInterface.identifier.name
         parentDesc = descriptor.getDescriptor(parentIfaceName)
         prefix = toBindingNamespace(parentDesc.name)
         protoGetter = prefix + "::GetConstructorObject"
         protoHandleGetter = prefix + "::GetConstructorObjectHandle"
     elif descriptor.interface.isNamespace():
-        protoGetter = "JS_GetObjectPrototype"
+        if (forXrays or
+            not descriptor.interface.getExtendedAttribute("ProtoObjectHack")):
+            protoGetter = "JS_GetObjectPrototype"
+        else:
+            protoGetter = "binding_detail::GetHackedNamespaceProtoObject"
         protoHandleGetter = None
     else:
         protoGetter = "JS_GetFunctionPrototype"
         protoHandleGetter = None
     return (protoGetter, protoHandleGetter)
 
 
 class CGInterfaceObjectJSClass(CGThing):
@@ -677,17 +681,18 @@ class CGInterfaceObjectJSClass(CGThing):
             hasinstance = "InterfaceHasInstance"
         else:
             hasinstance = "nullptr"
         prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
         slotCount = "DOM_INTERFACE_SLOTS_BASE"
         if len(self.descriptor.interface.namedConstructors) > 0:
             slotCount += (" + %i /* slots for the named constructors */" %
                           len(self.descriptor.interface.namedConstructors))
-        (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor)
+        (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor,
+                                                      forXrays=True)
 
         if ctorname == "ThrowingConstructor" and hasinstance == "InterfaceHasInstance":
             ret = ""
             classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
         elif ctorname == "nullptr" and hasinstance == "nullptr":
             ret = ""
             classOpsPtr = "JS_NULL_CLASS_OPS"
         else:
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1760,16 +1760,20 @@ class IDLNamespace(IDLInterfaceOrNamespa
                 convertExposedAttrToGlobalNameSet(attr,
                                                   self._exposureGlobalNames)
             elif identifier == "ClassString":
                 # Takes a string value to override the default "Object" if
                 # desired.
                 if not attr.hasValue():
                     raise WebIDLError("[%s] must have a value" % identifier,
                                       [attr.location])
+            elif identifier == "ProtoObjectHack":
+                if not attr.noArguments():
+                    raise WebIDLError("[%s] must not have arguments" % identifier,
+                                      [attr.location])
             else:
                 raise WebIDLError("Unknown extended attribute %s on namespace" %
                                   identifier,
                                   [attr.location])
 
             attrlist = attr.listValue()
             self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -1429,12 +1429,15 @@ public:
   static bool Foo(const GlobalObject&);
   static int32_t Bar(const GlobalObject&);
   static void Baz(const GlobalObject&);
 };
 
 class TestRenamedNamespace {
 };
 
+class TestProtoObjectHackedNamespace {
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -1225,12 +1225,16 @@ namespace TestNamespace {
 partial namespace TestNamespace {
   void baz();
 };
 
 [ClassString="RenamedNamespaceClassName"]
 namespace TestRenamedNamespace {
 };
 
+[ProtoObjectHack]
+namespace TestProtoObjectHackedNamespace {
+};
+
 [SecureContext]
 interface TestSecureContextInterface {
   static void alsoSecureContext();
 };