Backed out changeset d385df62c0e7 (bug 1267186) for hazard failures
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 09 May 2016 13:40:01 +0200
changeset 321117 b6c20b0bbaabfcab1d21367a3c34fb3bb25696d3
parent 321116 690850cbae730ebd508dd250e43278f04b3a613f
child 321118 d1b90728ce14ed9988383975b3a0399dc8ef81f1
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1267186
milestone49.0a1
backs outd385df62c0e7f25dc846d4992638f1c63491a788
Backed out changeset d385df62c0e7 (bug 1267186) for hazard failures
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/bindings/BindingUtils.cpp
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/WebIDLGlobalNameHash.cpp
dom/bindings/WebIDLGlobalNameHash.h
dom/bindings/moz.build
js/xpconnect/src/xpcpublic.h
layout/build/nsLayoutStatics.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1761,16 +1761,108 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
 
   // The class_name had better match our name
   MOZ_ASSERT(name.Equals(class_name));
 
   NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED);
 
   nsresult rv = NS_OK;
 
+  if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
+      name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
+      name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
+    // Lookup new DOM bindings.
+    DefineInterface getOrCreateInterfaceObject =
+      name_struct->mDefineDOMInterface;
+    if (getOrCreateInterfaceObject) {
+      if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
+          !OldBindingConstructorEnabled(name_struct, aWin, cx)) {
+        return NS_OK;
+      }
+
+      ConstructorEnabled* checkEnabledForScope = name_struct->mConstructorEnabled;
+      // We do the enabled check on the current compartment of cx, but for the
+      // actual object we pass in the underlying object in the Xray case.  That
+      // way the callee can decide whether to allow access based on the caller
+      // or the window being touched.
+      JS::Rooted<JSObject*> global(cx,
+        js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
+      if (!global) {
+        return NS_ERROR_DOM_SECURITY_ERR;
+      }
+      if (checkEnabledForScope && !checkEnabledForScope(cx, global)) {
+        return NS_OK;
+      }
+
+      // The DOM constructor resolve machinery interacts with Xrays in tricky
+      // ways, and there are some asymmetries that are important to understand.
+      //
+      // In the regular (non-Xray) case, we only want to resolve constructors
+      // once (so that if they're deleted, they don't reappear). We do this by
+      // stashing the constructor in a slot on the global, such that we can see
+      // during resolve whether we've created it already. This is rather
+      // memory-intensive, so we don't try to maintain these semantics when
+      // manipulating a global over Xray (so the properties just re-resolve if
+      // they've been deleted).
+      //
+      // Unfortunately, there's a bit of an impedance-mismatch between the Xray
+      // and non-Xray machinery. The Xray machinery wants an API that returns a
+      // JS::PropertyDescriptor, so that the resolve hook doesn't have to get
+      // snared up with trying to define a property on the Xray holder. At the
+      // same time, the DefineInterface callbacks are set up to define things
+      // directly on the global.  And re-jiggering them to return property
+      // descriptors is tricky, because some DefineInterface callbacks define
+      // multiple things (like the Image() alias for HTMLImageElement).
+      //
+      // So the setup is as-follows:
+      //
+      // * The resolve function takes a JS::PropertyDescriptor, but in the
+      //   non-Xray case, callees may define things directly on the global, and
+      //   set the value on the property descriptor to |undefined| to indicate
+      //   that there's nothing more for the caller to do. We assert against
+      //   this behavior in the Xray case.
+      //
+      // * We make sure that we do a non-Xray resolve first, so that all the
+      //   slots are set up. In the Xray case, this means unwrapping and doing
+      //   a non-Xray resolve before doing the Xray resolve.
+      //
+      // This all could use some grand refactoring, but for now we just limp
+      // along.
+      if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
+        JS::Rooted<JSObject*> interfaceObject(cx);
+        {
+          JSAutoCompartment ac(cx, global);
+          interfaceObject = getOrCreateInterfaceObject(cx, global, id, false);
+        }
+        if (NS_WARN_IF(!interfaceObject)) {
+          return NS_ERROR_FAILURE;
+        }
+        if (!JS_WrapObject(cx, &interfaceObject)) {
+          return NS_ERROR_FAILURE;
+        }
+
+        FillPropertyDescriptor(desc, obj, 0, JS::ObjectValue(*interfaceObject));
+      } else {
+        JS::Rooted<JSObject*> interfaceObject(cx,
+          getOrCreateInterfaceObject(cx, obj, id, true));
+        if (NS_WARN_IF(!interfaceObject)) {
+          return NS_ERROR_FAILURE;
+        }
+        // We've already defined the property.  We indicate this to the caller
+        // by filling a property descriptor with JS::UndefinedValue() as the
+        // value.  We still have to fill in a property descriptor, though, so
+        // that the caller knows the property is in fact on this object.  It
+        // doesn't matter what we pass for the "readonly" argument here.
+        FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
+      }
+
+      return NS_OK;
+    }
+  }
+
   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
       return NS_OK;
     }
 
     // Create the XPConnect prototype for our classinfo, PostCreateProto will
     // set up the prototype chain.  This will go ahead and define things on the
     // actual window's global.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -224,17 +224,16 @@
 #include "mozilla/dom/WindowBinding.h"
 #include "nsITabChild.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/NavigatorBinding.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ServiceWorkerRegistration.h"
 #include "mozilla/dom/U2F.h"
