Bug 993047 - Support outerizing and addProperty hooks on globals with WebIDL bindings. r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 15 Feb 2014 22:12:33 +0100
changeset 177575 f6b0e518f6d2200de210c8fb7da267ca7f4db6f9
parent 177574 1888dccad4f7b476ebc5b076c37a6c7b1affe6d4
child 177576 b6a353fc2b947c67192e2ac6535a9b99da33c1ec
push id26556
push userryanvm@gmail.com
push dateTue, 08 Apr 2014 22:16:57 +0000
treeherdermozilla-central@5811efc11011 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs993047
milestone31.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 993047 - Support outerizing and addProperty hooks on globals with WebIDL bindings. r=bz.
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/bindings/Codegen.py
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1935,16 +1935,49 @@ nsGlobalWindow::GetGlobalJSObject()
 }
 
 void
 nsGlobalWindow::TraceGlobalJSObject(JSTracer* aTrc)
 {
   TraceWrapper(aTrc, "active window global");
 }
 
+/* static */
+JSObject*
+nsGlobalWindow::OuterObject(JSContext* aCx, JS::HandleObject aObj)
+{
+  nsGlobalWindow *origWin;
+  UNWRAP_OBJECT(Window, aObj, origWin);
+  nsGlobalWindow *win = origWin->GetOuterWindowInternal();
+
+  if (!win) {
+    // If we no longer have an outer window. No code should ever be
+    // running on a window w/o an outer, which means this hook should
+    // never be called when we have no outer. But just in case, return
+    // null to prevent leaking an inner window to code in a different
+    // window.
+    NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
+    return nullptr;
+  }
+
+  JS::Rooted<JSObject*> winObj(aCx, win->FastGetGlobalJSObject());
+  MOZ_ASSERT(winObj);
+
+  // Note that while |wrapper| is same-compartment with cx, the outer window
+  // might not be. If we're running script in an inactive scope and evalute
+  // |this|, the outer window is actually a cross-compartment wrapper. So we
+  // need to wrap here.
+  if (!JS_WrapObject(aCx, &winObj)) {
+    NS_WARNING("nsGlobalWindow::OuterObject shouldn't fail!");
+    return nullptr;
+  }
+
+  return winObj;
+}
+
 bool
 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
 {
   // We reuse the inner window when:
   // a. We are currently at our original document.
   // b. At least one of the following conditions are true:
   // -- The new document is the same as the old document. This means that we're
   //    getting called from document.open().
@@ -4355,20 +4388,20 @@ nsGlobalWindow::GetOpener(nsIDOMWindow**
   return rv.ErrorCode();
 }
 
 void
 nsGlobalWindow::SetOpener(nsIDOMWindow* aOpener, ErrorResult& aError)
 {
   // Check if we were called from a privileged chrome script.  If not, and if
   // aOpener is not null, just define aOpener on our inner window's JS object,
-  // wapped into the current compartment so that for Xrays we define on the Xray
-  // expando object, but don't set it on the outer window, so that it'll get
-  // reset on navigation.  This is just like replaceable properties, but we're
-  // not quite readonly.
+  // wrapped into the current compartment so that for Xrays we define on the
+  // Xray expando object, but don't set it on the outer window, so that it'll
+  // get reset on navigation.  This is just like replaceable properties, but
+  // we're not quite readonly.
   if (aOpener && !nsContentUtils::IsCallerChrome()) {
     // JS_WrapObject will outerize, so we don't care if aOpener is an inner.
     nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOpener);
     if (!glob) {
       aError.Throw(NS_ERROR_UNEXPECTED);
       return;
     }
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -367,16 +367,18 @@ public:
   virtual nsresult EnsureScriptEnvironment();
 
   virtual nsIScriptContext *GetScriptContext();
 
   void PoisonOuterWindowProxy(JSObject *aObject);
 
   virtual bool IsBlackForCC(bool aTracingNeeded = true);
 
+  static JSObject* OuterObject(JSContext* aCx, JS::HandleObject aObj);
+
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   // nsIDOMWindow
   NS_DECL_NSIDOMWINDOW
 
 #ifdef MOZ_B2G
   // nsIDOMWindowB2G
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -48,17 +48,18 @@ def isTypeCopyConstructible(type):
              CGUnionStruct.isUnionCopyConstructible(type)) or
             (type.isDictionary() and
              CGDictionary.isDictionaryCopyConstructible(type.inner)))
 
 
 def wantsAddProperty(desc):
     return (desc.concrete and
             desc.wrapperCache and
-            not desc.interface.getExtendedAttribute("Global"))
+            not (desc.workers and
+                 desc.interface.getExtendedAttribute("Global")))
 
 
 # We'll want to insert the indent at the beginnings of lines, but we
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
 
 
@@ -325,19 +326,56 @@ class CGDOMJSClass(CGThing):
     def declare(self):
         return ""
 
     def define(self):
         traceHook = 'nullptr'
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
         slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
         classFlags = "JSCLASS_IS_DOMJSCLASS | "
