Make WebIDL properties on all globals own properties.
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 15 Feb 2014 22:12:34 +0100
changeset 181841 7ccef1339127
parent 181840 e50544d1d32d
child 181842 53b25b8cafe9
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone32.0a1
Make WebIDL properties on all globals own properties.
dom/base/nsDOMClassInfo.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1811,16 +1811,20 @@ nsWindowSH::PostCreate(nsIXPConnectWrapp
 
 #ifdef DEBUG
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
 
   NS_ASSERTION(sgo && sgo->GetGlobalJSObject() == obj,
                "Multiple wrappers created for global object!");
 #endif
 
+  if (!GlobalPropertiesAreOwn()) {
+    return NS_OK;
+  }
+
   const NativeProperties* windowProperties =
     WindowBinding::sNativePropertyHooks->mNativeProperties.regular;
   const NativeProperties* eventTargetProperties =
     EventTargetBinding::sNativePropertyHooks->mNativeProperties.regular;
 
   return DefineWebIDLBindingPropertiesOnXPCObject(cx, window, windowProperties, true) &&
          DefineWebIDLBindingPropertiesOnXPCObject(cx, window, eventTargetProperties, true) ?
          NS_OK : NS_ERROR_FAILURE;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -570,55 +570,64 @@ static JSObject*
 CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
                                JS::Handle<JSObject*> parentProto,
                                const JSClass* protoClass,
                                const NativeProperties* properties,
                                const NativeProperties* chromeOnlyProperties)
 {
   JS::Rooted<JSObject*> ourProto(cx,
     JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global));
-  if (!ourProto) {
+  if (!ourProto ||
+      !DefineProperties(cx, ourProto, properties, chromeOnlyProperties)) {
     return nullptr;
   }
 
+  return ourProto;
+}
+
+bool
+DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
+                 const NativeProperties* properties,
+                 const NativeProperties* chromeOnlyProperties)
+{
   if (properties) {
     if (properties->methods &&
-        !DefinePrefable(cx, ourProto, properties->methods)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, properties->methods)) {
+      return false;
     }
 
     if (properties->attributes &&
-        !DefinePrefable(cx, ourProto, properties->attributes)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, properties->attributes)) {
+      return false;
     }
 
     if (properties->constants &&
-        !DefinePrefable(cx, ourProto, properties->constants)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, properties->constants)) {
+      return false;
     }
   }
 
   if (chromeOnlyProperties) {
     if (chromeOnlyProperties->methods &&
-        !DefinePrefable(cx, ourProto, chromeOnlyProperties->methods)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, chromeOnlyProperties->methods)) {
+      return false;
     }
 
     if (chromeOnlyProperties->attributes &&
-        !DefinePrefable(cx, ourProto, chromeOnlyProperties->attributes)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, chromeOnlyProperties->attributes)) {
+      return false;
     }
 
     if (chromeOnlyProperties->constants &&
-        !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) {
-      return nullptr;
+        !DefinePrefable(cx, obj, chromeOnlyProperties->constants)) {
+      return false;
     }
   }
 
-  return ourProto;
+  return true;
 }
 
 void
 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
                        JS::Handle<JSObject*> protoProto,
                        const JSClass* protoClass, JS::Heap<JSObject*>* protoCache,
                        JS::Handle<JSObject*> constructorProto,
                        const JSClass* constructorClass, const JSNativeHolder* constructor,
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -576,16 +576,34 @@ CreateInterfaceObjects(JSContext* cx, JS
                        JS::Handle<JSObject*> interfaceProto,
                        const JSClass* constructorClass, const JSNativeHolder* constructor,
                        unsigned ctorNargs, const NamedConstructor* namedConstructors,
                        JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
                        const NativeProperties* regularProperties,
                        const NativeProperties* chromeOnlyProperties,
                        const char* name, bool defineOnGlobal);
 
+/**
+ * Define the properties (regular and chrome-only) on obj.
+ *
+ * obj the object to instal the properties on. This should be the interface
+ *     prototype object for regular interfaces and the instance object for
+ *     interfaces marked with Global.
+ * properties contains the methods, attributes and constants to be defined on
+ *            objects in any compartment.
+ * chromeProperties contains the methods, attributes and constants to be defined
+ *                  on objects in chrome compartments. This must be null if the
+ *                  interface doesn't have any ChromeOnly properties or if the
+ *                  object is being created in non-chrome compartment.
+ */
+bool
+DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
+                 const NativeProperties* properties,
+                 const NativeProperties* chromeOnlyProperties);
+
 /*
  * Define the unforgeable attributes on an object.
  */
 bool
 DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
                             const Prefable<const JSPropertySpec>* props);
 
 bool
