Bug 895758. Make the global scope polluter a proxy. r=bzbarsky
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 09 Jul 2013 10:45:13 -0400
changeset 155066 9bb15d65e503601bc25c7e4cc57806f4fbd23766
parent 155065 7d5d885fab531c376382bf2bf4498b6d27da4acd
child 155067 ede52678ba7deb0c248a8636ab416781b2aa9305
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs895758
milestone26.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 895758. Make the global scope polluter a proxy. r=bzbarsky
dom/base/WindowNamedPropertiesHandler.cpp
dom/base/WindowNamedPropertiesHandler.h
dom/base/moz.build
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMWindowList.cpp
dom/base/nsDOMWindowList.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
dom/bindings/Errors.msg
dom/imptests/failures/html/html/browsers/the-window-object/test_window-named-properties.html.json
dom/imptests/failures/html/html/browsers/the-window-object/test_window-prototype-chain.html.json
new file mode 100644
--- /dev/null
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowNamedPropertiesHandler.h"
+#include "nsDOMClassInfo.h"
+#include "nsGlobalWindow.h"
+#include "nsHTMLDocument.h"
+#include "nsJSUtils.h"
+#include "xpcprivate.h"
+
+namespace mozilla {
+namespace dom {
+
+bool
+WindowNamedPropertiesHandler::getOwnPropertyDescriptor(JSContext* aCx,
+                                                       JS::Handle<JSObject*> aProxy,
+                                                       JS::Handle<jsid> aId,
+                                                       JS::MutableHandle<JSPropertyDescriptor> aDesc,
+                                                       unsigned aFlags)
+{
+  if (!JSID_IS_STRING(aId)) {
+    // Nothing to do if we're resolving a non-string property.
+    return true;
+  }
+
+  JSObject* global = JS_GetGlobalForObject(aCx, aProxy);
+  nsresult rv =
+    nsDOMClassInfo::ScriptSecurityManager()->CheckPropertyAccess(aCx, global,
+                                                                 "Window", aId,
+                                                                 nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
+  if (NS_FAILED(rv)) {
+    // The security check failed. The security manager set a JS exception for
+    // us.
+    return false;
+  }
+
+  if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
+    return true;
+  }
+
+  nsDependentJSString str(aId);
+
+  // Grab the DOM window.
+  XPCWrappedNative* wrapper = XPCWrappedNative::Get(global);
+  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper);
+  MOZ_ASSERT(piWin);
+  nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
+  if (win->GetLength() > 0) {
+    nsCOMPtr<nsIDOMWindow> childWin = win->GetChildWindow(str);
+    if (childWin) {
+      // We found a subframe of the right name. Shadowing via |var foo| in
+      // global scope is still allowed, since |var| only looks up |own|
+      // properties. But unqualified shadowing will fail, per-spec.
+      JS::Rooted<JS::Value> v(aCx);
+      if (!WrapObject(aCx, aProxy, childWin, &v)) {
+        return false;
+      }
+      aDesc.object().set(aProxy);
+      aDesc.value().set(v);
+      aDesc.setAttributes(JSPROP_ENUMERATE);
+      return true;
+    }
+  }
+
+  // The rest of this function is for HTML documents only.
+  nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
+  if (!htmlDoc) {
+    return true;
+  }
+  nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
+
+  Element *element = document->GetElementById(str);
+  if (element) {
+    JS::Rooted<JS::Value> v(aCx);
+    if (!WrapObject(aCx, aProxy, element, &v)) {
+      return false;
+    }
+    aDesc.object().set(aProxy);
+    aDesc.value().set(v);
+    aDesc.setAttributes(JSPROP_ENUMERATE);
+    return true;
+  }
+
+  nsWrapperCache* cache;
+  nsISupports* result = document->ResolveName(str, &cache);
+  if (!result) {
+    return true;
+  }
+
+  JS::Rooted<JS::Value> v(aCx);
+  if (!WrapObject(aCx, aProxy, result, cache, nullptr, &v)) {
+    return false;
+  }
+  aDesc.object().set(aProxy);
+  aDesc.value().set(v);
+  aDesc.setAttributes(JSPROP_ENUMERATE);
+  return true;
+}
+
+bool
+WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
+                                             JS::Handle<JSObject*> aProxy,
+                                             JS::Handle<jsid> aId,
+                                             JS::MutableHandle<JSPropertyDescriptor> aDesc)
+{
+  ErrorResult rv;
+  rv.ThrowTypeError(MSG_DEFINEPROPERTY_ON_GSP);
+  rv.ReportTypeError(aCx);
+  return false;
+}
+
+bool
+WindowNamedPropertiesHandler::getOwnPropertyNames(JSContext *aCx,
+                                                  JS::Handle<JSObject*> aProxy,
+                                                  JS::AutoIdVector& aProps)
+{
+  // Grab the DOM window.
+  JSObject* global = JS_GetGlobalForObject(aCx, aProxy);
+  XPCWrappedNative* wrapper = XPCWrappedNative::Get(global);
+  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper);
+  MOZ_ASSERT(piWin);
+  nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
+  nsTArray<nsString> names;
+  win->GetSupportedNames(names);
+  if (!AppendNamedPropertyIds(aCx, aProxy, names, false, aProps)) {
+    return false;
+  }
+
+  names.Clear();
+  nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
+  if (!htmlDoc) {
+    return true;
+  }
+  nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
+  document->GetSupportedNames(names);
+
+  JS::AutoIdVector docProps(aCx);
+  if (!AppendNamedPropertyIds(aCx, aProxy, names, false, docProps)) {
+    return false;
+  }
+
+  return js::AppendUnique(aCx, aProps, docProps);
+}
+
+bool
+WindowNamedPropertiesHandler::delete_(JSContext* aCx,
+                                      JS::Handle<JSObject*> aProxy,
+                                      JS::Handle<jsid> aId, bool* aBp)
+{
+  *aBp = false;
+  return true;
+}
+
+// static
+void
+WindowNamedPropertiesHandler::Install(JSContext *aCx,
+                                      JS::Handle<JSObject*> aProto)
+{
+  JS::Rooted<JSObject*> protoProto(aCx);
+  if (!::JS_GetPrototype(aCx, aProto, &protoProto)) {
+    return;
+  }
+
+  JS::Rooted<JSObject*> gsp(aCx);
+  gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
+                           JS::NullHandleValue, protoProto,
+                           js::GetGlobalForObjectCrossCompartment(aProto));
+  if (!gsp) {
+    return;
+  }
+
+  // And then set the prototype of the interface prototype object to be the
+  // global scope polluter.
+  ::JS_SplicePrototype(aCx, aProto, gsp);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/WindowNamedPropertiesHandler.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowNamedPropertiesHandler_h
+#define mozilla_dom_WindowNamedPropertiesHandler_h__
+
+#include "jsproxy.h"
+#include "mozilla/dom/DOMJSProxyHandler.h"
+
+namespace mozilla {
+namespace dom {
+
+class WindowNamedPropertiesHandler : public BaseDOMProxyHandler
+{
+public:
+  WindowNamedPropertiesHandler() : BaseDOMProxyHandler(nullptr)
+  {
+    setHasPrototype(true);
+  }
+  virtual bool
+  preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy) MOZ_OVERRIDE
+  {
+    // Throw a TypeError, per WebIDL.
+    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
+                         JSMSG_CANT_CHANGE_EXTENSIBILITY);
+    return false;
+  }
+  virtual bool
+  getOwnPropertyDescriptor(JSContext* aCx, JS::Handle<JSObject*> aProxy,
+                           JS::Handle<jsid> aId,
+                           JS::MutableHandle<JSPropertyDescriptor> aDesc,
+                           unsigned aFlags) MOZ_OVERRIDE;
+  virtual bool
+  defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
+                 JS::Handle<jsid> aId,
+                 JS::MutableHandle<JSPropertyDescriptor> aDesc) MOZ_OVERRIDE;
+  virtual bool
+  getOwnPropertyNames(JSContext* aCx, JS::Handle<JSObject*> aProxy,
+                      JS::AutoIdVector& aProps) MOZ_OVERRIDE;
+  virtual bool
+  delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
+          bool* aBp) MOZ_OVERRIDE;
+  virtual bool
+  isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy,
+               bool* aIsExtensible) MOZ_OVERRIDE
+  {
+    *aIsExtensible = true;
+    return true;
+  }
+  virtual const char*
+  className(JSContext *aCx, JS::Handle<JSObject*> aProxy) MOZ_OVERRIDE
+  {
+    return "WindowProperties";
+  }
+
+  static WindowNamedPropertiesHandler*
+  getInstance()
+  {
+    static 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);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_WindowNamedPropertiesHandler_h */
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -93,16 +93,17 @@ CPP_SOURCES += [
     'nsPluginArray.cpp',
     'nsQueryContentEventResult.cpp',
     'nsScreen.cpp',
     'nsScriptNameSpaceManager.cpp',
     'nsStructuredCloneContainer.cpp',
     'nsWindowMemoryReporter.cpp',
     'nsWindowRoot.cpp',
     'nsWrapperCache.cpp',
+    'WindowNamedPropertiesHandler.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'ConsoleAPI.js',
     'ConsoleAPI.manifest',
     'SiteSpecificUserAgent.js',
     'SiteSpecificUserAgent.manifest',
 ]
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -246,16 +246,17 @@ using mozilla::dom::workers::ResolveWork
 #include "nsIAsyncScrollEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "LockedFile.h"
 #include "nsDebug.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Likely.h"
