Switch Window to WebIDL bindings.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 04 Mar 2014 15:56:31 +0100
changeset 171907 3c594e255df6777c1d3c182f8e0df9cd75931748
parent 171906 7ede4ba958b454c02385379de75342e1ebdee34f
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Switch Window to WebIDL bindings.
content/base/src/nsDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/imptests/failures/html/html/browsers/the-window-object/mochitest.ini
dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json
dom/imptests/failures/html/html/browsers/the-window-object/test_window-prototype-chain.html.json
dom/workers/WorkerScope.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/nsXPConnect.cpp
modules/libpref/src/init/all.js
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -12045,18 +12045,19 @@ nsIDocument::WrapObject(JSContext *aCx, 
   MOZ_ASSERT(IsDOMBinding());
 
   JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aScope));
   if (!obj) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetInnerWindow());
-  if (!win) {
-    // No window, nothing else to do here
+  if (!win ||
+      static_cast<nsGlobalWindow*>(win.get())->IsDOMBinding()) {
+    // No window or window on new DOM binding, nothing else to do here.
     return obj;
   }
 
   if (this != win->GetExtantDoc()) {
     // We're not the current document; we're also done here
     return obj;
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -30,16 +30,17 @@
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIPermissionManager.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptTimeoutHandler.h"
 #include "nsIController.h"
 #include "nsScriptNameSpaceManager.h"
+#include "WindowNamedPropertiesHandler.h"
 
 // Helper Classes
 #include "nsJSUtils.h"
 #include "jsapi.h"              // for JSAutoRequest
 #include "js/OldDebugAPI.h"     // for JS_ClearWatchPointsForObject
 #include "jswrapper.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfo.h"
@@ -1108,16 +1109,21 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true)
 {
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
+  if (Preferences::GetBool("dom.window_experimental_bindings") ||
+      !aOuterWindow) {
+    SetIsDOMBinding();
+  }
+
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
     // window list of inners.
     PR_INSERT_AFTER(this, aOuterWindow);
 
     mObserver = new nsGlobalWindowObserver(this);
     if (mObserver) {
       NS_ADDREF(mObserver);
@@ -1135,17 +1141,16 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     }
   } else {
     // |this| is an outer window. Outer windows start out frozen and
     // remain frozen until they get an inner window, so freeze this
     // outer window here.
     Freeze();
 
     mObserver = nullptr;
-    SetIsDOMBinding();
   }
 
   // We could have failed the first time through trying
   // to create the entropy collector, so we should
   // try to get one until we succeed.
 
   gRefCnt++;
 
@@ -2208,35 +2213,42 @@ CreateNativeGlobalForInner(JSContext* aC
   }
   JS::CompartmentOptions options;
   if (top) {
     if (top->GetGlobalJSObject()) {
       options.setSameZoneAs(top->GetGlobalJSObject());
     }
   }
 
-  nsIXPConnect* xpc = nsContentUtils::XPConnect();
-
   // Determine if we need the Components object.
   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
                         TreatAsRemoteXUL(aPrincipal);
   uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
   flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
 
-  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
-    aCx, ToSupports(aNewInner),
-    aPrincipal, flags, options, getter_AddRefs(holder));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  aGlobal.set(holder->GetJSObject());
+  if (aNewInner->IsDOMBinding()) {
+    aGlobal.set(WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
+                                    nsJSPrincipals::get(aPrincipal), false));
+    if (!aGlobal || !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
+      return NS_ERROR_FAILURE;
+    }
+  } else {
+    nsIXPConnect* xpc = nsContentUtils::XPConnect();
+    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+    nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
+      aCx, ToSupports(aNewInner),
+      aPrincipal, flags, options, getter_AddRefs(holder));
+    NS_ENSURE_SUCCESS(rv, rv);
+  
+    aGlobal.set(holder->GetJSObject());
+    MOZ_ASSERT(aGlobal);
+  }
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
-  MOZ_ASSERT(aGlobal);
   xpc::SetLocationForGlobal(aGlobal, aURI);
 
   return NS_OK;
 }
 
 nsresult
 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
                                nsISupports* aState,