+        classExtensionAndObjectOps = """\
+JS_NULL_CLASS_EXT,
+JS_NULL_OBJECT_OPS
+"""
         if self.descriptor.interface.getExtendedAttribute("Global"):
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
             traceHook = "JS_GlobalObjectTraceHook"
+            if not self.descriptor.workers:
+                classExtensionAndObjectOps = """\
+{
+  nsGlobalWindow::OuterObject, /* outerObject */
+  nullptr, /* innerObject */
+  nullptr, /* iteratorObject */
+  false, /* isWrappedNative */
+  nullptr /* weakmapKeyDelegateOp */
+},
+{
+  nullptr, /* lookupGeneric */
+  nullptr, /* lookupProperty */
+  nullptr, /* lookupElement */
+  nullptr, /* defineGeneric */
+  nullptr, /* defineProperty */
+  nullptr, /* defineElement */
+  nullptr, /* getGeneric  */
+  nullptr, /* getProperty */
+  nullptr, /* getElement */
+  nullptr, /* setGeneric */
+  nullptr, /* setProperty */
+  nullptr, /* setElement */
+  nullptr, /* getGenericAttributes */
+  nullptr, /* setGenericAttributes */
+  nullptr, /* deleteProperty */
+  nullptr, /* deleteElement */
+  nullptr, /* watch */
+  nullptr, /* unwatch */
+  nullptr, /* slice */
+  nullptr, /* enumerate */
+  JS_ObjectToOuterObject /* thisObject */
+}
+"""
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
             classFlags += " | JSCLASS_NEW_RESOLVE"
             enumerateHook = ENUMERATE_HOOK_NAME
         elif self.descriptor.interface.getExtendedAttribute("Global"):
             newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal"
@@ -361,30 +399,30 @@ class CGDOMJSClass(CGThing):
                 ${resolve}, /* resolve */
                 JS_ConvertStub,
                 ${finalize}, /* finalize */
                 ${call}, /* call */
                 nullptr,               /* hasInstance */
                 nullptr,               /* construct */
                 ${trace}, /* trace */
                 JS_NULL_CLASS_SPEC,
-                JS_NULL_CLASS_EXT,
-                JS_NULL_OBJECT_OPS
+                $*{classExtensionAndObjectOps}
               },
               $*{descriptor}
             };
             """,
             name=self.descriptor.interface.identifier.name,
             flags=classFlags,
             addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub',
             enumerate=enumerateHook,
             resolve=newResolveHook,
             finalize=FINALIZE_HOOK_NAME,
             call=callHook,
             trace=traceHook,
+            classExtensionAndObjectOps=classExtensionAndObjectOps,
             descriptor=DOMClass(self.descriptor))
 
 
 class CGDOMProxyJSClass(CGThing):
     """
     Generate a DOMJSClass for a given proxy descriptor
     """
     def __init__(self, descriptor):