-#include "mozilla/dom/WebIDLGlobalNameHash.h"
 #ifdef HAVE_SIDEBAR
 #include "mozilla/dom/ExternalBinding.h"
 #endif
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/SpeechSynthesis.h"
 #endif
 
@@ -4495,25 +4494,16 @@ nsGlobalWindow::DoResolve(JSContext* aCx
 
   // Note: Keep this in sync with MayResolve.
 
   // Note: The infallibleInit call in GlobalResolve depends on this check.
   if (!JSID_IS_STRING(aId)) {
     return true;
   }
 
-  bool found;
-  if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
-    return false;
-  }
-
-  if (found) {
-    return true;
-  }
-
   nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
   if (NS_FAILED(rv)) {
     return Throw(aCx, rv);
   }
 
   return true;
 }
 
@@ -4532,20 +4522,16 @@ nsGlobalWindow::MayResolve(jsid aId)
   }
 
   if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_CONTROLLERS)) {
     // We only resolve .controllers in release builds and on non-chrome windows,
     // but let's not worry about any of that stuff.
     return true;
   }
 
-  if (WebIDLGlobalNameHash::MayResolve(aId)) {
-    return true;
-  }
-
   nsScriptNameSpaceManager *nameSpaceManager = PeekNameSpaceManager();
   if (!nameSpaceManager) {
     // Really shouldn't happen.  Fail safe.
     return true;
   }
 
   nsAutoString name;
   AssignJSFlatString(name, JSID_TO_FLAT_STRING(aId));
@@ -4559,23 +4545,22 @@ nsGlobalWindow::GetOwnPropertyNames(JSCo
 {
   MOZ_ASSERT(IsInnerWindow());
   // "Components" is marked as enumerable but only resolved on demand :-/.
   //aNames.AppendElement(NS_LITERAL_STRING("Components"));
 
   nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
   if (nameSpaceManager) {
     JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
-
-    WebIDLGlobalNameHash::GetNames(aCx, wrapper, aNames);
-
     for (auto i = nameSpaceManager->GlobalNameIter(); !i.Done(); i.Next()) {
       const GlobalNameMapEntry* entry = i.Get();
       if (nsWindowSH::NameStructEnabled(aCx, this, entry->mKey,
-                                        entry->mGlobalName)) {
+                                        entry->mGlobalName) &&
+          (!entry->mGlobalName.mConstructorEnabled ||
+           entry->mGlobalName.mConstructorEnabled(aCx, wrapper))) {
         aNames.AppendElement(entry->mKey);
       }
     }
   }
 }
 
 /* static */ bool
 nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj)
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -20,27 +20,25 @@
 #include "nsXPIDLString.h"
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsHashKeys.h"
 #include "nsDOMClassInfo.h"
 #include "nsCRT.h"
 #include "nsIObserverService.h"
 #include "nsISimpleEnumerator.h"
-#include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/WebIDLGlobalNameHash.h"
+
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 
 #define NS_INTERFACE_PREFIX "nsI"
 #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
 
 using namespace mozilla;
-using namespace mozilla::dom;
 
 static PLDHashNumber
 GlobalNameHashHashKey(const void *key)
 {
   const nsAString *str = static_cast<const nsAString *>(key);
   return HashString(*str);
 }
 
@@ -92,43 +90,40 @@ static const PLDHashTableOps hash_table_
 {
   GlobalNameHashHashKey,
   GlobalNameHashMatchEntry,
   PLDHashTable::MoveEntryStub,
   GlobalNameHashClearEntry,
   GlobalNameHashInitEntry
 };
 
-#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH          32
+#define GLOBALNAME_HASHTABLE_INITIAL_LENGTH   512
 
 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
   : mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
                  GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
 {
   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
 }
 
 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
 {
   UnregisterWeakMemoryReporter(this);
   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
 }
 
 nsGlobalNameStruct *
-nsScriptNameSpaceManager::AddToHash(const char *aKey,
+nsScriptNameSpaceManager::AddToHash(const nsAString *aKey,
                                     const char16_t **aClassName)
 {
-  NS_ConvertASCIItoUTF16 key(aKey);
-  auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(&key, fallible));
+  auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(aKey, fallible));
   if (!entry) {
     return nullptr;
   }
 
-  WebIDLGlobalNameHash::Remove(aKey, key.Length());
-
   if (aClassName) {
     *aClassName = entry->mKey.get();
   }
 
   return &entry->mGlobalName;
 }
 
 void
@@ -230,17 +225,18 @@ nsScriptNameSpaceManager::RegisterClassN
 
   // If a external constructor is already defined with aClassName we
   // won't overwrite it.
 
   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
     return NS_OK;
   }
 