+#include "WindowNamedPropertiesHandler.h"
 
 #ifdef MOZ_TIME_MANAGER
 #include "TimeManager.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -2311,261 +2312,37 @@ nsWindowSH::PreCreate(nsISupports *nativ
 
   // If we're bootstrapping, we don't have a JS object yet.
   if (win->GetOuterWindowInternal()->IsCreatingInnerWindow())
     return NS_OK;
 
   return SetParentToWindow(win, parentObj);
 }
 
-static JSClass sGlobalScopePolluterClass = {
-  "Global Scope Polluter",
-  JSCLASS_NEW_RESOLVE,
-  JS_PropertyStub,
-  JS_DeletePropertyStub,
-  nsWindowSH::GlobalScopePolluterGetProperty,
-  JS_StrictPropertyStub,
-  JS_EnumerateStub,
-  (JSResolveOp)nsWindowSH::GlobalScopePolluterNewResolve,
-  JS_ConvertStub,
-  nullptr
-};
-
-
-// static
-bool
-nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JS::Handle<JSObject*> obj,
-                                           JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
+NS_IMETHODIMP
+nsWindowSH::PostCreatePrototype(JSContext* aCx, JSObject* aProto)
 {
-  // Someone is accessing a element by referencing its name/id in the
-  // global scope, do a security check to make sure that's ok.
-
-  nsresult rv =
-    sSecMan->CheckPropertyAccess(cx, ::JS_GetGlobalForObject(cx, obj),
-                                 "Window", id,
-                                 nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
-
-  if (NS_FAILED(rv)) {
-    // The security check failed. The security manager set a JS
-    // exception for us.
-
-    return false;
-  }
-
-  return true;
-}
-
-// Gets a subframe.
-static bool
-ChildWindowGetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                  JS::MutableHandle<JS::Value> vp)
-{
-  MOZ_ASSERT(JSID_IS_STRING(id));
-  // Grab the native DOM window.
-  vp.setUndefined();
-  nsCOMPtr<nsISupports> winSupports =
-    do_QueryInterface(nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj));
-  if (!winSupports)
-    return true;
-  nsGlobalWindow *win = nsGlobalWindow::FromSupports(winSupports);
-
-  // Find the child, if it exists.
-  nsDependentJSString name(id);
-  nsCOMPtr<nsIDOMWindow> child = win->GetChildWindow(name);
-  if (!child)
-    return true;
-
-  // Wrap the child for JS.
-  JS::Rooted<JS::Value> v(cx);
-  nsresult rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), child,
-                           /* aAllowWrapping = */ true, v.address());
-  NS_ENSURE_SUCCESS(rv, false);
-  vp.set(v);
-  return true;
+  nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, aProto);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // We should probably move this into the CreateInterfaceObjects for Window
+  // once it is on WebIDL bindings.
+  JS::Rooted<JSObject*> proto(aCx, aProto);
+  WindowNamedPropertiesHandler::Install(aCx, proto);
+  return NS_OK;
 }
 
 static nsHTMLDocument*
 GetDocument(JSObject *obj)
 {
   MOZ_ASSERT(js::GetObjectJSClass(obj) == &sHTMLDocumentAllClass);
   return static_cast<nsHTMLDocument*>(
     static_cast<nsINode*>(JS_GetPrivate(obj)));
 }
 
