Bug 787070 - Expandos on the xray of DOM prototypes should have effect on xrays of DOM nodes, create the named properties object from the binding code. r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Fri, 05 Sep 2014 22:36:36 +0200
changeset 207613 d7cb38405fc2
parent 207612 7f2d0c477f64
child 207614 3ef7fe194800
push id49735
push userpvanderbeken@mozilla.com
push dateMon, 29 Sep 2014 07:58:28 +0000
treeherdermozilla-inbound@090b62fdfd21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs787070
milestone35.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 787070 - Expandos on the xray of DOM prototypes should have effect on xrays of DOM nodes, create the named properties object from the binding code. r=bz.
dom/base/WindowNamedPropertiesHandler.cpp
dom/base/WindowNamedPropertiesHandler.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/bindings/Codegen.py
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -222,39 +222,27 @@ static const DOMIfaceAndProtoJSClass Win
   eInterfacePrototype,
   sWindowNamedPropertiesNativePropertyHooks,
   "[object WindowProperties]",
   prototypes::id::_ID_Count,
   0,
 };
 
 // static
-void
-WindowNamedPropertiesHandler::Install(JSContext* aCx,
-                                      JS::Handle<JSObject*> aProto)
+JSObject*
+WindowNamedPropertiesHandler::Create(JSContext* aCx,
+                                     JS::Handle<JSObject*> aProto)
 {
-  JS::Rooted<JSObject*> protoProto(aCx);
-  if (!::JS_GetPrototype(aCx, aProto, &protoProto)) {
-    return;
-  }
-
   // Note: since the scope polluter proxy lives on the window's prototype
   // chain, it needs a singleton type to avoid polluting type information
   // for properties on the window.
   JS::Rooted<JSObject*> gsp(aCx);
   js::ProxyOptions options;
   options.setSingleton(true);
   options.setClass(&WindowNamedPropertiesClass.mBase);
-  gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
-                           JS::NullHandleValue, protoProto,
-                           js::GetGlobalForObjectCrossCompartment(aProto),
-                           options);
-  if (!gsp) {
-    return;
-  }
-
-  // And then set the prototype of the interface prototype object to be the
-  // global scope polluter.
-  ::JS_SplicePrototype(aCx, aProto, gsp);
+  return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
+                            JS::NullHandleValue, aProto,
+                            js::GetGlobalForObjectCrossCompartment(aProto),
+                            options);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/WindowNamedPropertiesHandler.h
+++ b/dom/base/WindowNamedPropertiesHandler.h
@@ -58,17 +58,18 @@ public:
 
   static const WindowNamedPropertiesHandler*
   getInstance()
   {
     static const WindowNamedPropertiesHandler instance;
     return &instance;
   }
 
-  // For Install, aProto is the proto of the Window we're associated with.
-  static void
-  Install(JSContext *aCx, JS::Handle<JSObject*> aProto);
+  // For Create, aProto is the parent of the interface prototype object of the
+  // Window we're associated with.
+  static JSObject*
+  Create(JSContext *aCx, JS::Handle<JSObject*> aProto);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_WindowNamedPropertiesHandler_h */
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2585,25 +2585,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
     // Enter the new global's compartment.
     JSAutoCompartment ac(cx, GetWrapperPreserveColor());
 
     // Set scriptability based on the state of the docshell.
     bool allow = GetDocShell()->GetCanExecuteScripts();
     xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);
 
-    // If we created a new inner window above, we need to do the last little bit
-    // of initialization now that the dust has settled.
-    if (createdInnerWindow) {
-      JS::Rooted<JSObject*> global(cx, newInnerGlobal);
-      JS::Rooted<JSObject*> proto(cx);
-      JS_GetPrototype(cx, global, &proto);
-      WindowNamedPropertiesHandler::Install(cx, proto);
-    }
-
     if (!aState) {
       JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
       if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
                              JS_PropertyStub, JS_StrictPropertyStub)) {
         NS_ERROR("can't create the 'window' property");
         return NS_ERROR_FAILURE;
       }
@@ -13970,16 +13961,24 @@ void
 nsGlobalWindow::ClearDocumentDependentSlots(JSContext* aCx)
 {
   MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(IsDOMBinding());
   WindowBinding::ClearCachedDocumentValue(aCx, this);
   WindowBinding::ClearCachedPerformanceValue(aCx, this);
 }
 