@@ -2527,24 +2539,31 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
     // 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) {
-      nsIXPConnect *xpc = nsContentUtils::XPConnect();
-      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-      nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
-                                                    getter_AddRefs(wrapper));
-      NS_ENSURE_SUCCESS(rv, rv);
-      NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
-      rv = wrapper->FinishInitForWrappedGlobal();
-      NS_ENSURE_SUCCESS(rv, rv);
+      if (IsDOMBinding()) {
+        JS::Rooted<JSObject*> global(cx, newInnerGlobal);
+        JS::Rooted<JSObject*> proto(cx);
+        JS_GetPrototype(cx, global, &proto);
+        WindowNamedPropertiesHandler::Install(cx, proto);
+      } else {
+        nsIXPConnect *xpc = nsContentUtils::XPConnect();
+        nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
+        nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerGlobal,
+                                                      getter_AddRefs(wrapper));
+        NS_ENSURE_SUCCESS(rv, rv);
+        NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
+        rv = wrapper->FinishInitForWrappedGlobal();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
     }
 
     if (!aState) {
       if (!JS_DefineProperty(cx, newInnerWindow->GetWrapperPreserveColor(), "window",
                              OBJECT_TO_JSVAL(GetWrapperPreserveColor()),
                              JS_PropertyStub, JS_StrictPropertyStub,
                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
         NS_ERROR("can't create the 'window' property");
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2172,16 +2172,26 @@ IsInCertifiedApp(JSContext* aCx, JSObjec
   if (!NS_IsMainThread()) {
     return GetWorkerPrivateFromContext(aCx)->IsInCertifiedApp();
   }
 
   nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj);
   return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
 }
 
+#ifdef DEBUG
+void
+VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
+                                    JSGCTraceKind kind)
+{
+    // We don't do anything here, we only want to verify that
+    // TraceProtoAndIfaceCache was called.
+}
+#endif
+
 void
 TraceGlobal(JSTracer* aTrc, JSObject* aObj)
 {
   MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
   mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
 }
 
 void
@@ -2295,10 +2305,22 @@ GenericBindingMethod(JSContext* cx, unsi
                               protoID);
     }
   }
   MOZ_ASSERT(info->type() == JSJitInfo::Method);
   JSJitMethodOp method = info->method;
   return method(cx, obj, self, JSJitMethodCallArgs(args));
 }
 
+void
+CreateJSGlobal(JSContext* aCx, const JSClass* aClass,
+             JS::CompartmentOptions& aOptions, JSPrincipals* aPrincipal,
+             bool aInitStandardClasses, JS::MutableHandle<JSObject*> aGlobal)
+{
+  aGlobal.set(xpc::CreateGlobalObject(aCx, aClass,
+                                      nsJSPrincipals::get(aPrincipal),
+                                      aOptions));
+
+  NS_WARN_IF_FALSE(aGlobal, "Failed to create global");
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -317,21 +317,42 @@ AllocateProtoAndIfaceCache(JSObject* obj
   MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
 
   ProtoAndIfaceArray* protoAndIfaceArray = new ProtoAndIfaceArray();
 
   js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
                       JS::PrivateValue(protoAndIfaceArray));
 }
 