-// static
-bool
-nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JS::Handle<JSObject*> obj,
-                                          JS::Handle<jsid> id, unsigned flags,
-                                          JS::MutableHandle<JSObject*> objp)
-{
-  if (!JSID_IS_STRING(id)) {
-    // Nothing to do if we're resolving a non-string property.
-    return true;
-  }
-
-  // Crash reports from the wild seem to get here during shutdown when there's
-  // no more XPConnect singleton.
-  nsIXPConnect *xpc = XPConnect();
-  NS_ENSURE_TRUE(xpc, true);
-
-  // Grab the DOM window.
-  JSObject *global = JS_GetGlobalForObject(cx, obj);
-  nsISupports *globalNative = xpc->GetNativeOfWrapper(cx, global);
-  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(globalNative);
-  MOZ_ASSERT(piWin);
-  nsGlobalWindow* win = static_cast<nsGlobalWindow*>(piWin.get());
-
-  if (win->GetLength() > 0) {
-    nsDependentJSString name(id);
-    nsCOMPtr<nsIDOMWindow> child_win = win->GetChildWindow(name);
-    if (child_win) {
-      // We found a subframe of the right name, so define the property
-      // on the GSP. This property is a read-only accessor. Shadowing via
-      // |var foo| in global scope is still allowed, since |var| only looks
-      // up |own| properties. But unqualified shadowing will fail, per-spec.
-      if (!JS_DefinePropertyById(cx, obj, id, JS::UndefinedValue(),
-                                 ChildWindowGetter, JS_StrictPropertyStub,
-                                 JSPROP_SHARED | JSPROP_ENUMERATE))
-      {
-        return false;
-      }
-
-      objp.set(obj);
-      return true;
-    }
-  }
-
-  JS::Rooted<JSObject*> proto(cx);
-  if (!::JS_GetPrototype(cx, obj, &proto)) {
-    return false;
-  }
-  bool hasProp;
-
-  if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) ||
-      hasProp) {
-    // No prototype, or the property exists on the prototype. Do
-    // nothing.
-
-    return true;
-  }
-
-  //
-  // The rest of this function is for HTML documents only.
-  //
-  nsCOMPtr<nsIHTMLDocument> htmlDoc =
-    do_QueryInterface(win->GetExtantDoc());
-  if (!htmlDoc)
-    return true;
-  nsHTMLDocument *document = static_cast<nsHTMLDocument*>(htmlDoc.get());
-
-  nsDependentJSString str(id);
-  nsCOMPtr<nsISupports> result;
-  nsWrapperCache *cache;
-  {
-    Element *element = document->GetElementById(str);
-    result = element;
-    cache = element;
-  }
-
-  if (!result) {
-    result = document->ResolveName(str, &cache);
-  }
-
-  if (result) {
-    JS::Rooted<JS::Value> v(cx);
-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsresult rv = WrapNative(cx, obj, result, cache, true, v.address(),
-                             getter_AddRefs(holder));
-    NS_ENSURE_SUCCESS(rv, false);
-
-    if (!JS_WrapValue(cx, v.address()) ||
-        !JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub, 0)) {
-      return false;
-    }
-
-    objp.set(obj);
-  }
-
-  return true;
-}
-
-// static
-bool
-nsWindowSH::InvalidateGlobalScopePolluter(JSContext *cx,
-                                          JS::Handle<JSObject*> aObj)
-{
-  JS::Rooted<JSObject*> proto(cx);
-  JS::Rooted<JSObject*> obj(cx, aObj);
-
-  for (;;) {
-    if (!::JS_GetPrototype(cx, obj, &proto)) {
-      return false;
-    }
-    if (!proto) {
-      break;
-    }
-
-    if (JS_GetClass(proto) == &sGlobalScopePolluterClass) {
-
-      JS::Rooted<JSObject*> proto_proto(cx);
-      if (!::JS_GetPrototype(cx, proto, &proto_proto)) {
-        return false;
-      }
-
-      // Pull the global scope polluter out of the prototype chain so
-      // that it can be freed.
-      ::JS_SplicePrototype(cx, obj, proto_proto);
-
-      break;
-    }
-
-    obj = proto;
-  }
-
-  return true;
-}
-
-// static
-nsresult
-nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JS::Handle<JSObject*> obj)
-{
-  JS::Rooted<JSObject*> gsp(cx, ::JS_NewObjectWithUniqueType(cx, &sGlobalScopePolluterClass, nullptr, obj));
-  if (!gsp) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  JS::Rooted<JSObject*> o(cx, obj), proto(cx);
-
-  // Find the place in the prototype chain where we want this global
-  // scope polluter (right before Object.prototype).
-
-  for (;;) {
-    if (!::JS_GetPrototype(cx, o, &proto)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    if (!proto) {
-      break;
-    }
-    if (JS_GetClass(proto) == sObjectClass) {
-      // Set the global scope polluters prototype to Object.prototype
-      ::JS_SplicePrototype(cx, gsp, proto);
-
-      break;
-    }
-
-    o = proto;
-  }
-
-  // And then set the prototype of the object whose prototype was
-  // Object.prototype to be the global scope polluter.
-  ::JS_SplicePrototype(cx, o, gsp);
-
-  return NS_OK;
-}
-
 struct ResolveGlobalNameClosure
 {
   JSContext* cx;
   JS::Handle<JSObject*> obj;
   bool* retval;
 };
 
 static PLDHashOperator
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -131,16 +131,20 @@ public:
   static bool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj);
 
   static nsISupports *GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj);
 
   static nsIXPConnect *XPConnect()
   {
     return sXPConnect;
   }