+/* static */
+JSObject*
+nsGlobalWindow::CreateNamedPropertiesObject(JSContext *aCx,
+                                            JS::Handle<JSObject*> aProto)
+{
+  return WindowNamedPropertiesHandler::Create(aCx, aProto);
+}
+
 #ifdef MOZ_B2G
 void
 nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     services::GetPermissionManager();
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -780,16 +780,19 @@ public:
 #undef ERROR_EVENT
 #undef EVENT
 
   nsISupports* GetParentObject()
   {
     return nullptr;
   }
 
+  static JSObject*
+    CreateNamedPropertiesObject(JSContext *aCx, JS::Handle<JSObject*> aProto);
+
   nsIDOMWindow* GetWindow(mozilla::ErrorResult& aError);
   nsIDOMWindow* GetSelf(mozilla::ErrorResult& aError);
   nsIDocument* GetDocument()
   {
     return GetDoc();
   }
   void GetName(nsAString& aName, mozilla::ErrorResult& aError);
   void SetName(const nsAString& aName, mozilla::ErrorResult& aError);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2575,17 +2575,20 @@ class CGCreateInterfaceObjectsMethod(CGA
                 Argument('JS::Handle<JSObject*>', 'aGlobal'),
                 Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'),
                 Argument('bool', 'aDefineOnGlobal')]
         CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
         self.properties = properties
 
     def definition_body(self):
         parentProtoName = self.descriptor.parentPrototypeName
-        if parentProtoName is None:
+        if self.descriptor.hasNamedPropertiesObject:
+            parentProtoType = "Rooted"
+            getParentProto = "aCx, GetNamedPropertiesObject(aCx, aGlobal)"
+        elif parentProtoName is None:
             parentProtoType = "Rooted"
             if self.descriptor.interface.getExtendedAttribute("ArrayClass"):
                 getParentProto = "aCx, JS_GetArrayPrototype(aCx, aGlobal)"
             elif self.descriptor.interface.getExtendedAttribute("ExceptionClass"):
                 getParentProto = "aCx, JS_GetErrorPrototype(aCx)"
             else:
                 getParentProto = "aCx, JS_GetObjectPrototype(aCx, aGlobal)"
         else:
@@ -2842,16 +2845,49 @@ class CGGetConstructorObjectMethod(CGGet
     def definition_body(self):
         return dedent("""
             /* Get the interface object for this class.  This will create the object as
                needed. */
 
             """) + CGGetPerInterfaceObject.definition_body(self)
 
 
+class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'aCx'),
+                Argument('JS::Handle<JSObject*>', 'aGlobal')]
+        CGAbstractStaticMethod.__init__(self, descriptor,
+                                        'GetNamedPropertiesObject',
+                                        'JSObject*', args)
+
+    def definition_body(self):
+        parentProtoName = self.descriptor.parentPrototypeName
+        if parentProtoName is None:
+            getParentProto = ""
+            parentProto = "nullptr"
+        else:
+            getParentProto = fill(
+                """
+                JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObject(aCx, aGlobal));
+                if (!parentProto) {
+                  return nullptr;
+                }
+                """,
+                parent=toBindingNamespace(parentProtoName))
+            parentProto = "parentProto"
+        return fill(
+            """
+            $*{getParentProto}
+            return ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
+            """,
+            getParentProto=getParentProto,
+            parentProto=parentProto,
+            nativeType=self.descriptor.nativeType)
+
+
 class CGDefineDOMInterfaceMethod(CGAbstractMethod):
     """
     A method for resolve hooks to try to lazily define the interface object for
     a given interface.
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aGlobal'),
@@ -11009,16 +11045,19 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGClassConstructHookHolder(descriptor))
             cgThings.append(CGNamedConstructors(descriptor))
 
         cgThings.append(CGLegacyCallHook(descriptor))
         if descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             cgThings.append(CGNewResolveHook(descriptor))
             cgThings.append(CGEnumerateHook(descriptor))
 
+        if descriptor.hasNamedPropertiesObject:
+            cgThings.append(CGGetNamedPropertiesObjectMethod(descriptor))
+
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 
         if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
             not descriptor.interface.isExternal() and