-  NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized,
+  NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
+               s->mType == nsGlobalNameStruct::eTypeNewDOMBinding,
                "Whaaa, JS environment name clash!");
 
   s->mType = nsGlobalNameStruct::eTypeClassConstructor;
   s->mDOMClassInfoID = aDOMClassInfoID;
   s->mChromeOnly = aPrivileged;
   s->mAllowXBL = aXBLAllowed;
 
   return NS_OK;
@@ -253,17 +249,18 @@ nsScriptNameSpaceManager::RegisterClassP
 {
   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
 
   *aFoundOld = false;
 
   nsGlobalNameStruct *s = AddToHash(aClassName);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
-  if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
+  if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
+      s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) {
     *aFoundOld = true;
 
     return NS_OK;
   }
 
   s->mType = nsGlobalNameStruct::eTypeClassProto;
   s->mIID = *aConstructorProtoIID;
 
@@ -347,17 +344,18 @@ nsScriptNameSpaceManager::OperateCategor
   // Copy CID onto the stack, so we can free it right away and avoid having
   // to add cleanup code at every exit point from this function.
   nsCID cid = *cidPtr;
   free(cidPtr);
 
   nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
-  if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
+  if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
+      s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
     s->mType = type;
     s->mCID = cid;
     s->mChromeOnly =
       strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
   } else {
     NS_WARNING("Global script name not overwritten!");
   }
 
@@ -411,16 +409,31 @@ nsScriptNameSpaceManager::Observe(nsISup
   }
 
   // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
   // but we are safe without it. See bug 600460.
 
   return NS_OK;
 }
 