+  static nsIScriptSecurityManager *ScriptSecurityManager()
+  {
+    return sSecMan;
+  }
 
 protected:
   friend nsIClassInfo* NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);
 
   const nsDOMClassInfoData* mData;
 
   virtual void PreserveWrapper(nsISupports *aNative) MOZ_OVERRIDE
   {
@@ -302,16 +306,17 @@ protected:
 
   static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                                 JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                                 bool *did_resolve);
 
 public:
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE;
+  NS_IMETHOD PostCreatePrototype(JSContext * cx, JSObject * proto) MOZ_OVERRIDE;
 #ifdef DEBUG
   NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj) MOZ_OVERRIDE
   {
     nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
 
     NS_ASSERTION(!sgo || sgo->GetGlobalJSObject() == nullptr,
                  "Multiple wrappers created for global object!");
--- a/dom/base/nsDOMWindowList.cpp
+++ b/dom/base/nsDOMWindowList.cpp
@@ -81,24 +81,19 @@ nsDOMWindowList::GetLength(uint32_t* aLe
 {
   *aLength = GetLength();
   return NS_OK;
 }
 
 already_AddRefed<nsIDOMWindow>
 nsDOMWindowList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
-  EnsureFresh();
+  aFound = false;
 
-  aFound = false;
-  NS_ENSURE_TRUE(mDocShellNode, nullptr);
-
-  nsCOMPtr<nsIDocShellTreeItem> item;
-  mDocShellNode->GetChildAt(aIndex, getter_AddRefs(item));
-
+  nsCOMPtr<nsIDocShellTreeItem> item = GetDocShellTreeItemAt(aIndex);
   if (!item) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDOMWindow> window = do_GetInterface(item);
   MOZ_ASSERT(window);
 
   aFound = true;
--- a/dom/base/nsDOMWindowList.h
+++ b/dom/base/nsDOMWindowList.h
@@ -5,16 +5,17 @@
 #ifndef nsDOMWindowList_h___
 #define nsDOMWindowList_h___
 
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
 #include "nsIDOMWindowCollection.h"
 #include "nsString.h"
 #include <stdint.h>
+#include "nsIDocShellTreeItem.h"
 
 class nsIDocShellTreeNode;
 class nsIDocShell;
 class nsIDOMWindow;
 
 class nsDOMWindowList : public nsIDOMWindowCollection
 {
 public:
@@ -24,16 +25,25 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMWINDOWCOLLECTION
 
   uint32_t GetLength();
   already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
 
   //local methods
   NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
+  already_AddRefed<nsIDocShellTreeItem> GetDocShellTreeItemAt(uint32_t aIndex)
+  {
+    EnsureFresh();
+    nsCOMPtr<nsIDocShellTreeItem> item;
+    if (mDocShellNode) {
+      mDocShellNode->GetChildAt(aIndex, getter_AddRefs(item));
+    }
+    return item.forget();
+  }
 
 protected:
   // Note: this function may flush and cause mDocShellNode to become null.
   void EnsureFresh();
 
   nsIDocShellTreeNode* mDocShellNode; //Weak Reference
 };
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2274,19 +2274,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       JS::Rooted<JSObject*> obj(cx, currentInner->mJSObject);
       xpc_UnmarkGrayObject(obj);
-      if (!nsWindowSH::InvalidateGlobalScopePolluter(cx, obj)) {
-        return NS_ERROR_FAILURE;
-      }
     }
 
     // We're reusing the inner window, but this still counts as a navigation,
     // so all expandos and such defined on the outer window should go away. Force
     // all Xray wrappers to be recomputed.
     xpc_UnmarkGrayObject(mJSObject);
     if (!JS_RefreshCrossCompartmentWrappers(cx, mJSObject)) {
       return NS_ERROR_FAILURE;
@@ -2494,32 +2491,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
         SuspendTimeouts(parentWindow->TimeoutSuspendCount());
       }
     }
   }
 
   // Add an extra ref in case we release mContext during GC.
   nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
 