@@ -2656,12 +2674,21 @@ StaticMethodPromiseWrapper(JSContext* cx
 // rval.
 //
 // promiseScope should be the scope in which the Promise should be created.
 bool
 ConvertExceptionToPromise(JSContext* cx,
                           JSObject* promiseScope,
                           JS::MutableHandle<JS::Value> rval);
 
+// While we wait for the outcome of spec discussions on whether properties for
+// DOM global objects live on the object or the prototype, we supply this one
+// place to switch the behaviour, so we can easily turn this off on branches.
+inline bool
+GlobalPropertiesAreOwn()
+{
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2466,23 +2466,27 @@ class CGCreateInterfaceObjectsMethod(CGA
             interfaceClass = "nullptr"
             interfaceCache = "nullptr"
 
         if self.descriptor.concrete:
             domClass = "&Class.mClass"
         else:
             domClass = "nullptr"
 
-        if self.properties.hasNonChromeOnly():
+        isGlobal = self.descriptor.interface.getExtendedAttribute("Global") is not None
+        if not isGlobal and self.properties.hasNonChromeOnly():
             properties = "&sNativeProperties"
+        elif self.properties.hasNonChromeOnly():
+            properties = "!GlobalPropertiesAreOwn() ? &sNativeProperties : nullptr"
         else:
             properties = "nullptr"
-        if self.properties.hasChromeOnly():
-            accessCheck = "nsContentUtils::ThreadsafeIsCallerChrome()"
-            chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
+        if not isGlobal and self.properties.hasChromeOnly():
+            chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? &sChromeOnlyNativeProperties : nullptr"
+        elif self.properties.hasChromeOnly():
+            chromeProperties = "!GlobalPropertiesAreOwn() && nsContentUtils::ThreadsafeIsCallerChrome() ? &sChromeOnlyNativeProperties : nullptr"
         else:
             chromeProperties = "nullptr"
 
         call = fill(
             """
             dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
                                         ${protoClass}, ${protoCache},
                                         constructorProto, ${interfaceClass}, ${constructHookHolder}, ${constructArgs}, ${namedConstructors},
@@ -2947,16 +2951,25 @@ class CGWrapGlobalMethod(CGAbstractMetho
                 Argument('nsWrapperCache*', 'aCache'),
                 Argument('JS::CompartmentOptions&', 'aOptions'),
                 Argument('JSPrincipals*', 'aPrincipal')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.descriptor = descriptor
         self.properties = properties
 
     def definition_body(self):
+        if self.properties.hasNonChromeOnly():
+            properties = "GlobalPropertiesAreOwn() ? &sNativeProperties : nullptr"
+        else:
+            properties = "nullptr"
+        if self.properties.hasChromeOnly():
+            chromeProperties = "GlobalPropertiesAreOwn() && nsContentUtils::ThreadsafeIsCallerChrome() ? &sChromeOnlyNativeProperties : nullptr"
+        else:
+            chromeProperties = "nullptr"
+
         return fill(
             """
             ${assertions}
               MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
                          "nsISupports must be on our primary inheritance chain");
 
               JS::Rooted<JSObject*> obj(aCx);
               obj = CreateGlobal<${nativeType}, GetProtoObject>(aCx,
@@ -2964,27 +2977,33 @@ class CGWrapGlobalMethod(CGAbstractMetho
                                                      aCache,
                                                      Class.ToJSClass(),
                                                      aOptions,
                                                      aPrincipal);
 
               // obj is a new global, so has a new compartment.  Enter it
               // before doing anything with it.
               JSAutoCompartment ac(aCx, obj);
+
+              if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
+                return nullptr;
+              }
               $*{unforgeable}
 
               $*{slots}
 
               // XXXkhuey can't do this yet until workers can lazy resolve.
               // JS_FireOnNewGlobalObject(aCx, obj);
 
               return obj;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
             nativeType=self.descriptor.nativeType,
+            properties=properties,
+            chromeProperties=chromeProperties,
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, True))
 
 
 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aWrapper'),