+#ifdef DEBUG
+struct VerifyTraceProtoAndIfaceCacheCalledTracer
+{
+    JSTracer base;
+    bool ok;
+};
+
+void
+VerifyTraceProtoAndIfaceCacheCalled(JSTracer *trc, void **thingp,
+                                    JSGCTraceKind kind);
+#endif
+
 inline void
 TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
 {
   MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
 
+#ifdef DEBUG
+  if (trc->callback == VerifyTraceProtoAndIfaceCacheCalled) {
+    // We don't do anything here, we only want to verify that TraceXPCGlobal
+    // was called.
+    reinterpret_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
+    return;
+  }
+#endif
+
   if (!HasProtoAndIfaceArray(obj))
     return;
   ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(obj);
   for (size_t i = 0; i < ArrayLength(protoAndIfaceArray); ++i) {
     if (protoAndIfaceArray[i]) {
       JS_CallHeapObjectTracer(trc, &protoAndIfaceArray[i], "protoAndIfaceArray[i]");
     }
   }
@@ -2402,65 +2423,106 @@ FinalizeGlobal(JSFreeOp* aFop, JSObject*
 bool
 ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
               JS::Handle<jsid> aId, unsigned aFlags,
               JS::MutableHandle<JSObject*> aObjp);
 
 bool
 EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
 
-template <class T, JS::Handle<JSObject*> (*ProtoGetter)(JSContext*,
-                                                        JS::Handle<JSObject*>)>
+template <class T, ProtoGetter GetProto>
+bool
+CreateGlobalCommon(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
+                   JS::Handle<JSObject*> aGlobal, bool aInitStandardClasses)
+{
+  MOZ_ASSERT(js::IsObjectInContextCompartment(aGlobal, aCx),
+             "Caller should enter the compartment of aGlobal.");
+
+  js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aNative));
+  NS_ADDREF(aNative);
+
+  aCache->SetIsDOMBinding();
+  aCache->SetWrapper(aGlobal);
+
+  if (aInitStandardClasses && !JS_InitStandardClasses(aCx, aGlobal)) {
+    NS_WARNING("Failed to init standard classes");
+    return false;
+  }
+
+  JS::Handle<JSObject*> proto = GetProto(aCx, aGlobal);
+  if (!proto || !JS_SetPrototype(aCx, aGlobal, proto)) {
+    NS_WARNING("Failed to set proto");
+    return false;
+  }
+
+  return true;
+}
+
+template <class T, ProtoGetter GetProto>
 JSObject*
-CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
-             const JSClass* aClass, JS::CompartmentOptions& aOptions,
-             JSPrincipals* aPrincipal)
+CreateWorkerGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
+                   const JSClass* aClass, JS::CompartmentOptions& aOptions,
+                   JSPrincipals* aPrincipal, bool aInitStandardClasses)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   JS::Rooted<JSObject*> global(aCx,
     JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook,
                        aOptions));
   if (!global) {
     NS_WARNING("Failed to create global");
     return nullptr;
   }
 
   JSAutoCompartment ac(aCx, global);
 
   dom::AllocateProtoAndIfaceCache(global);
 
-  js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
-  NS_ADDREF(aObject);
-
-  aCache->SetIsDOMBinding();
-  aCache->SetWrapper(global);
-
-  /* Intl API is broken and makes this fail intermittently, see bug 934889.
-  if (!JS_InitStandardClasses(aCx, global)) {
-    NS_WARNING("Failed to init standard classes");
-    return nullptr;
-  }
-  */
-
-  JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
-  NS_ENSURE_TRUE(proto, nullptr);
-
-  if (!JS_SetPrototype(aCx, global, proto)) {
-    NS_WARNING("Failed to set proto");
+  // Intl API is broken and JS_InitStandardClasses fails intermittently on
+  // workers, and so we always pass false for aInitStandardClasses to
+  // CreateGlobalCommon. See bug 934889.
+  if (!CreateGlobalCommon<T, GetProto>(aCx, aObject, aCache, global, false)) {
     return nullptr;
   }
 
   MOZ_ALWAYS_TRUE(TryPreserveWrapper(global));
 
   MOZ_ASSERT(UnwrapDOMObjectToISupports(global));
 
   return global;
 }
 