-  // Now that the prototype is all set up, install the global scope
-  // polluter. This must happen after the above prototype fixup. If
-  // the GSP was to be installed on the inner window's real
-  // prototype (as it would be if this was done before the prototype
-  // fixup above) we would end up holding the GSP alive (through
-  // XPConnect's internal marking of wrapper prototypes) as long as
-  // the inner window was around, and if the GSP had properties on
-  // it that held an element alive we'd hold the document alive,
-  // which could hold event handlers alive, which hold the context
-  // alive etc.
-
-  if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
-    JS::Rooted<JSObject*> obj(cx, newInnerWindow->mJSObject);
-    nsWindowSH::InstallGlobalScopePolluter(cx, obj);
-  }
-
   aDocument->SetScriptGlobalObject(newInnerWindow);
 
   if (!aState) {
     if (reUseInnerWindow) {
       if (newInnerWindow->mDoc != aDocument) {
         newInnerWindow->mDoc = aDocument;
 
         // We're reusing the inner window for a new document. In this
@@ -3838,16 +3819,33 @@ nsGlobalWindow::IndexedGetter(uint32_t a
   FORWARD_TO_OUTER(IndexedGetter, (aIndex, aFound), nullptr);
 
   nsDOMWindowList* windows = GetWindowList();
   NS_ENSURE_TRUE(windows, nullptr);
 
   return windows->IndexedGetter(aIndex, aFound);
 }
 
+void
+nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
+{
+  FORWARD_TO_OUTER_VOID(GetSupportedNames, (aNames));
+
+  nsDOMWindowList* windows = GetWindowList();
+  if (windows) {
+    uint32_t length = windows->GetLength();
+    nsString* name = aNames.AppendElements(length);
+    for (uint32_t i = 0; i < length; ++i, ++name) {
+      nsCOMPtr<nsIDocShellTreeItem> item =
+        windows->GetDocShellTreeItemAt(i);
+      item->GetName(*name);
+    }
+  }
+}
+
 NS_IMETHODIMP
 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
 {
   FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
 
   NS_ENSURE_ARG_POINTER(aApplicationCache);
 
   if (!mApplicationCache) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -465,16 +465,18 @@ public:
 
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // WebIDL interface.
   uint32_t GetLength();
   already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
 
+  void GetSupportedNames(nsTArray<nsString>& aNames);
+
   // Object Management
   nsGlobalWindow(nsGlobalWindow *aOuterWindow);
 
   static nsGlobalWindow *FromSupports(nsISupports *supports)
   {
     // Make sure this matches the casts we do in QueryInterface().
     return (nsGlobalWindow *)(mozilla::dom::EventTarget *)supports;
   }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1331,30 +1331,56 @@ GetPropertyOnPrototype(JSContext* cx, JS
   }
 
   *vp = value;
   return true;
 }
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       DOMProxyHandler* handler,
                        JS::Handle<jsid> id)
 {
   JS::Rooted<JSObject*> obj(cx, proxy);
   Maybe<JSAutoCompartment> ac;
   if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
     obj = js::UncheckedUnwrap(obj);
     ac.construct(cx, obj);
   }
-  MOZ_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == handler);
 
   bool found;
-  // We ignore an error from GetPropertyOnPrototype.
-  return !GetPropertyOnPrototype(cx, obj, id, &found, NULL) || found;
+  // We ignore an error from GetPropertyOnPrototype.  We pass nullptr
+  // for vp so that GetPropertyOnPrototype won't actually do a get.
+  return !GetPropertyOnPrototype(cx, obj, id, &found, nullptr) || found;
+}
+
+bool
+AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       nsTArray<nsString>& names,
+                       bool shadowPrototypeProperties,
+                       JS::AutoIdVector& props)
+{
+  for (uint32_t i = 0; i < names.Length(); ++i) {
+    JS::Rooted<JS::Value> v(cx);
+    if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
+      return false;
+    }
+
+    JS::Rooted<jsid> id(cx);
+    if (!JS_ValueToId(cx, v, id.address())) {
+      return false;
+    }
+
+    if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
+      if (!props.append(id)) {
+        return false;
+      }
+    }
+  }
+
+  return true;
 }
 
 JSObject*
 GetXrayExpandoChain(JSObject* obj)
 {
   js::Class* clasp = js::GetObjectClass(obj);
   JS::Value v;
   if (IsDOMClass(clasp) || IsDOMIfaceAndProtoClass(clasp)) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1412,26 +1412,37 @@ WantsQueryInterface<T, true>
   {
     return IsChromeOrXBL(aCx, aGlobal);
   }
 };
 
 bool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