+void
+nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
+    mozilla::dom::DefineInterface aDefineDOMInterface,
+    mozilla::dom::ConstructorEnabled* aConstructorEnabled)
+{
+  nsGlobalNameStruct *s = AddToHash(&aName);
+  if (s) {
+    if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
+      s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
+    }
+    s->mDefineDOMInterface = aDefineDOMInterface;
+    s->mConstructorEnabled = aConstructorEnabled;
+  }
+}
+
 MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
 
 NS_IMETHODIMP
 nsScriptNameSpaceManager::CollectReports(
   nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
 {
   return MOZ_COLLECT_REPORT(
     "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -28,34 +28,45 @@
 #include "nsString.h"
 #include "nsID.h"
 #include "PLDHashTable.h"
 #include "nsDOMClassInfo.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "xpcpublic.h"
 
+
 struct nsGlobalNameStruct
 {
   enum nametype {
     eTypeNotInitialized,
+    eTypeNewDOMBinding,
     eTypeProperty,
     eTypeExternalConstructor,
     eTypeClassConstructor,
     eTypeClassProto,
   } mType;
 
+  // mChromeOnly is only used for structs that define non-WebIDL things
+  // (possibly in addition to WebIDL ones).  In particular, it's not even
+  // initialized for eTypeNewDOMBinding structs.
   bool mChromeOnly : 1;
   bool mAllowXBL : 1;
 
   union {
     int32_t mDOMClassInfoID; // eTypeClassConstructor
     nsIID mIID; // eTypeClassProto
-    nsCID mCID; // All other types
+    nsCID mCID; // All other types except eTypeNewDOMBinding
   };
+
+  // For new style DOM bindings.
+  mozilla::dom::DefineInterface mDefineDOMInterface;
+
+  // May be null if enabled unconditionally
+  mozilla::dom::ConstructorEnabled* mConstructorEnabled;
 };
 
 class GlobalNameMapEntry : public PLDHashEntryHdr
 {
 public:
   // Our hash table ops don't care about the order of these members.
   nsString mKey;
   nsGlobalNameStruct mGlobalName;
@@ -96,16 +107,29 @@ public:
                              bool aPrivileged,
                              bool aXBLAllowed,
                              const char16_t **aResult);
 
   nsresult RegisterClassProto(const char *aClassName,
                               const nsIID *aConstructorProtoIID,
                               bool *aFoundOld);
 
+  void RegisterDefineDOMInterface(const nsAFlatString& aName,
+    mozilla::dom::DefineInterface aDefineDOMInterface,
+    mozilla::dom::ConstructorEnabled* aConstructorEnabled);
+  template<size_t N>
+  void RegisterDefineDOMInterface(const char16_t (&aKey)[N],
+    mozilla::dom::DefineInterface aDefineDOMInterface,
+    mozilla::dom::ConstructorEnabled* aConstructorEnabled)
+  {
+    nsLiteralString key(aKey);
+    return RegisterDefineDOMInterface(key, aDefineDOMInterface,
+                                      aConstructorEnabled);
+  }
+
   class NameIterator : public PLDHashTable::Iterator
   {
   public:
     typedef PLDHashTable::Iterator Base;
     explicit NameIterator(PLDHashTable* aTable) : Base(aTable) {}
     NameIterator(NameIterator&& aOther) : Base(mozilla::Move(aOther.mTable)) {}
 
     const GlobalNameMapEntry* Get() const
@@ -126,24 +150,32 @@ public:
 
 private:
   virtual ~nsScriptNameSpaceManager();
 
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
-  nsGlobalNameStruct *AddToHash(const char *aKey,
+  nsGlobalNameStruct *AddToHash(const nsAString *aKey,
                                 const char16_t **aClassName = nullptr);
-
+  nsGlobalNameStruct *AddToHash(const char *aKey,
+                                const char16_t **aClassName = nullptr)
+  {
+    NS_ConvertASCIItoUTF16 key(aKey);
+    return AddToHash(&key, aClassName);
+  }
   // Removes an existing entry from the hash.
   void RemoveFromHash(const nsAString *aKey);
 
   nsresult FillHash(nsICategoryManager *aCategoryManager,
                     const char *aCategory);
+  nsresult RegisterInterface(const char* aIfName,
+                             const nsIID *aIfIID,
+                             bool* aFoundOld);
 
   /**
    * Add a new category entry into the hash table.
    * Only some categories can be added (see the beginning of the definition).
    * The other ones will be ignored.
    *
    * @aCategoryManager Instance of the category manager service.
    * @aCategory        Category where the entry comes from.
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -40,17 +40,16 @@
 #include "mozilla/dom/ElementBinding.h"
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/HTMLObjectElementBinding.h"
 #include "mozilla/dom/HTMLSharedObjectElement.h"
 #include "mozilla/dom/HTMLEmbedElementBinding.h"
 #include "mozilla/dom/HTMLAppletElementBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ResolveSystemBinding.h"
-#include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsDOMClassInfo.h"
 #include "ipc/ErrorIPCUtils.h"
 #include "mozilla/UseCounter.h"
 
 namespace mozilla {
@@ -2932,25 +2931,30 @@ static bool sRegisteredDOMNames = false;
 
 nsresult
 RegisterDOMNames()
 {
   if (sRegisteredDOMNames) {
     return NS_OK;
   }
 
-  // Register new DOM bindings
-  WebIDLGlobalNameHash::Init();
-
   nsresult rv = nsDOMClassInfo::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsDOMClassInfo");
     return rv;
   }
 
+  // Register new DOM bindings
+  nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
+  if (!nameSpaceManager) {
+    NS_ERROR("Could not initialize nsScriptNameSpaceManager");
+    return NS_ERROR_FAILURE;
+  }
+  mozilla::dom::Register(nameSpaceManager);
+
   sRegisteredDOMNames = true;
 
   return NS_OK;
 }
 
 /* static */
 bool
 CreateGlobalOptions<nsGlobalWindow>::PostCreateGlobal(JSContext* aCx,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12052,24 +12052,24 @@ class CGDescriptor(CGThing):
             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.isNavigatorProperty()) and
             not descriptor.interface.isExternal() and
             descriptor.isExposedConditionally()):
             cgThings.append(CGConstructorEnabled(descriptor))
 
-        if descriptor.registersGlobalNamesOnWindow:
-            cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
-
         if (descriptor.interface.hasMembersInSlots() and
             descriptor.interface.hasChildInterfaces()):
             raise TypeError("We don't support members in slots on "
                             "non-leaf interfaces like %s" %
                             descriptor.interface.identifier.name)
 
         if descriptor.concrete:
             if descriptor.proxy:
@@ -13052,63 +13052,58 @@ class CGResolveSystemBinding(CGAbstractM
         return CGList([CGGeneric("MOZ_ASSERT(NS_IsMainThread());\n"),
                        jsidDecls,
                        jsidInits,
                        definitions,
                        CGGeneric("return true;\n")],
                       "\n").define()
 
 
-def getGlobalNames(config):
-    names = []
-    for desc in config.getDescriptors(registersGlobalNamesOnWindow=True):
-        names.append((desc.name, desc))
-        names.extend((n.identifier.name, desc) for n in desc.interface.namedConstructors)
-    return names
-
-class CGGlobalNamesString(CGGeneric):
+class CGRegisterProtos(CGAbstractMethod):
     def __init__(self, config):
-        globalNames = getGlobalNames(config)
-        currentOffset = 0
-        strings = []
-        for (name, _) in globalNames:
-            strings.append('/* %i */ "%s\\0"' % (currentOffset, name))
-            currentOffset += len(name) + 1 # Add trailing null.
-        define = fill("""
-            const uint32_t WebIDLGlobalNameHash::sCount = ${count};
-
-            const char WebIDLGlobalNameHash::sNames[] =
-              $*{strings}
-
-            """,
-            count=len(globalNames),
-            strings="\n".join(strings) + ";\n")
-
-        CGGeneric.__init__(self, define=define)
-
-
-class CGRegisterGlobalNames(CGAbstractMethod):
-    def __init__(self, config):
-        CGAbstractMethod.__init__(self, None, 'RegisterWebIDLGlobalNames',
-                                  'void', [])
+        CGAbstractMethod.__init__(self, None, 'Register', 'void',
+                                  [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
         self.config = config
 
-    def definition_body(self):
+    def _defineMacro(self):
+        return dedent("""
+            #define REGISTER_PROTO(_dom_class, _ctor_check) \\
+              aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_class), _dom_class##Binding::DefineDOMInterface, _ctor_check);
+            #define REGISTER_CONSTRUCTOR(_dom_constructor, _dom_class, _ctor_check) \\
+              aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_constructor), _dom_class##Binding::DefineDOMInterface, _ctor_check);
+            """)
+
+    def _undefineMacro(self):
+        return dedent("""
+            #undef REGISTER_CONSTRUCTOR
+            #undef REGISTER_PROTO
+            """)
+
+    def _registerProtos(self):
         def getCheck(desc):
             if not desc.isExposedConditionally():
                 return "nullptr"
             return "%sBinding::ConstructorEnabled" % desc.name
-
-        define = ""
-        currentOffset = 0
-        for (name, desc) in getGlobalNames(self.config):
-            length = len(name)
-            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s);\n" % (currentOffset, length, desc.name, getCheck(desc))
-            currentOffset += length + 1 # Add trailing null.
-        return define
+        lines = []
+        for desc in self.config.getDescriptors(hasInterfaceObject=True,
+                                               isExternal=False,
+                                               workers=False,
+                                               isExposedInWindow=True,
+                                               register=True):
+            lines.append("REGISTER_PROTO(%s, %s);\n" % (desc.name, getCheck(desc)))
+            lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc))
+                         for n in desc.interface.namedConstructors)
+        return ''.join(lines)
+
+    def indent_body(self, body):
+        # Don't indent the body of this method, as it's all preprocessor gunk.
+        return body
+
+    def definition_body(self):
+        return "\n" + self._defineMacro() + "\n" + self._registerProtos() + "\n" + self._undefineMacro()
 
 
 def dependencySortObjects(objects, dependencyGetter, nameGetter):
     """
     Sort IDL objects with dependencies on each other such that if A
     depends on B then B will come before A.  This is needed for
     declaring C++ classes in the right order, for example.  Objects
     that have no dependencies are just sorted by name.
@@ -16208,30 +16203,30 @@ class GlobalGenRoots():
         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Done.
         return curr
 
     @staticmethod
     def RegisterBindings(config):
 
-        curr = CGList([CGGlobalNamesString(config), CGRegisterGlobalNames(config)])
+        curr = CGRegisterProtos(config)
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, post='\n'))
         curr = CGWrapper(curr, post='\n')
 
         # Add the includes
         defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
                           for desc in config.getDescriptors(hasInterfaceObject=True,
                                                             workers=False,
                                                             isExposedInWindow=True,
                                                             register=True)]
-        defineIncludes.append('mozilla/dom/WebIDLGlobalNameHash.h')
+        defineIncludes.append('nsScriptNameSpaceManager.h')
         defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
                                for desc in config.getDescriptors(isNavigatorProperty=True,
                                                                  workers=False,
                                                                  register=True)])
         curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings',
                          curr)
 
         # Add include guards.
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -805,24 +805,16 @@ class Descriptor(DescriptorProvider):
     def isGlobal(self):
         """
         Returns true if this is the primary interface for a global object
         of some sort.
         """
         return (self.interface.getExtendedAttribute("Global") or
                 self.interface.getExtendedAttribute("PrimaryGlobal"))
 
-    @property
-    def registersGlobalNamesOnWindow(self):
-        return (not self.interface.isExternal() and
-                self.interface.hasInterfaceObject() and
-                not self.workers and
-                self.interface.isExposedInWindow() and
-                self.register)
-
 
 # Some utility methods
 def getTypesFromDescriptor(descriptor):
     """
     Get all argument and return types for all members of the descriptor
     """
     members = [m for m in descriptor.interface.members]
     if descriptor.interface.ctor():
deleted file mode 100644
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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 "WebIDLGlobalNameHash.h"
-#include "mozilla/HashFunctions.h"
-#include "mozilla/dom/DOMJSProxyHandler.h"
-#include "mozilla/dom/RegisterBindings.h"
-#include "nsIMemoryReporter.h"
-#include "nsTHashtable.h"
-
-namespace mozilla {
-namespace dom {
-
-struct MOZ_STACK_CLASS WebIDLNameTableKey
-{
-  explicit WebIDLNameTableKey(JSFlatString* aJSString)
-    : mLength(js::GetFlatStringLength(aJSString))
-  {
-    JSLinearString* jsString = js::FlatStringToLinearString(aJSString);
-    if (js::LinearStringHasLatin1Chars(jsString)) {
-      mLatin1String = reinterpret_cast<const char*>(
-        js::GetLatin1LinearStringChars(mNogc, jsString));
-      mTwoBytesString = nullptr;
-      mHash = mLatin1String ? HashString(mLatin1String, mLength) : 0;
-    } else {
-      mLatin1String = nullptr;
-      mTwoBytesString = js::GetTwoByteLinearStringChars(mNogc, jsString);
-      mHash = mTwoBytesString ? HashString(mTwoBytesString, mLength) : 0;
-    }
-  }
-  explicit WebIDLNameTableKey(const char* aString, size_t aLength)
-    : mLatin1String(aString),
-      mTwoBytesString(nullptr),
-      mLength(aLength),
-      mHash(HashString(aString, aLength))
-  {
-    MOZ_ASSERT(aString[aLength] == '\0');
-  }
-
-  JS::AutoCheckCannotGC mNogc;
-  const char* mLatin1String;
-  const char16_t* mTwoBytesString;
-  size_t mLength;
-  uint32_t mHash;
-};
-
-struct WebIDLNameTableEntry : public PLDHashEntryHdr
-{
-  typedef const WebIDLNameTableKey& KeyType;
-  typedef const WebIDLNameTableKey* KeyTypePointer;
-
-  explicit WebIDLNameTableEntry(KeyTypePointer aKey)
-  {}
-  WebIDLNameTableEntry(WebIDLNameTableEntry&& aEntry)
-    : mNameOffset(aEntry.mNameOffset),
-      mNameLength(aEntry.mNameLength),
-      mDefine(aEntry.mDefine),
-      mEnabled(aEntry.mEnabled)
-  {}
-  ~WebIDLNameTableEntry()
-  {}
-
-  bool KeyEquals(KeyTypePointer aKey) const
-  {
-    if (mNameLength != aKey->mLength) {
-      return false;
-    }
-
-    const char* name = WebIDLGlobalNameHash::sNames + mNameOffset;
-
-    if (aKey->mLatin1String) {
-      return PodEqual(aKey->mLatin1String, name, aKey->mLength);
-    }
-
-    return nsCharTraits<char16_t>::compareASCII(aKey->mTwoBytesString, name,
-                                                aKey->mLength) == 0;
-  }
-
-  static KeyTypePointer KeyToPointer(KeyType aKey)
-  {
-    return &aKey;
-  }
-
-  static PLDHashNumber HashKey(KeyTypePointer aKey)
-  {
-    return aKey->mHash;
-  }
-
-  enum { ALLOW_MEMMOVE = true };
-
-  uint16_t mNameOffset;
-  uint16_t mNameLength;
-  WebIDLGlobalNameHash::DefineGlobalName mDefine;
-  // May be null if enabled unconditionally
-  WebIDLGlobalNameHash::ConstructorEnabled* mEnabled;
-};
-
-static nsTHashtable<WebIDLNameTableEntry>* sWebIDLGlobalNames;
-
-class WebIDLGlobalNamesHashReporter final : public nsIMemoryReporter
-{
-  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
-
-  ~WebIDLGlobalNamesHashReporter() {}
-
-public:
-  NS_DECL_ISUPPORTS
-
-  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData, bool aAnonymize) override
-  {
-    int64_t amount =
-      sWebIDLGlobalNames ?
-      sWebIDLGlobalNames->ShallowSizeOfIncludingThis(MallocSizeOf) : 0;
-
-    return MOZ_COLLECT_REPORT("explicit/dom/webidl-globalnames", KIND_HEAP,
-                              UNITS_BYTES, amount,
-                              "Memory used by the hash table for WebIDL's "
-                              "global names.");
-  }
-};
-
-NS_IMPL_ISUPPORTS(WebIDLGlobalNamesHashReporter, nsIMemoryReporter)
-
-/* static */
-void
-WebIDLGlobalNameHash::Init()
-{
-  sWebIDLGlobalNames = new nsTHashtable<WebIDLNameTableEntry>(sCount);
-  RegisterWebIDLGlobalNames();
-
-  RegisterStrongMemoryReporter(new WebIDLGlobalNamesHashReporter());
-}
-
-/* static */
-void
-WebIDLGlobalNameHash::Shutdown()
-{
-  delete sWebIDLGlobalNames;
-}
-
-/* static */
-void
-WebIDLGlobalNameHash::Register(uint16_t aNameOffset, uint16_t aNameLength,
-                               DefineGlobalName aDefine,
-                               ConstructorEnabled* aEnabled)
-{
-  const char* name = sNames + aNameOffset;
-  WebIDLNameTableKey key(name, aNameLength);
-  WebIDLNameTableEntry* entry = sWebIDLGlobalNames->PutEntry(key);
-  entry->mNameOffset = aNameOffset;
-  entry->mNameLength = aNameLength;
-  entry->mDefine = aDefine;
-  entry->mEnabled = aEnabled;
-}
-
-/* static */
-void
-WebIDLGlobalNameHash::Remove(const char* aName, uint32_t aLength)
-{
-  WebIDLNameTableKey key(aName, aLength);
-  sWebIDLGlobalNames->RemoveEntry(key);
-}
-
-/* static */
-bool
-WebIDLGlobalNameHash::DefineIfEnabled(JSContext* aCx,
-                                      JS::Handle<JSObject*> aObj,
-                                      JS::Handle<jsid> aId,
-                                      JS::MutableHandle<JS::PropertyDescriptor> aDesc,
-                                      bool* aFound)
-{
-  MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");
-
-  const WebIDLNameTableEntry* entry;
-  {
-    WebIDLNameTableKey key(JSID_TO_FLAT_STRING(aId));
-    entry = sWebIDLGlobalNames->GetEntry(key);
-  }
-
-  if (!entry) {
-    *aFound = false;
-    return true;
-  }
-
-  *aFound = true;
-
-  ConstructorEnabled* checkEnabledForScope = entry->mEnabled;
-  // We do the enabled check on the current compartment of aCx, but for the
-  // actual object we pass in the underlying object in the Xray case.  That
-  // way the callee can decide whether to allow access based on the caller
-  // or the window being touched.
-  JS::Rooted<JSObject*> global(aCx,
-    js::CheckedUnwrap(aObj, /* stopAtWindowProxy = */ false));
-  if (!global) {
-    return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
-  }
-
-  {
-    DebugOnly<nsGlobalWindow*> win;
-    MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, win)));
-  }
-
-  if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
-    return true;
-  }
-
-  // The DOM constructor resolve machinery interacts with Xrays in tricky
-  // ways, and there are some asymmetries that are important to understand.
-  //
-  // In the regular (non-Xray) case, we only want to resolve constructors
-  // once (so that if they're deleted, they don't reappear). We do this by
-  // stashing the constructor in a slot on the global, such that we can see
-  // during resolve whether we've created it already. This is rather
-  // memory-intensive, so we don't try to maintain these semantics when
-  // manipulating a global over Xray (so the properties just re-resolve if
-  // they've been deleted).
-  //
-  // Unfortunately, there's a bit of an impedance-mismatch between the Xray
-  // and non-Xray machinery. The Xray machinery wants an API that returns a
-  // JS::PropertyDescriptor, so that the resolve hook doesn't have to get
-  // snared up with trying to define a property on the Xray holder. At the
-  // same time, the DefineInterface callbacks are set up to define things
-  // directly on the global.  And re-jiggering them to return property
-  // descriptors is tricky, because some DefineInterface callbacks define
-  // multiple things (like the Image() alias for HTMLImageElement).
-  //
-  // So the setup is as-follows:
-  //
-  // * The resolve function takes a JS::PropertyDescriptor, but in the
-  //   non-Xray case, callees may define things directly on the global, and
-  //   set the value on the property descriptor to |undefined| to indicate
-  //   that there's nothing more for the caller to do. We assert against
-  //   this behavior in the Xray case.
-  //
-  // * We make sure that we do a non-Xray resolve first, so that all the
-  //   slots are set up. In the Xray case, this means unwrapping and doing
-  //   a non-Xray resolve before doing the Xray resolve.
-  //
-  // This all could use some grand refactoring, but for now we just limp
-  // along.
-  if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
-    JS::Rooted<JSObject*> interfaceObject(aCx);
-    {
-      JSAutoCompartment ac(aCx, global);
-      interfaceObject = entry->mDefine(aCx, global, aId, false);
-    }
-    if (NS_WARN_IF(!interfaceObject)) {
-      return Throw(aCx, NS_ERROR_FAILURE);
-    }
-    if (!JS_WrapObject(aCx, &interfaceObject)) {
-      return Throw(aCx, NS_ERROR_FAILURE);
-    }
-
-    FillPropertyDescriptor(aDesc, aObj, 0, JS::ObjectValue(*interfaceObject));
-    return true;
-  }
-
-  JS::Rooted<JSObject*> interfaceObject(aCx,
-                                        entry->mDefine(aCx, aObj, aId, true));
-  if (NS_WARN_IF(!interfaceObject)) {
-    return Throw(aCx, NS_ERROR_FAILURE);
-  }
-
-  // We've already defined the property.  We indicate this to the caller
-  // by filling a property descriptor with JS::UndefinedValue() as the
-  // value.  We still have to fill in a property descriptor, though, so
-  // that the caller knows the property is in fact on this object.  It
-  // doesn't matter what we pass for the "readonly" argument here.
-  FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false);
-
-  return true;
-}
-
-/* static */
-bool
-WebIDLGlobalNameHash::MayResolve(jsid aId)
-{
-  WebIDLNameTableKey key(JSID_TO_FLAT_STRING(aId));
-  return sWebIDLGlobalNames->Contains(key);
-}
-
-/* static */
-void
-WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                               nsTArray<nsString>& aNames)
-{
-  for (auto iter = sWebIDLGlobalNames->Iter(); !iter.Done(); iter.Next()) {
-    const WebIDLNameTableEntry* entry = iter.Get();
-    if (!entry->mEnabled || entry->mEnabled(aCx, aObj)) {
-      AppendASCIItoUTF16(nsDependentCString(sNames + entry->mNameOffset,
-                                            entry->mNameLength),
-                         *aNames.AppendElement());
-    }
-  }
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/bindings/WebIDLGlobalNameHash.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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_WebIDLGlobalNameHash_h__
-#define mozilla_dom_WebIDLGlobalNameHash_h__
-
-#include "js/RootingAPI.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-
-struct WebIDLNameTableEntry;
-
-class WebIDLGlobalNameHash
-{
-public:
-  static void Init();
-  static void Shutdown();
-
-  typedef JSObject*
-  (*DefineGlobalName)(JSContext* cx, JS::Handle<JSObject*> global,
-                      JS::Handle<jsid> id, bool defineOnGlobal);
-
-  // Check whether a constructor should be enabled for the given object.
-  // Note that the object should NOT be an Xray, since Xrays will end up
-  // defining constructors on the underlying object.
-  // This is a typedef for the function type itself, not the function
-  // pointer, so it's more obvious that pointers to a ConstructorEnabled
-  // can be null.
-  typedef bool
-  (ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
-
-  static void Register(uint16_t aNameOffset, uint16_t aNameLength,
-                       DefineGlobalName aDefine, ConstructorEnabled* aEnabled);
-
-  static void Remove(const char* aName, uint32_t aLength);
-
-  // Returns false if something failed. aFound is set to true if the name is in
-  // the hash, whether it's enabled or not.
-  static bool DefineIfEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                              JS::Handle<jsid> aId,
-                              JS::MutableHandle<JS::PropertyDescriptor> aDesc,
-                              bool* aFound);
-
-  static bool MayResolve(jsid aId);
-
-  static void GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                       nsTArray<nsString>& aNames);
-
-private:
-  friend struct WebIDLNameTableEntry;
-
-  // The total number of names that we will add to the hash.
-  // The value of sCount is generated by Codegen.py in RegisterBindings.cpp.
-  static const uint32_t sCount;
-
-  // The names that will be registered in the hash, concatenated as one big
-  // string with \0 as a separator between names.
-  // The value of sNames is generated by Codegen.py in RegisterBindings.cpp.
-  static const char sNames[];
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_WebIDLGlobalNameHash_h__
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -34,17 +34,16 @@ EXPORTS.mozilla.dom += [
     'Nullable.h',
     'PrimitiveConversions.h',
     'RootedDictionary.h',
     'SimpleGlobalObject.h',
     'StructuredClone.h',
     'ToJSValue.h',
     'TypedArray.h',
     'UnionMember.h',
-    'WebIDLGlobalNameHash.h',
 ]
 
 # Generated bindings reference *Binding.h, not mozilla/dom/*Binding.h. And,
 # since we generate exported bindings directly to $(DIST)/include, we need
 # to add that path to the search list.
 #
 # Ideally, binding generation uses the prefixed header file names.
 # Bug 932082 tracks.
@@ -85,17 +84,16 @@ UNIFIED_SOURCES += [
     'CallbackInterface.cpp',
     'CallbackObject.cpp',
     'Date.cpp',
     'DOMJSProxyHandler.cpp',
     'Exceptions.cpp',
     'IterableIterator.cpp',
     'SimpleGlobalObject.cpp',
     'ToJSValue.cpp',
-    'WebIDLGlobalNameHash.cpp',
 ]
 
 SOURCES += [
     'StructuredClone.cpp',
 ]
 
 # Tests for maplike and setlike require bindings to be built, which means they
 # must be included in libxul. This breaks the "no test classes are exported"
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -573,16 +573,35 @@ GetJSRuntime();
 void AddGCCallback(xpcGCCallback cb);
 void RemoveGCCallback(xpcGCCallback cb);
 
 } // namespace xpc
 
 namespace mozilla {
 namespace dom {
 
+typedef JSObject*
+(*DefineInterface)(JSContext* cx, JS::Handle<JSObject*> global,
+                   JS::Handle<jsid> id, bool defineOnGlobal);
+
+typedef JSObject*
+(*ConstructNavigatorProperty)(JSContext* cx, JS::Handle<JSObject*> naviObj);
+
+// Check whether a constructor should be enabled for the given object.
+// Note that the object should NOT be an Xray, since Xrays will end up
+// defining constructors on the underlying object.
+// This is a typedef for the function type itself, not the function
+// pointer, so it's more obvious that pointers to a ConstructorEnabled
+// can be null.
+typedef bool
+(ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
+
+void
+Register(nsScriptNameSpaceManager* aNameSpaceManager);
+
 /**
  * A test for whether WebIDL methods that should only be visible to
  * chrome or XBL scopes should be exposed.
  */
 bool IsChromeOrXBL(JSContext* cx, JSObject* /* unused */);
 
 } // namespace dom
 } // namespace mozilla
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -126,17 +126,16 @@ using namespace mozilla::system;
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CameraPreferences.h"
 #include "TouchManager.h"
 #include "MediaDecoder.h"
 #include "mozilla/layers/CompositorLRU.h"
 #include "mozilla/dom/devicestorage/DeviceStorageStatics.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StaticPresData.h"
-#include "mozilla/dom/WebIDLGlobalNameHash.h"
 
 #ifdef MOZ_B2G_BT
 #include "mozilla/dom/BluetoothUUID.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
@@ -380,17 +379,16 @@ nsLayoutStatics::Shutdown()
   nsAttrValue::Shutdown();
   nsContentUtils::Shutdown();
   nsLayoutStylesheetCache::Shutdown();
   RuleProcessorCache::Shutdown();
 
   ShutdownJSEnvironment();
   nsGlobalWindow::ShutDown();
   nsDOMClassInfo::ShutDown();
-  WebIDLGlobalNameHash::Shutdown();
   nsListControlFrame::Shutdown();
   nsXBLService::Shutdown();
   nsAutoCopyListener::Shutdown();
   FrameLayerBuilder::Shutdown();
 
 #ifdef MOZ_ANDROID_OMX
   AndroidMediaPluginHost::Shutdown();
 #endif