+void
+CreateJSGlobal(JSContext* aCx, const JSClass* aClass,
+             JS::CompartmentOptions& aOptions, JSPrincipals* aPrincipal,
+             bool aInitStandardClasses, JS::MutableHandle<JSObject*> aGlobal);
+
+template <class T, ProtoGetter GetProto>
+JSObject*
+CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
+             const JSClass* aClass, JS::CompartmentOptions& aOptions,
+             JSPrincipals* aPrincipal, bool aInitStandardClasses)
+{
+  JS::Rooted<JSObject*> global(aCx);
+  CreateJSGlobal(aCx, aClass, aOptions, aPrincipal, aInitStandardClasses,
+                 &global);
+  if (!global) {
+    return nullptr;
+  }
+
+  JSAutoCompartment ac(aCx, global);
+
+  if (!CreateGlobalCommon<T, GetProto>(aCx, aNative, aCache, global,
+                                       aInitStandardClasses)) {
+    return nullptr;
+  }
+
+  return global;
+}
+
 /*
  * Holds a jsid that is initialized to an interned string, with conversion to
  * Handle<jsid>.
  */
 class InternedStringId
 {
   jsid id;
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -207,17 +207,16 @@ DOMInterfaces = {
 
 'CharacterData': {
     'nativeType': 'nsGenericDOMDataNode',
     'concrete': False
 },
 
 'ChromeWindow': {
     'concrete': False,
-    'register': False,
 },
 
 'ChromeWorker': {
     'headerFile': 'mozilla/dom/WorkerPrivate.h',
     'nativeType': 'mozilla::dom::workers::ChromeWorkerPrivate',
 },
 
 'DOMRectList': {
@@ -1425,17 +1424,16 @@ DOMInterfaces = {
     'headerFile': 'WebSocket.h',
 },
 
 'Window': {
     'nativeType': 'nsGlobalWindow',
     # When turning on Window, remember to drop the "'register': False"
     # from ChromeWindow.
     'hasXPConnectImpls': True,
-    'register': False,
     'binaryNames': {
         'postMessage': 'postMessageMoz',
     },
 },
 
 'WindowProxy': [
 {
     'nativeType': 'nsIDOMWindow',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2451,17 +2451,18 @@ class CGWrapGlobalMethod(CGAbstractMetho
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
                 Argument('nsWrapperCache*', 'aCache'),
                 Argument('JS::CompartmentOptions&', 'aOptions'),
-                Argument('JSPrincipals*', 'aPrincipal')]
+                Argument('JSPrincipals*', 'aPrincipal'),
+                Argument('bool', 'aInitStandardClasses')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.descriptor = descriptor
         self.properties = properties
 
     def definition_body(self):
         if self.properties.hasNonChromeOnly():
             properties = "&sNativeProperties"
         else:
@@ -2478,34 +2479,41 @@ if (!DefineProperties(aCx, obj, %s, %s))
 
         unforgeable = CGGeneric(InitUnforgeableProperties(self.descriptor, self.properties))
 
         initMemberSlots = CGGeneric(InitMemberSlots(self.descriptor, True))
 
         initObject = CGList([defineProperties, unforgeable, initMemberSlots], "\n")
         initObject = CGIndenter(CGWrapper(initObject, pre="{\n", post="\n}"))
 
+        if self.descriptor.workers:
+            createGlobal = "CreateWorkerGlobal"
+            fireOnNewGlobal = CGGeneric("""// XXXkhuey can't do this yet until workers can lazy resolve.
+// JS_FireOnNewGlobalObject(aCx, obj);""")
+            initObject = CGList([initObject, CGIndenter(fireOnNewGlobal)], "\n\n")
+        else:
+            createGlobal = "CreateGlobal"
+
         return """%s
   MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
              "nsISupports must be on our primary inheritance chain");
 
   JS::Rooted<JSObject*> obj(aCx);
-  obj = CreateGlobal<%s, GetProtoObject>(aCx,
-                                         aObject,
-                                         aCache,
-                                         Class.ToJSClass(),
-                                         aOptions,
-                                         aPrincipal);
+  obj = %s<%s, GetProtoObject>(aCx,
+    aObject,
+    aCache,
+    Class.ToJSClass(),
+    aOptions,
+    aPrincipal,
+    aInitStandardClasses);
 
 %s
 
-  // XXXkhuey can't do this yet until workers can lazy resolve.
-  // JS_FireOnNewGlobalObject(aCx, obj);
-
   return obj;""" % (AssertInheritanceChain(self.descriptor),
+                    createGlobal,
                     self.descriptor.nativeType,
                     initObject.define())
 
 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'aCx'),
                 Argument('JS::Handle<JSObject*>', 'aWrapper'),
                 Argument(descriptor.nativeType + '*' , 'aObject')]
--- a/dom/imptests/failures/html/html/browsers/the-window-object/mochitest.ini
+++ b/dom/imptests/failures/html/html/browsers/the-window-object/mochitest.ini
@@ -2,9 +2,8 @@
 [DEFAULT]
 support-files =
 
 
 [test_window-indexed-properties-strict.html.json]
 [test_window-named-properties.html.json]
 skip-if = true # bug 859075
 [test_window-properties.html.json]
-[test_window-prototype-chain.html.json]
--- a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json
+++ b/dom/imptests/failures/html/html/browsers/the-window-object/test_window-properties.html.json
@@ -1,35 +1,12 @@
 {
   "EventTarget method: addEventListener": true,
   "EventTarget method: removeEventListener": true,
   "EventTarget method: dispatchEvent": true,
-  "Window method: close": true,
-  "Window method: stop": true,
-  "Window method: focus": true,
-  "Window method: blur": true,
-  "Window method: open": true,
-  "Window method: alert": true,
-  "Window method: confirm": true,
-  "Window method: prompt": true,
-  "Window method: print": true,
-  "Window method: showModalDialog": true,
-  "Window method: postMessage": true,
-  "Window method: btoa": true,
-  "Window method: atob": true,
-  "Window method: setTimeout": true,
-  "Window method: clearTimeout": true,
-  "Window method: setInterval": true,
-  "Window method: clearInterval": true,
-  "Window method: getSelection": true,
-  "Window method: getComputedStyle": true,
-  "Window method: matchMedia": true,
-  "Window method: scroll": true,
-  "Window method: scrollTo": true,
-  "Window method: scrollBy": true,
   "Window readonly attribute: history": true,
   "Window readonly attribute: parent": true,
   "Window readonly attribute: frameElement": true,
   "Window readonly attribute: navigator": true,
   "Window readonly attribute: external": true,
   "Window readonly attribute: applicationCache": true,
   "Window readonly attribute: sessionStorage": true,
   "Window readonly attribute: localStorage": true,
@@ -39,98 +16,17 @@
   "Window readonly attribute: scrollX": true,
   "Window readonly attribute: pageXOffset": true,
   "Window readonly attribute: scrollY": true,
   "Window readonly attribute: pageYOffset": true,
   "Window readonly attribute: screenX": true,
   "Window readonly attribute: screenY": true,
   "Window readonly attribute: outerWidth": true,
   "Window readonly attribute: outerHeight": true,
-  "Window attribute: name": true,
-  "Window attribute: status": true,
-  "Window attribute: opener": true,
-  "Window attribute: onabort": true,
-  "Window attribute: onafterprint": true,
-  "Window attribute: onbeforeprint": true,
-  "Window attribute: onbeforeunload": true,
-  "Window attribute: onblur": true,
-  "Window attribute: oncancel": true,
-  "Window attribute: oncanplay": true,
-  "Window attribute: oncanplaythrough": true,
-  "Window attribute: onchange": true,
-  "Window attribute: onclick": true,
-  "Window attribute: onclose": true,
-  "Window attribute: oncontextmenu": true,
-  "Window attribute: oncuechange": true,
-  "Window attribute: ondblclick": true,
-  "Window attribute: ondrag": true,
-  "Window attribute: ondragend": true,
-  "Window attribute: ondragenter": true,
-  "Window attribute: ondragleave": true,
-  "Window attribute: ondragover": true,
-  "Window attribute: ondragstart": true,
-  "Window attribute: ondrop": true,
-  "Window attribute: ondurationchange": true,
-  "Window attribute: onemptied": true,
-  "Window attribute: onended": true,
-  "Window attribute: onerror": true,
-  "Window attribute: onfocus": true,
-  "Window attribute: onhashchange": true,
-  "Window attribute: oninput": true,
-  "Window attribute: oninvalid": true,
-  "Window attribute: onkeydown": true,
-  "Window attribute: onkeypress": true,
-  "Window attribute: onkeyup": true,
   "Window attribute: oncancel": true,
   "Window attribute: onclose": true,
   "Window attribute: oncuechange": true,
   "Window attribute: onmousewheel": true,
-  "Window attribute: onload": true,
-  "Window attribute: onloadeddata": true,
-  "Window attribute: onloadedmetadata": true,
-  "Window attribute: onloadstart": true,
-  "Window attribute: onmessage": true,
-  "Window attribute: onmousedown": true,
-  "Window attribute: onmousemove": true,
-  "Window attribute: onmouseout": true,
-  "Window attribute: onmouseover": true,
-  "Window attribute: onmouseup": true,
-  "Window attribute: onmousewheel": true,
-  "Window attribute: onoffline": true,
-  "Window attribute: ononline": true,
-  "Window attribute: onpause": true,
-  "Window attribute: onplay": true,
-  "Window attribute: onplaying": true,
-  "Window attribute: onpagehide": true,
-  "Window attribute: onpageshow": true,
-  "Window attribute: onpopstate": true,
-  "Window attribute: onprogress": true,
-  "Window attribute: onratechange": true,
-  "Window attribute: onreset": true,
-  "Window attribute: onresize": true,
-  "Window attribute: onscroll": true,
-  "Window attribute: onseeked": true,
-  "Window attribute: onseeking": true,
-  "Window attribute: onselect": true,
-  "Window attribute: onshow": true,
-  "Window attribute: onstalled": true,
   "Window attribute: onstorage": true,
-  "Window attribute: onsubmit": true,
-  "Window attribute: onsuspend": true,
-  "Window attribute: ontimeupdate": true,
-  "Window attribute: onunload": true,
-  "Window attribute: onvolumechange": true,
-  "Window attribute: onwaiting": true,
   "Window unforgeable attribute: window": true,
   "Window unforgeable attribute: document": true,
-  "Window unforgeable attribute: location": true,
-  "Window unforgeable attribute: top": true,
-  "Window replaceable attribute: self": true,
-  "Window replaceable attribute: locationbar": true,
-  "Window replaceable attribute: menubar": true,
-  "Window replaceable attribute: personalbar": true,
-  "Window replaceable attribute: scrollbars": true,
-  "Window replaceable attribute: statusbar": true,
-  "Window replaceable attribute: toolbar": true,
-  "Window replaceable attribute: frames": true,
-  "Window replaceable attribute: length": true,
-  "constructor": true
+  "Window unforgeable attribute: top": true
 }
deleted file mode 100644
--- a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-prototype-chain.html.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "Window.prototype": true,
-  "EventTarget.prototype": true,
-  "Object.prototype": true
-}
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -295,17 +295,18 @@ DedicatedWorkerGlobalScope::WrapGlobalOb
   JS::CompartmentOptions options;
   mWorkerPrivate->CopyJSCompartmentOptions(options);
 
   // We're wrapping the global, so the scope is undefined.
   JS::Rooted<JSObject*> scope(aCx);
 
   return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this,
                                                          options,
-                                                         GetWorkerPrincipal());
+                                                         GetWorkerPrincipal(),
+                                                         true);
 }
 
 void
 DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
                                         JS::Handle<JS::Value> aMessage,
                                         const Optional<Sequence<JS::Value>>& aTransferable,
                                         ErrorResult& aRv)
 {
@@ -335,17 +336,18 @@ SharedWorkerGlobalScope::WrapGlobalObjec
 
   JS::CompartmentOptions options;
   mWorkerPrivate->CopyJSCompartmentOptions(options);
 
   // We're wrapping the global, so the scope is undefined.
   JS::Rooted<JSObject*> scope(aCx);
 
   return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options,
-                                                      GetWorkerPrincipal());
+                                                      GetWorkerPrincipal(),
+                                                      true);
 }
 
 bool
 GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
 {
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
   return false;
 }
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -73,18 +73,16 @@ XPCWrappedNativeScope::XPCWrappedNativeS
         mComponents(nullptr),
         mNext(nullptr),
         mGlobalJSObject(aGlobal),
         mIsXBLScope(false)
 {
     // add ourselves to the scopes list
     {
         MOZ_ASSERT(aGlobal);
-        MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
-                                                         JSCLASS_HAS_PRIVATE)); 
 #ifdef DEBUG
         for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
             MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
 #endif
 
         mNext = gScopes;
         gScopes = this;
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -326,43 +326,19 @@ nsXPConnect::InitClasses(JSContext * aJS
     scope->RemoveWrappedNativeProtos();
 
     if (!XPCNativeWrapper::AttachNewConstructorObject(aJSContext, globalJSObj))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
-#ifdef DEBUG
-struct VerifyTraceXPCGlobalCalledTracer
-{
-    JSTracer base;
-    bool ok;
-};
-
-static void
-VerifyTraceXPCGlobalCalled(JSTracer *trc, void **thingp, JSGCTraceKind kind)
-{
-    // We don't do anything here, we only want to verify that TraceXPCGlobal
-    // was called.
-}
-#endif
-
 void
 TraceXPCGlobal(JSTracer *trc, JSObject *obj)
 {
-#ifdef DEBUG
-    if (trc->callback == VerifyTraceXPCGlobalCalled) {
-        // We don't do anything here, we only want to verify that TraceXPCGlobal
-        // was called.
-        reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
-        return;
-    }
-#endif
-
     if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
         mozilla::dom::TraceProtoAndIfaceCache(trc, obj);
 }
 
 namespace xpc {
 
 JSObject*
 CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
@@ -383,21 +359,24 @@ CreateGlobalObject(JSContext *cx, const 
     (void) new XPCWrappedNativeScope(cx, global);
 
 #ifdef DEBUG
     // Verify that the right trace hook is called. Note that this doesn't
     // work right for wrapped globals, since the tracing situation there is
     // more complicated. Manual inspection shows that they do the right thing.
     if (!((const js::Class*)clasp)->ext.isWrappedNative)
     {
-        VerifyTraceXPCGlobalCalledTracer trc;
-        JS_TracerInit(&trc.base, JS_GetRuntime(cx), VerifyTraceXPCGlobalCalled);
+        VerifyTraceProtoAndIfaceCacheCalledTracer trc;
+        JS_TracerInit(&trc.base, JS_GetRuntime(cx),
+                      VerifyTraceProtoAndIfaceCacheCalled);
         trc.ok = false;
         JS_TraceChildren(&trc.base, global, JSTRACE_OBJECT);
-        MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
+        MOZ_ASSERT(trc.ok,
+                   "Trace hook on global needs to call TraceProtoAndIfaceCache for XPConnect "
+                   "compartments.");
     }
 #endif
 
     if (clasp->flags & JSCLASS_DOM_GLOBAL) {
         AllocateProtoAndIfaceCache(global);
     }
 
     return global;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -721,16 +721,18 @@ pref("dom.forms.color", true);
 // Enables system messages and activities
 pref("dom.sysmsg.enabled", false);
 
 // Enable pre-installed applications.
 pref("dom.webapps.useCurrentProfile", false);
 
 pref("dom.cycle_collector.incremental", false);
 
+pref("dom.window_experimental_bindings", true);
+
 // Parsing perf prefs. For now just mimic what the old code did.
 #ifndef XP_WIN
 pref("content.sink.pending_event_mode", 0);
 #endif
 
 // Disable popups from plugins by default
 //   0 = openAllowed
 //   1 = openControlled