+// vp is allowed to be null; in that case no get will be attempted,
+// and *found will simply indicate whether the property exists.
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
                        JS::Value* vp);
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       DOMProxyHandler* handler,
                        JS::Handle<jsid> id);
 
+
+// Append the property names in "names" to "props". If
+// shadowPrototypeProperties is false then skip properties that are also
+// present on the proto chain of proxy.  If shadowPrototypeProperties is true,
+// then the "proxy" argument is ignored.
+bool
+AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       nsTArray<nsString>& names,
+                       bool shadowPrototypeProperties, JS::AutoIdVector& props);
+
 template<class T>
 class OwningNonNull
 {
 public:
   OwningNonNull()
 #ifdef DEBUG
     : inited(false)
 #endif
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6976,17 +6976,17 @@ class CGEnumerateOwnPropertiesViaGetOwnP
                 "ErrorResult rv;\n"
                 "self->GetOwnPropertyNames(cx, names, rv);\n"
                 "rv.WouldReportJSException();\n"
                 "if (rv.Failed()) {\n"
                 '  return ThrowMethodFailedWithDetails<true>(cx, rv, "%s", "enumerate");\n'
                 "}\n"
                 '// OK to pass null as "proxy" because it\'s ignored if\n'
                 "// shadowPrototypeProperties is true\n"
-                "return DOMProxyHandler::AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, nullptr, props);"))
+                "return AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, props);"))
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
@@ -7338,17 +7338,17 @@ MOZ_ASSERT_IF(desc.object(), desc.object
                                     "}\n\n")
             setOrIndexedGet += getUnforgeable
 
         if self.descriptor.supportsNamedProperties():
             readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
             fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
             templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
-            condition = "!HasPropertyOnPrototype(cx, proxy, this, id)"
+            condition = "!HasPropertyOnPrototype(cx, proxy, id)"
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 condition = "(!isXray || %s)" % condition
             condition = "!(flags & JSRESOLVE_ASSIGNING) && " + condition
             if self.descriptor.supportsIndexedProperties():
                 condition = "!IsArrayIndex(index) && " + condition
             namedGet = ("\n" +
                         CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
                                     condition).define() +
@@ -7509,17 +7509,17 @@ class CGDOMJSProxyHandler_delete(ClassMe
             # indexed properties, so we can just treat the id as a name
             # unconditionally here.
             delete += (CGGeneric(namedBody).define() + "\n"
                        "if (found) {\n"
                        "  return true;\n"
                        "}\n")
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 delete = CGIfWrapper(CGGeneric(delete),
-                                     "!HasPropertyOnPrototype(cx, proxy, this, id)").define()
+                                     "!HasPropertyOnPrototype(cx, proxy, id)").define()
         delete += """
 
 return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);"""
 
         return delete
 
 class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
     def __init__(self, descriptor):
@@ -7546,17 +7546,17 @@ for (int32_t i = 0; i < int32_t(length);
         if self.descriptor.supportsNamedProperties():
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 shadow = "!isXray"
             else:
                 shadow = "false"
             addNames = """
 nsTArray<nsString> names;
 UnwrapProxy(proxy)->GetSupportedNames(names);
-if (!AppendNamedPropertyIds(cx, proxy, names, %s, this, props)) {
+if (!AppendNamedPropertyIds(cx, proxy, names, %s, props)) {
   return false;
 }
 """ % shadow
         else:
             addNames = ""
 
         if UseHolderForUnforgeable(self.descriptor):
             addUnforgeable = (
@@ -7610,17 +7610,17 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
 
         if self.descriptor.supportsNamedProperties():
             # If we support indexed properties we always return above for index
             # property names, so no need to check for those here.
             named = (CGProxyNamedPresenceChecker(self.descriptor).define() + "\n" +
                      "*bp = found;\n")
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 named = CGIfWrapper(CGGeneric(named + "return true;\n"),
-                                    "!HasPropertyOnPrototype(cx, proxy, this, id)").define()
+                                    "!HasPropertyOnPrototype(cx, proxy, id)").define()
                 named += ("\n"
                           "*bp = false;")
         else:
             named = "*bp = false;"
 
         return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
           "Should not have a XrayWrapper here");
 
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -155,18 +155,21 @@ bool
 DOMProxyHandler::preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy)
 {
   // Throw a TypeError, per WebIDL.
   JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
   return false;
 }
 
 bool
-DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                                       MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
+BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx,
+                                           JS::Handle<JSObject*> proxy,
+                                           JS::Handle<jsid> id,
+                                           MutableHandle<JSPropertyDescriptor> desc,
+                                           unsigned flags)
 {
   if (!getOwnPropertyDescriptor(cx, proxy, id, desc, flags)) {
     return false;
   }
   if (desc.object()) {
     return true;
   }
 
@@ -216,17 +219,18 @@ DOMProxyHandler::delete_(JSContext* cx, 
     return JS_DeletePropertyById2(cx, expando, id, bp);
   }
 
   *bp = true;
   return true;
 }
 
 bool
-DOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, AutoIdVector& props)
+BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
+                               AutoIdVector& props)
 {
   JS::Rooted<JSObject*> proto(cx);
   if (!JS_GetPrototype(cx, proxy, &proto))  {
     return false;
   }
   return getOwnPropertyNames(cx, proxy, props) &&
          (!proto || js::GetPropertyNames(cx, proto, 0, &props));
 }
@@ -255,47 +259,16 @@ DOMProxyHandler::has(JSContext* cx, JS::
   bool protoHasProp;
   bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
   if (ok) {
     *bp = protoHasProp;
   }
   return ok;
 }
 
-/* static */
-bool
-DOMProxyHandler::AppendNamedPropertyIds(JSContext* cx,
-                                        JS::Handle<JSObject*> proxy,
-                                        nsTArray<nsString>& names,
-                                        bool shadowPrototypeProperties,
-                                        DOMProxyHandler* handler,
-                                        JS::AutoIdVector& props)
-{
-  for (uint32_t i = 0; i < names.Length(); ++i) {
-    JS::Rooted<JS::Value> v(cx);
-    if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
-      return false;
-    }
-
-    JS::Rooted<jsid> id(cx);
-    if (!JS_ValueToId(cx, v, id.address())) {
-      return false;
-    }
-
-    if (shadowPrototypeProperties ||
-        !HasPropertyOnPrototype(cx, proxy, handler, id)) {
-      if (!props.append(id)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 int32_t
 IdToInt32(JSContext* cx, JS::Handle<jsid> id)
 {
   JS::Value idval;
   double array_index;
   int32_t i;
   if (!::JS_IdToValue(cx, id, &idval) ||
       !::JS_ValueToNumber(cx, idval, &array_index) ||
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -22,39 +22,53 @@ namespace dom {
 
 enum {
   JSPROXYSLOT_EXPANDO = 0,
   JSPROXYSLOT_XRAY_EXPANDO
 };
 
 template<typename T> struct Prefable;
 
-class DOMProxyHandler : public js::BaseProxyHandler
+class BaseDOMProxyHandler : public js::BaseProxyHandler
+{
+public:
+  BaseDOMProxyHandler(void* aProxyFamily)
+    : js::BaseProxyHandler(aProxyFamily)
+  {}
+
+  // Implementations of traps that can be implemented in terms of
+  // fundamental traps.
+  bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
+                 JS::AutoIdVector& props) MOZ_OVERRIDE;
+  bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+                             JS::Handle<jsid> id,
+                             JS::MutableHandle<JSPropertyDescriptor> desc,
+                             unsigned flags) MOZ_OVERRIDE;
+};
+
+class DOMProxyHandler : public BaseDOMProxyHandler
 {
 public:
   DOMProxyHandler(const DOMClass& aClass)
-    : js::BaseProxyHandler(ProxyFamily()),
+    : BaseDOMProxyHandler(ProxyFamily()),
       mClass(aClass)
   {
   }
 
   bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
-  bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                             JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags) MOZ_OVERRIDE;
   bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                       JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
   {
     bool unused;
     return defineProperty(cx, proxy, id, desc, &unused);
   }
   virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                               JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
-  bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) MOZ_OVERRIDE;
   bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) MOZ_OVERRIDE;
 
   static JSObject* GetExpandoObject(JSObject* obj)
   {
     MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
     JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
     if (v.isObject()) {
@@ -71,26 +85,16 @@ public:
     return v.isUndefined() ? nullptr : &v.toObject();
   }
   /* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
   static JSObject* GetAndClearExpandoObject(JSObject* obj);
   static JSObject* EnsureExpandoObject(JSContext* cx,
                                        JS::Handle<JSObject*> obj);
 
   const DOMClass& mClass;
-
-  // Append the property names in "names" to "props". If
-  // shadowPrototypeProperties is false then skip properties that are also
-  // present on our proto chain.  If shadowPrototypeProperties is true,
-  // then the "proxy" and "handler" arguments are ignored.
-  static bool AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
-                                     nsTArray<nsString>& names,
-                                     bool shadowPrototypeProperties,
-                                     DOMProxyHandler* handler,
-                                     JS::AutoIdVector& props);
 };
 
 extern jsid s_length_id;
 
 int32_t IdToInt32(JSContext* cx, JS::Handle<jsid> id);
 
 // XXXbz this should really return uint32_t, with the maximum value
 // meaning "not an index"...
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -40,8 +40,9 @@ MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "Globa
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
 MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
 MSG_DEF(MSG_NOT_FINITE, 1, "{0} is not a finite floating-point value.")
 MSG_DEF(MSG_INVALID_VERSION, 0, "0 (Zero) is not a valid database version.")
 MSG_DEF(MSG_INVALID_BYTESTRING, 2, "Cannot convert string to ByteString because the character"
         " at index {0} has value {1} which is greater than 255.")
 MSG_DEF(MSG_NOT_DATE, 1, "{0} is not a date.")
 MSG_DEF(MSG_INVALID_ADVANCE_COUNT, 0, "0 (Zero) is not a valid advance count.")
+MSG_DEF(MSG_DEFINEPROPERTY_ON_GSP, 0, "Not allowed to define a property on the named properties object.")
--- a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-named-properties.html.json
+++ b/dom/imptests/failures/html/html/browsers/the-window-object/test_window-named-properties.html.json
@@ -1,5 +1,4 @@
 {
   "Static name on the prototype": true,
-  "constructor": true,
-  "Ghost name": true
+  "constructor": true
 }
--- a/dom/imptests/failures/html/html/browsers/the-window-object/test_window-prototype-chain.html.json
+++ b/dom/imptests/failures/html/html/browsers/the-window-object/test_window-prototype-chain.html.json
@@ -1,6 +1,5 @@
 {
   "Window.prototype": true,
-  "Global scope polluter": true,
   "EventTarget.prototype": true,
   "Object.prototype": true
 }