Back out changesets 2fcef6b54be7, 2be07829fefc, 66dfe37b8532, df3fcd2be8fd, 0a436bce77a6 (bug 1050035) for causing intermittent crashes and assertion failures.
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 10 Feb 2015 14:39:49 -0800
changeset 257347 a4cf56d0e98ff7059ba78e8fdb34f8494cd01186
parent 257346 516285b8e2d9a1d1abdf8580cb3b9d8c5d6c5094
child 257348 09b002eaa381c992fa255074d482286a7a935681
push idunknown
push userunknown
push dateunknown
bugs1050035
milestone38.0a1
backs out2fcef6b54be7ec818a20f3f8039ebc09cefd77a4
2be07829fefc3e28a8fb8a1de18a04fc2a2d5ba7
66dfe37b8532cd188b528527e06086f3126d1259
df3fcd2be8fda0166301cab6d83087b24e1e9124
0a436bce77a6695f0b5a600b726cd3693c000213
Back out changesets 2fcef6b54be7, 2be07829fefc, 66dfe37b8532, df3fcd2be8fd, 0a436bce77a6 (bug 1050035) for causing intermittent crashes and assertion failures.
dom/base/nsContentList.cpp
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsPropertyTable.cpp
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/plugins/base/nsJSNPRuntime.cpp
dom/xul/XULDocument.cpp
dom/xul/templates/nsContentSupportMap.h
dom/xul/templates/nsTemplateMap.h
embedding/components/commandhandler/nsCommandParams.cpp
gfx/thebes/gfxFT2FontList.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCMaps.cpp
js/xpconnect/src/XPCMaps.h
layout/base/nsFrameManager.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsRuleNode.cpp
layout/tables/SpanningCellSorter.cpp
modules/libpref/Preferences.cpp
modules/libpref/prefapi.cpp
modules/libpref/prefapi.h
netwerk/base/nsLoadGroup.cpp
netwerk/cache/nsCacheEntry.cpp
netwerk/cache/nsCacheEntry.h
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsDiskCacheBinding.cpp
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/protocol/http/nsHttp.cpp
parser/htmlparser/nsHTMLEntities.cpp
rdf/base/nsInMemoryDataSource.cpp
rdf/base/nsRDFService.cpp
security/manager/boot/src/nsSecureBrowserUIImpl.cpp
security/manager/ssl/src/nsCertTree.cpp
security/manager/ssl/src/nsCertTree.h
security/manager/ssl/src/nsNSSShutDown.cpp
uriloader/base/nsDocLoader.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsPersistentProperties.cpp
xpcom/ds/nsStaticNameTable.cpp
xpcom/glue/nsTHashtable.h
xpcom/glue/pldhash.cpp
xpcom/glue/pldhash.h
xpcom/tests/TestPLDHash.cpp
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -219,17 +219,17 @@ NS_GetContentList(nsINode* aRootNode,
     PL_DHashTableInit(&gContentListHashTable, &hash_table_ops,
                       sizeof(ContentListHashEntry));
   }
 
   ContentListHashEntry *entry = nullptr;
   // First we look in our hashtable.  Then we create a content list if needed
   if (gContentListHashTable.IsInitialized()) {
     entry = static_cast<ContentListHashEntry *>
-      (PL_DHashTableAdd(&gContentListHashTable, &hashKey, fallible));
+                       (PL_DHashTableAdd(&gContentListHashTable, &hashKey));
     if (entry)
       list = entry->mContentList;
   }
 
   if (!list) {
     // We need to create a ContentList and add it to our new entry, if
     // we have an entry
     nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
@@ -327,17 +327,18 @@ GetFuncStringContentList(nsINode* aRootN
   }
 
   FuncStringContentListHashEntry *entry = nullptr;
   // First we look in our hashtable.  Then we create a content list if needed
   if (gFuncStringContentListHashTable.IsInitialized()) {
     nsFuncStringCacheKey hashKey(aRootNode, aFunc, aString);
 
     entry = static_cast<FuncStringContentListHashEntry *>
-      (PL_DHashTableAdd(&gFuncStringContentListHashTable, &hashKey, fallible));
+                       (PL_DHashTableAdd(&gFuncStringContentListHashTable,
+                                         &hashKey));
     if (entry) {
       list = entry->mContentList;
 #ifdef DEBUG
       MOZ_ASSERT_IF(list, list->mType == ListType::sType);
 #endif
     }
   }
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3959,17 +3959,17 @@ nsContentUtils::GetListenerManagerForNod
     // We're already shut down, don't bother creating an event listener
     // manager.
 
     return nullptr;
   }
 
   EventListenerManagerMapEntry *entry =
     static_cast<EventListenerManagerMapEntry *>
-      (PL_DHashTableAdd(&sEventListenerManagersHash, aNode, fallible));
+               (PL_DHashTableAdd(&sEventListenerManagersHash, aNode));
 
   if (!entry) {
     return nullptr;
   }
 
   if (!entry->mListenerManager) {
     entry->mListenerManager = new EventListenerManager(aNode);
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1710,18 +1710,18 @@ nsDocument::~nsDocument()
     mAnimationController->Disconnect();
   }
 
   mParentDocument = nullptr;
 
   // Kill the subdocument map, doing this will release its strong
   // references, if any.
   if (mSubDocuments) {
-    PL_DHashTableFinish(mSubDocuments);
-    delete mSubDocuments;
+    PL_DHashTableDestroy(mSubDocuments);
+
     mSubDocuments = nullptr;
   }
 
   // Destroy link map now so we don't waste time removing
   // links one by one
   DestroyElementMaps();
 
   nsAutoScriptBlocker scriptBlocker;
@@ -2121,18 +2121,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
 
   if (tmp->mStyleSheetSetList) {
     tmp->mStyleSheetSetList->Disconnect();
     tmp->mStyleSheetSetList = nullptr;
   }
 
   if (tmp->mSubDocuments) {
-    PL_DHashTableFinish(tmp->mSubDocuments);
-    delete tmp->mSubDocuments;
+    PL_DHashTableDestroy(tmp->mSubDocuments);
     tmp->mSubDocuments = nullptr;
   }
 
   tmp->mFrameRequestCallbacks.Clear();
 
   tmp->mRadioGroups.Clear();
 
   // nsDocument has a pretty complex destructor, so we're going to
@@ -2327,18 +2326,18 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
 
   mSecurityInfo = nullptr;
 
   mDocumentLoadGroup = nullptr;
 
   // Delete references to sub-documents and kill the subdocument map,
   // if any. It holds strong references
   if (mSubDocuments) {
-    PL_DHashTableFinish(mSubDocuments);
-    delete mSubDocuments;
+    PL_DHashTableDestroy(mSubDocuments);
+
     mSubDocuments = nullptr;
   }
 
   // Destroy link map now so we don't waste time removing
   // links one by one
   DestroyElementMaps();
 
   bool oldVal = mInUnlinkOrDeletion;
@@ -3997,23 +3996,26 @@ nsDocument::SetSubDocumentFor(Element* a
       {
         PL_DHashVoidPtrKeyStub,
         PL_DHashMatchEntryStub,
         PL_DHashMoveEntryStub,
         SubDocClearEntry,
         SubDocInitEntry
       };
 
-      mSubDocuments = new PLDHashTable();
-      PL_DHashTableInit(mSubDocuments, &hash_table_ops, sizeof(SubDocMapEntry));
+      mSubDocuments = PL_NewDHashTable(&hash_table_ops, sizeof(SubDocMapEntry));
+      if (!mSubDocuments) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
     }
 
     // Add a mapping to the hash table
-    SubDocMapEntry *entry = static_cast<SubDocMapEntry*>
-      (PL_DHashTableAdd(mSubDocuments, aElement, fallible));
+    SubDocMapEntry *entry =
+      static_cast<SubDocMapEntry*>
+                 (PL_DHashTableAdd(mSubDocuments, aElement));
 
     if (!entry) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (entry->mSubDocument) {
       entry->mSubDocument->SetParentDocument(nullptr);
 
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -225,17 +225,17 @@ nsPropertyTable::SetPropertyInternal(nsP
     propertyList->mNext = mPropertyList;
     mPropertyList = propertyList;
   }
 
   // The current property value (if there is one) is replaced and the current
   // value is destroyed
   nsresult result = NS_OK;
   PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
-    (PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject, fallible));
+                                           (PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject));
   if (!entry)
     return NS_ERROR_OUT_OF_MEMORY;
   // A nullptr entry->key is the sign that the entry has just been allocated
   // for us.  If it's non-nullptr then we have an existing entry.
   if (entry->key) {
     if (aOldValue)
       *aOldValue = entry->value;
     else if (propertyList->mDtorFunc)
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -117,35 +117,39 @@ GlobalNameHashInitEntry(PLDHashTable *ta
 
 NS_IMPL_ISUPPORTS(
   nsScriptNameSpaceManager,
   nsIObserver,
   nsISupportsWeakReference,
   nsIMemoryReporter)
 
 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
+  : mIsInitialized(false)
 {
   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
 }
 
 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
 {
-  UnregisterWeakMemoryReporter(this);
-  // Destroy the hash
-  PL_DHashTableFinish(&mGlobalNames);
-  PL_DHashTableFinish(&mNavigatorNames);
+  if (mIsInitialized) {
+    UnregisterWeakMemoryReporter(this);
+    // Destroy the hash
+    PL_DHashTableFinish(&mGlobalNames);
+    PL_DHashTableFinish(&mNavigatorNames);
+  }
   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
 }
 
 nsGlobalNameStruct *
 nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
                                     const char16_t **aClassName)
 {
-  GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>
-    (PL_DHashTableAdd(aTable, aKey, fallible));
+  GlobalNameMapEntry *entry =
+    static_cast<GlobalNameMapEntry *>
+               (PL_DHashTableAdd(aTable, aKey));
 
   if (!entry) {
     return nullptr;
   }
 
   if (aClassName) {
     *aClassName = entry->mKey.get();
   }
@@ -317,23 +321,31 @@ nsScriptNameSpaceManager::Init()
   {
     GlobalNameHashHashKey,
     GlobalNameHashMatchEntry,
     PL_DHashMoveEntryStub,
     GlobalNameHashClearEntry,
     GlobalNameHashInitEntry
   };
 
-  PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
-                    sizeof(GlobalNameMapEntry),
-                    GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
+  mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
+                                     sizeof(GlobalNameMapEntry),
+                                     fallible,
+                                     GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
+  NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
 
-  PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
-                    sizeof(GlobalNameMapEntry),
-                    GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
+  mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
+                                     sizeof(GlobalNameMapEntry),
+                                     fallible,
+                                     GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
+  if (!mIsInitialized) {
+    PL_DHashTableFinish(&mGlobalNames);
+
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
   RegisterWeakMemoryReporter(this);
 
   nsresult rv = NS_OK;
 
   rv = RegisterExternalInterfaces(false);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -235,11 +235,13 @@ private:
                                     nsISupports* aEntry,
                                     bool aRemove);
 
   nsGlobalNameStruct* LookupNameInternal(const nsAString& aName,
                                          const char16_t **aClassName = nullptr);
 
   PLDHashTable mGlobalNames;
   PLDHashTable mNavigatorNames;
+
+  bool mIsInitialized;
 };
 
 #endif /* nsScriptNameSpaceManager_h__ */
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1867,17 +1867,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
   if (!sNPObjWrappers.IsInitialized()) {
     // No hash yet (or any more), initialize it.
     if (!CreateNPObjWrapperTable()) {
       return nullptr;
     }
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
+    (PL_DHashTableAdd(&sNPObjWrappers, npobj));
 
   if (!entry) {
     // Out of memory
     JS_ReportOutOfMemory(cx);
 
     return nullptr;
   }
 
@@ -2030,17 +2030,17 @@ static NPP
 LookupNPP(NPObject *npobj)
 {
   if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
     nsJSObjWrapper* o = static_cast<nsJSObjWrapper*>(npobj);
     return o->mNpp;
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableAdd(&sNPObjWrappers, npobj, fallible));
+    (PL_DHashTableAdd(&sNPObjWrappers, npobj));
 
   if (!entry) {
     return nullptr;
   }
 
   NS_ASSERTION(entry->mNpp, "Live NPObject entry w/o an NPP!");
 
   return entry->mNpp;
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -211,18 +211,17 @@ XULDocument::~XULDocument()
     // decls never got resolved.
     mForwardReferences.Clear();
     // Likewise for any references we have to IDs where we might
     // look for persisted data:
     mPersistenceIds.Clear();
 
     // Destroy our broadcaster map.
     if (mBroadcasterMap) {
-        PL_DHashTableFinish(mBroadcasterMap);
-        delete mBroadcasterMap;
+        PL_DHashTableDestroy(mBroadcasterMap);
     }
 
     delete mTemplateBuilderTable;
 
     Preferences::UnregisterCallback(XULDocument::DirectionChanged,
                                     "intl.uidirection.", this);
 
     if (mOffThreadCompileStringBuf) {
@@ -764,27 +763,32 @@ XULDocument::AddBroadcastListenerFor(Ele
         PL_DHashVoidPtrKeyStub,
         PL_DHashMatchEntryStub,
         PL_DHashMoveEntryStub,
         ClearBroadcasterMapEntry,
         nullptr
     };
 
     if (! mBroadcasterMap) {
-        mBroadcasterMap = new PLDHashTable();
-        PL_DHashTableInit(mBroadcasterMap, &gOps, sizeof(BroadcasterMapEntry));
+        mBroadcasterMap = PL_NewDHashTable(&gOps, sizeof(BroadcasterMapEntry));
+
+        if (! mBroadcasterMap) {
+            aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+            return;
+        }
     }
 
     BroadcasterMapEntry* entry =
         static_cast<BroadcasterMapEntry*>
                    (PL_DHashTableSearch(mBroadcasterMap, &aBroadcaster));
 
     if (!entry) {
-        entry = static_cast<BroadcasterMapEntry*>
-            (PL_DHashTableAdd(mBroadcasterMap, &aBroadcaster, fallible));
+        entry =
+            static_cast<BroadcasterMapEntry*>
+                       (PL_DHashTableAdd(mBroadcasterMap, &aBroadcaster));
 
         if (! entry) {
             aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
             return;
         }
 
         entry->mBroadcaster = &aBroadcaster;
 
--- a/dom/xul/templates/nsContentSupportMap.h
+++ b/dom/xul/templates/nsContentSupportMap.h
@@ -23,18 +23,17 @@ class nsContentSupportMap {
 public:
     nsContentSupportMap() { Init(); }
     ~nsContentSupportMap() { Finish(); }
 
     nsresult Put(nsIContent* aElement, nsTemplateMatch* aMatch) {
         if (!mMap.IsInitialized())
             return NS_ERROR_NOT_INITIALIZED;
 
-        PLDHashEntryHdr* hdr =
-            PL_DHashTableAdd(&mMap, aElement, mozilla::fallible);
+        PLDHashEntryHdr* hdr = PL_DHashTableAdd(&mMap, aElement);
         if (!hdr)
             return NS_ERROR_OUT_OF_MEMORY;
 
         Entry* entry = static_cast<Entry*>(hdr);
         NS_ASSERTION(entry->mMatch == nullptr, "over-writing entry");
         entry->mContent = aElement;
         entry->mMatch   = aMatch;
         return NS_OK;
--- a/dom/xul/templates/nsTemplateMap.h
+++ b/dom/xul/templates/nsTemplateMap.h
@@ -32,18 +32,17 @@ public:
 
     ~nsTemplateMap() { Finish(); }
 
     void
     Put(nsIContent* aContent, nsIContent* aTemplate) {
         NS_ASSERTION(!PL_DHashTableSearch(&mTable, aContent),
                      "aContent already in map");
 
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(&mTable, aContent, fallible));
+        Entry* entry = static_cast<Entry*>(PL_DHashTableAdd(&mTable, aContent));
 
         if (entry) {
             entry->mContent = aContent;
             entry->mTemplate = aTemplate;
         }
     }
 
     void
--- a/embedding/components/commandhandler/nsCommandParams.cpp
+++ b/embedding/components/commandhandler/nsCommandParams.cpp
@@ -225,18 +225,17 @@ nsCommandParams::GetOrMakeEntry(const ch
 {
   HashEntry *foundEntry =
     (HashEntry *)PL_DHashTableSearch(&mValuesHash, (void *)aName);
   if (foundEntry) { // reuse existing entry
     foundEntry->Reset(entryType);
     return foundEntry;
   }
 
-  foundEntry = static_cast<HashEntry*>
-    (PL_DHashTableAdd(&mValuesHash, (void *)aName, fallible));
+  foundEntry = (HashEntry *)PL_DHashTableAdd(&mValuesHash, (void *)aName);
   if (!foundEntry) {
     return nullptr;
   }
 
   // Use placement new. Our ctor does not clobber keyHash, which is important.
   new (foundEntry) HashEntry(entryType, aName);
   return foundEntry;
 }
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -683,18 +683,19 @@ public:
             }
             uint32_t timestamp = strtoul(beginning, nullptr, 10);
             beginning = end + 1;
             if (!(end = strchr(beginning, ';'))) {
                 break;
             }
             uint32_t filesize = strtoul(beginning, nullptr, 10);
 
-            FNCMapEntry* mapEntry = static_cast<FNCMapEntry*>
-                (PL_DHashTableAdd(&mMap, filename.get(), fallible));
+            FNCMapEntry* mapEntry =
+                static_cast<FNCMapEntry*>
+                (PL_DHashTableAdd(&mMap, filename.get()));
             if (mapEntry) {
                 mapEntry->mFilename.Assign(filename);
                 mapEntry->mTimestamp = timestamp;
                 mapEntry->mFilesize = filesize;
                 mapEntry->mFaces.Assign(faceList);
                 // entries from the startupcache are marked "non-existing"
                 // until we have confirmed that the file still exists
                 mapEntry->mFileExists = false;
@@ -731,18 +732,19 @@ public:
 
     virtual void
     CacheFileInfo(const nsCString& aFileName, const nsCString& aFaceList,
                   uint32_t aTimestamp, uint32_t aFilesize)
     {
         if (!mMap.IsInitialized()) {
             return;
         }
-        FNCMapEntry* entry = static_cast<FNCMapEntry*>
-            (PL_DHashTableAdd(&mMap, aFileName.get(), fallible));
+        FNCMapEntry* entry =
+            static_cast<FNCMapEntry*>
+            (PL_DHashTableAdd(&mMap, aFileName.get()));
         if (entry) {
             entry->mFilename.Assign(aFileName);
             entry->mTimestamp = aTimestamp;
             entry->mFilesize = aFilesize;
             entry->mFaces.Assign(aFaceList);
             entry->mFileExists = true;
         }
         mWriteNeeded = true;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1531,18 +1531,19 @@ DetachedWrappedNativeProtoShutdownMarker
 void XPCJSRuntime::DestroyJSContextStack()
 {
     delete mJSContextStack;
     mJSContextStack = nullptr;
 }
 
 void XPCJSRuntime::SystemIsBeingShutDown()
 {
-    mDetachedWrappedNativeProtoMap->
-        Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
+    if (mDetachedWrappedNativeProtoMap)
+        mDetachedWrappedNativeProtoMap->
+            Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
 }
 
 #define JS_OPTIONS_DOT_STR "javascript.options."
 
 static void
 ReloadPrefsCallback(const char *pref, void *data)
 {
     XPCJSRuntime *runtime = reinterpret_cast<XPCJSRuntime *>(data);
@@ -1614,43 +1615,61 @@ XPCJSRuntime::~XPCJSRuntime()
     if (mCallContext)
         mCallContext->SystemIsBeingShutDown();
 
     auto rtPrivate = static_cast<PerThreadAtomCache*>(JS_GetRuntimePrivate(Runtime()));
     delete rtPrivate;
     JS_SetRuntimePrivate(Runtime(), nullptr);
 
     // clean up and destroy maps...
-    mWrappedJSMap->ShutdownMarker();
-    delete mWrappedJSMap;
-    mWrappedJSMap = nullptr;
-
-    delete mWrappedJSClassMap;
-    mWrappedJSClassMap = nullptr;
-
-    delete mIID2NativeInterfaceMap;
-    mIID2NativeInterfaceMap = nullptr;
-
-    delete mClassInfo2NativeSetMap;
-    mClassInfo2NativeSetMap = nullptr;
-
-    delete mNativeSetMap;
-    mNativeSetMap = nullptr;
-
-    delete mThisTranslatorMap;
-    mThisTranslatorMap = nullptr;
-
-    delete mNativeScriptableSharedMap;
-    mNativeScriptableSharedMap = nullptr;
-
-    delete mDyingWrappedNativeProtoMap;
-    mDyingWrappedNativeProtoMap = nullptr;
-
-    delete mDetachedWrappedNativeProtoMap;
-    mDetachedWrappedNativeProtoMap = nullptr;
+    if (mWrappedJSMap) {
+        mWrappedJSMap->ShutdownMarker();
+        delete mWrappedJSMap;
+        mWrappedJSMap = nullptr;
+    }
+
+    if (mWrappedJSClassMap) {
+        delete mWrappedJSClassMap;
+        mWrappedJSClassMap = nullptr;
+    }
+
+    if (mIID2NativeInterfaceMap) {
+        delete mIID2NativeInterfaceMap;
+        mIID2NativeInterfaceMap = nullptr;
+    }
+
+    if (mClassInfo2NativeSetMap) {
+        delete mClassInfo2NativeSetMap;
+        mClassInfo2NativeSetMap = nullptr;
+    }
+
+    if (mNativeSetMap) {
+        delete mNativeSetMap;
+        mNativeSetMap = nullptr;
+    }
+
+    if (mThisTranslatorMap) {
+        delete mThisTranslatorMap;
+        mThisTranslatorMap = nullptr;
+    }
+
+    if (mNativeScriptableSharedMap) {
+        delete mNativeScriptableSharedMap;
+        mNativeScriptableSharedMap = nullptr;
+    }
+
+    if (mDyingWrappedNativeProtoMap) {
+        delete mDyingWrappedNativeProtoMap;
+        mDyingWrappedNativeProtoMap = nullptr;
+    }
+
+    if (mDetachedWrappedNativeProtoMap) {
+        delete mDetachedWrappedNativeProtoMap;
+        mDetachedWrappedNativeProtoMap = nullptr;
+    }
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     // Tell the profiler that the runtime is gone
     if (PseudoStack *stack = mozilla_get_pseudo_stack())
         stack->sampleRuntime(nullptr);
 #endif
 
     Preferences::UnregisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this);
@@ -3490,48 +3509,52 @@ XPCJSRuntime::DebugDump(int16_t depth)
         while (JS_ContextIterator(Runtime(), &iter)) {
             XPCContext *xpc = XPCContext::GetXPCContext(iter);
             XPC_LOG_INDENT();
             xpc->DebugDump(depth);
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",  \
-                        mWrappedJSClassMap, mWrappedJSClassMap->Count()));
+                        mWrappedJSClassMap, mWrappedJSClassMap ?              \
+                        mWrappedJSClassMap->Count() : 0));
         // iterate wrappersclasses...
-        if (depth && mWrappedJSClassMap->Count()) {
+        if (depth && mWrappedJSClassMap && mWrappedJSClassMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
         XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",             \
-                        mWrappedJSMap, mWrappedJSMap->Count()));
+                        mWrappedJSMap, mWrappedJSMap ?                        \
+                        mWrappedJSMap->Count() : 0));
         // iterate wrappers...
-        if (depth && mWrappedJSMap->Count()) {
+        if (depth && mWrappedJSMap && mWrappedJSMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedJSMap->Dump(depth);
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_ALWAYS(("mIID2NativeInterfaceMap @ %x with %d interface(s)",  \
-                        mIID2NativeInterfaceMap,
-                        mIID2NativeInterfaceMap->Count()));
+                        mIID2NativeInterfaceMap, mIID2NativeInterfaceMap ?    \
+                        mIID2NativeInterfaceMap->Count() : 0));
 
         XPC_LOG_ALWAYS(("mClassInfo2NativeSetMap @ %x with %d sets(s)",       \
-                        mClassInfo2NativeSetMap,                              \
-                        mClassInfo2NativeSetMap->Count()));
+                        mClassInfo2NativeSetMap, mClassInfo2NativeSetMap ?    \
+                        mClassInfo2NativeSetMap->Count() : 0));
 
         XPC_LOG_ALWAYS(("mThisTranslatorMap @ %x with %d translator(s)",      \
-                        mThisTranslatorMap, mThisTranslatorMap->Count()));
+                        mThisTranslatorMap, mThisTranslatorMap ?              \
+                        mThisTranslatorMap->Count() : 0));
 
         XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",                 \
-                        mNativeSetMap, mNativeSetMap->Count()));
+                        mNativeSetMap, mNativeSetMap ?                        \
+                        mNativeSetMap->Count() : 0));
 
         // iterate sets...
-        if (depth && mNativeSetMap->Count()) {
+        if (depth && mNativeSetMap && mNativeSetMap->Count()) {
             XPC_LOG_INDENT();
             mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_OUTDENT();
 #endif
 }
--- a/js/xpconnect/src/XPCMaps.cpp
+++ b/js/xpconnect/src/XPCMaps.cpp
@@ -164,37 +164,44 @@ JSObject2WrappedJSMap::SizeOfWrappedJS(m
 
 /***************************************************************************/
 // implement Native2WrappedNativeMap...
 
 // static
 Native2WrappedNativeMap*
 Native2WrappedNativeMap::newMap(int length)
 {
-    return new Native2WrappedNativeMap(length);
+    Native2WrappedNativeMap* map = new Native2WrappedNativeMap(length);
+    if (map && map->mTable)
+        return map;
+    // Allocation of the map or the creation of its hash table has
+    // failed. This will cause a nullptr deref later when we attempt
+    // to use the map, so we abort immediately to provide a more
+    // useful crash stack.
+    NS_RUNTIMEABORT("Ran out of memory.");
+    return nullptr;
 }
 
 Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, PL_DHashGetStubOps(), sizeof(Entry), length);
+    mTable = PL_NewDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 Native2WrappedNativeMap::~Native2WrappedNativeMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 size_t
 Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
+    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
     return n;
 }
 
 /* static */ size_t
 Native2WrappedNativeMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
                                                   mozilla::MallocSizeOf mallocSizeOf, void *)
 {
     return mallocSizeOf(((Native2WrappedNativeMap::Entry*)hdr)->value);
@@ -210,29 +217,32 @@ const struct PLDHashTableOps IID2Wrapped
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 IID2WrappedJSClassMap*
 IID2WrappedJSClassMap::newMap(int length)
 {
-    return new IID2WrappedJSClassMap(length);
+    IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, &Entry::sOps, sizeof(Entry), length);
+    mTable = PL_NewDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 
 /***************************************************************************/
 // implement IID2NativeInterfaceMap...
 
 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
 {
@@ -241,37 +251,40 @@ const struct PLDHashTableOps IID2NativeI
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 IID2NativeInterfaceMap*
 IID2NativeInterfaceMap::newMap(int length)
 {
-    return new IID2NativeInterfaceMap(length);
+    IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, &Entry::sOps, sizeof(Entry), length);
+    mTable = PL_NewDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 size_t
 IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
+    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
     return n;
 }
 
 /* static */ size_t
 IID2NativeInterfaceMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
                                                  mozilla::MallocSizeOf mallocSizeOf, void *)
 {
     XPCNativeInterface *iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
@@ -280,69 +293,79 @@ IID2NativeInterfaceMap::SizeOfEntryExclu
 
 /***************************************************************************/
 // implement ClassInfo2NativeSetMap...
 
 // static
 ClassInfo2NativeSetMap*
 ClassInfo2NativeSetMap::newMap(int length)
 {
-    return new ClassInfo2NativeSetMap(length);
+    ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, PL_DHashGetStubOps(), sizeof(Entry), length);
+    mTable = PL_NewDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 size_t
 ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
     // The second arg is nullptr because this is a "shallow" measurement of the map.
-    n += PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf);
+    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf) : 0;
     return n;
 }
 
 /***************************************************************************/
 // implement ClassInfo2WrappedNativeProtoMap...
 
 // static
 ClassInfo2WrappedNativeProtoMap*
 ClassInfo2WrappedNativeProtoMap::newMap(int length)
 {
-    return new ClassInfo2WrappedNativeProtoMap(length);
+    ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(length);
+    if (map && map->mTable)
+        return map;
+    // Allocation of the map or the creation of its hash table has
+    // failed. This will cause a nullptr deref later when we attempt
+    // to use the map, so we abort immediately to provide a more
+    // useful crash stack.
+    NS_RUNTIMEABORT("Ran out of memory.");
+    return nullptr;
 }
 
 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, PL_DHashGetStubOps(), sizeof(Entry), length);
+    mTable = PL_NewDHashTable(PL_DHashGetStubOps(), sizeof(Entry), length);
 }
 
 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 size_t
 ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
+    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
     return n;
 }
 
 /* static */ size_t
 ClassInfo2WrappedNativeProtoMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
                                                           mozilla::MallocSizeOf mallocSizeOf, void *)
 {
     return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value);
@@ -430,37 +453,40 @@ const struct PLDHashTableOps NativeSetMa
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 NativeSetMap*
 NativeSetMap::newMap(int length)
 {
-    return new NativeSetMap(length);
+    NativeSetMap* map = new NativeSetMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 NativeSetMap::NativeSetMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, &Entry::sOps, sizeof(Entry), length);
+    mTable = PL_NewDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 NativeSetMap::~NativeSetMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 size_t
 NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = 0;
     n += mallocSizeOf(this);
-    n += PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf);
+    n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
     return n;
 }
 
 /* static */ size_t
 NativeSetMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *)
 {
     XPCNativeSet *set = ((NativeSetMap::Entry*)hdr)->key_value;
     return set->SizeOfIncludingThis(mallocSizeOf);
@@ -491,29 +517,32 @@ const struct PLDHashTableOps IID2ThisTra
     PL_DHashMoveEntryStub,
     Clear
 };
 
 // static
 IID2ThisTranslatorMap*
 IID2ThisTranslatorMap::newMap(int length)
 {
-    return new IID2ThisTranslatorMap(length);
+    IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, &Entry::sOps, sizeof(Entry), length);
+    mTable = PL_NewDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 /***************************************************************************/
 
 PLDHashNumber
 XPCNativeScriptableSharedMap::Entry::Hash(PLDHashTable *table, const void *key)
 {
     PLDHashNumber h;
@@ -564,42 +593,45 @@ const struct PLDHashTableOps XPCNativeSc
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub
 };
 
 // static
 XPCNativeScriptableSharedMap*
 XPCNativeScriptableSharedMap::newMap(int length)
 {
-    return new XPCNativeScriptableSharedMap(length);
+    XPCNativeScriptableSharedMap* map =
+        new XPCNativeScriptableSharedMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, &Entry::sOps, sizeof(Entry), length);
+    mTable = PL_NewDHashTable(&Entry::sOps, sizeof(Entry), length);
 }
 
 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 bool
 XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags,
                                            char* name,
                                            XPCNativeScriptableInfo* si)
 {
     NS_PRECONDITION(name,"bad param");
     NS_PRECONDITION(si,"bad param");
 
     XPCNativeScriptableShared key(flags, name);
-    Entry* entry = static_cast<Entry*>
-        (PL_DHashTableAdd(mTable, &key, fallible));
+    Entry* entry = (Entry*) PL_DHashTableAdd(mTable, &key);
     if (!entry)
         return false;
 
     XPCNativeScriptableShared* shared = entry->key;
 
     if (!shared) {
         entry->key = shared =
             new XPCNativeScriptableShared(flags, key.TransferNameOwnership());
@@ -613,25 +645,28 @@ XPCNativeScriptableSharedMap::GetNewOrUs
 
 /***************************************************************************/
 // implement XPCWrappedNativeProtoMap...
 
 // static
 XPCWrappedNativeProtoMap*
 XPCWrappedNativeProtoMap::newMap(int length)
 {
-    return new XPCWrappedNativeProtoMap(length);
+    XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(length);
+    if (map && map->mTable)
+        return map;
+    delete map;
+    return nullptr;
 }
 
 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length)
 {
-    mTable = new PLDHashTable();
-    PL_DHashTableInit(mTable, PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
-                      length);
+    mTable = PL_NewDHashTable(PL_DHashGetStubOps(),
+                              sizeof(PLDHashEntryStub), length);
 }
 
 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
 {
-    PL_DHashTableFinish(mTable);
-    delete mTable;
+    if (mTable)
+        PL_DHashTableDestroy(mTable);
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -27,17 +27,17 @@
 class JSObject2WrappedJSMap
 {
     typedef js::HashMap<JSObject*, nsXPCWrappedJS*, js::PointerHasher<JSObject*, 3>,
                         js::SystemAllocPolicy> Map;
 
 public:
     static JSObject2WrappedJSMap* newMap(int length) {
         JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap();
-        if (map->mTable.init(length))
+        if (map && map->mTable.init(length))
             return map;
         delete map;
         return nullptr;
     }
 
     inline nsXPCWrappedJS* Find(JSObject* Obj) {
         NS_PRECONDITION(Obj,"bad param");
         Map::Ptr p = mTable.lookup(Obj);
@@ -115,18 +115,17 @@ public:
         return entry ? entry->value : nullptr;
     }
 
     inline XPCWrappedNative* Add(XPCWrappedNative* wrapper)
     {
         NS_PRECONDITION(wrapper,"bad param");
         nsISupports* obj = wrapper->GetIdentityObject();
         MOZ_ASSERT(!Find(obj), "wrapper already in new scope!");
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, obj, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, obj);
         if (!entry)
             return nullptr;
         if (entry->key)
             return entry->value;
         entry->key = obj;
         entry->value = wrapper;
         return wrapper;
     }
@@ -181,18 +180,17 @@ public:
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, &iid);
         return entry ? entry->value : nullptr;
     }
 
     inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz)
     {
         NS_PRECONDITION(clazz,"bad param");
         const nsIID* iid = &clazz->GetIID();
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, iid, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, iid);
         if (!entry)
             return nullptr;
         if (entry->key)
             return entry->value;
         entry->key = iid;
         entry->value = clazz;
         return clazz;
     }
@@ -235,18 +233,17 @@ public:
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, &iid);
         return entry ? entry->value : nullptr;
     }
 
     inline XPCNativeInterface* Add(XPCNativeInterface* iface)
     {
         NS_PRECONDITION(iface,"bad param");
         const nsIID* iid = iface->GetIID();
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, iid, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, iid);
         if (!entry)
             return nullptr;
         if (entry->key)
             return entry->value;
         entry->key = iid;
         entry->value = iface;
         return iface;
     }
@@ -291,18 +288,17 @@ public:
     {
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, info);
         return entry ? entry->value : nullptr;
     }
 
     inline XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set)
     {
         NS_PRECONDITION(info,"bad param");
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, info, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, info);
         if (!entry)
             return nullptr;
         if (entry->key)
             return entry->value;
         entry->key = info;
         entry->value = set;
         return set;
     }
@@ -348,18 +344,17 @@ public:
     {
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, info);
         return entry ? entry->value : nullptr;
     }
 
     inline XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto)
     {
         NS_PRECONDITION(info,"bad param");
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, info, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, info);
         if (!entry)
             return nullptr;
         if (entry->key)
             return entry->value;
         entry->key = info;
         entry->value = proto;
         return proto;
     }
@@ -411,18 +406,17 @@ public:
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, key);
         return entry ? entry->key_value : nullptr;
     }
 
     inline XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set)
     {
         NS_PRECONDITION(key,"bad param");
         NS_PRECONDITION(set,"bad param");
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, key, mozilla::fallible));
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, key);
         if (!entry)
             return nullptr;
         if (entry->key_value)
             return entry->key_value;
         entry->key_value = set;
         return set;
     }
 
@@ -484,18 +478,18 @@ public:
     {
         Entry* entry = (Entry*) PL_DHashTableSearch(mTable, &iid);
         return entry ? entry->value : nullptr;
     }
 
     inline nsIXPCFunctionThisTranslator* Add(REFNSIID iid,
                                              nsIXPCFunctionThisTranslator* obj)
     {
-        Entry* entry = static_cast<Entry*>
-            (PL_DHashTableAdd(mTable, &iid, mozilla::fallible));
+
+        Entry* entry = (Entry*) PL_DHashTableAdd(mTable, &iid);
         if (!entry)
             return nullptr;
         entry->value = obj;
         entry->key = iid;
         return obj;
     }
 
     inline void Remove(REFNSIID iid)
@@ -556,18 +550,18 @@ private:
 class XPCWrappedNativeProtoMap
 {
 public:
     static XPCWrappedNativeProtoMap* newMap(int length);
 
     inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto)
     {
         NS_PRECONDITION(proto,"bad param");
-        PLDHashEntryStub* entry = static_cast<PLDHashEntryStub*>
-            (PL_DHashTableAdd(mTable, proto, mozilla::fallible));
+        PLDHashEntryStub* entry = (PLDHashEntryStub*)
+            PL_DHashTableAdd(mTable, proto);
         if (!entry)
             return nullptr;
         if (entry->key)
             return (XPCWrappedNativeProto*) entry->key;
         entry->key = proto;
         return proto;
     }
 
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -170,19 +170,18 @@ nsFrameManager::RegisterPlaceholderFrame
 {
   NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
   NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
                   "unexpected frame type");
   if (!mPlaceholderMap.IsInitialized()) {
     PL_DHashTableInit(&mPlaceholderMap, &PlaceholderMapOps,
                       sizeof(PlaceholderMapEntry));
   }
-  PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>
-    (PL_DHashTableAdd(&mPlaceholderMap,
-                      aPlaceholderFrame->GetOutOfFlowFrame(), fallible));
+  PlaceholderMapEntry *entry = static_cast<PlaceholderMapEntry*>(PL_DHashTableAdd(&mPlaceholderMap,
+                              aPlaceholderFrame->GetOutOfFlowFrame()));
   if (!entry)
     return NS_ERROR_OUT_OF_MEMORY;
 
   NS_ASSERTION(!entry->placeholderFrame, "Registering a placeholder for a frame that already has a placeholder!");
   entry->placeholderFrame = aPlaceholderFrame;
 
   return NS_OK;
 }
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -568,29 +568,29 @@ RuleHash::~RuleHash()
   }
 }
 
 void RuleHash::AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
                                  const RuleSelectorPair& aRuleInfo)
 {
   // Get a new or existing entry.
   RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
-    (PL_DHashTableAdd(aTable, aKey, fallible));
+                                         (PL_DHashTableAdd(aTable, aKey));
   if (!entry)
     return;
   entry->mRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
 }
 
 static void
 AppendRuleToTagTable(PLDHashTable* aTable, nsIAtom* aKey,
                      const RuleValue& aRuleInfo)
 {
   // Get a new or exisiting entry
   RuleHashTagTableEntry *entry = static_cast<RuleHashTagTableEntry*>
-    (PL_DHashTableAdd(aTable, aKey, fallible));
+    (PL_DHashTableAdd(aTable, aKey));
   if (!entry)
     return;
 
   entry->mRules.AppendElement(aRuleInfo);
 }
 
 void RuleHash::AppendUniversalRule(const RuleSelectorPair& aRuleInfo)
 {
@@ -1036,17 +1036,17 @@ RuleCascadeData::SizeOfIncludingThis(Mal
   return n;
 }
 
 nsTArray<nsCSSSelector*>*
 RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
 {
   AtomSelectorEntry *entry =
     static_cast<AtomSelectorEntry*>
-               (PL_DHashTableAdd(&mAttributeSelectors, aAttribute, fallible));
+               (PL_DHashTableAdd(&mAttributeSelectors, aAttribute));
   if (!entry)
     return nullptr;
   return &entry->mSelectors;
 }
 
 // -------------------------------
 // CSS Style rule processor implementation
 //
@@ -3129,33 +3129,34 @@ AddSelector(RuleCascadeData* aCascade,
         nsCSSRuleProcessor::StateSelector(dependentStates,
                                           aSelectorInTopLevel));
     }
 
     // Build mIDSelectors
     if (negation == aSelectorInTopLevel) {
       for (nsAtomList* curID = negation->mIDList; curID;
            curID = curID->mNext) {
-        AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>
-          (PL_DHashTableAdd(&aCascade->mIdSelectors, curID->mAtom, fallible));
+        AtomSelectorEntry *entry =
+          static_cast<AtomSelectorEntry*>(PL_DHashTableAdd(&aCascade->mIdSelectors,
+                                                           curID->mAtom));
         if (entry) {
           entry->mSelectors.AppendElement(aSelectorInTopLevel);
         }
       }
     } else if (negation->mIDList) {
       aCascade->mPossiblyNegatedIDSelectors.AppendElement(aSelectorInTopLevel);
     }
 
     // Build mClassSelectors
     if (negation == aSelectorInTopLevel) {
       for (nsAtomList* curClass = negation->mClassList; curClass;
            curClass = curClass->mNext) {
-        AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>
-          (PL_DHashTableAdd(&aCascade->mClassSelectors, curClass->mAtom,
-                            fallible));
+        AtomSelectorEntry *entry =
+          static_cast<AtomSelectorEntry*>(PL_DHashTableAdd(&aCascade->mClassSelectors,
+                                                           curClass->mAtom));
         if (entry) {
           entry->mSelectors.AppendElement(aSelectorInTopLevel);
         }
       }
     } else if (negation->mClassList) {
       aCascade->mPossiblyNegatedClassSelectors.AppendElement(aSelectorInTopLevel);
     }
 
@@ -3404,18 +3405,17 @@ CascadeRuleEnumFunc(css::Rule* aRule, vo
 
   if (css::Rule::STYLE_RULE == type) {
     css::StyleRule* styleRule = static_cast<css::StyleRule*>(aRule);
 
     for (nsCSSSelectorList *sel = styleRule->Selector();
          sel; sel = sel->mNext) {
       int32_t weight = sel->mWeight;
       RuleByWeightEntry *entry = static_cast<RuleByWeightEntry*>(
-        PL_DHashTableAdd(&data->mRulesByWeight, NS_INT32_TO_PTR(weight),
-                         fallible));
+        PL_DHashTableAdd(&data->mRulesByWeight, NS_INT32_TO_PTR(weight)));
       if (!entry)
         return false;
       entry->data.mWeight = weight;
       // entry->data.mRuleSelectorPairs should be linked in forward order;
       // entry->data.mTail is the slot to write to.
       PerWeightDataListItem *newItem =
         new (data->mArena) PerWeightDataListItem(styleRule, sel->mSelectors);
       if (newItem) {
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -478,19 +478,18 @@ nsHTMLStyleSheet::SetVisitedLinkColor(ns
 
 already_AddRefed<nsMappedAttributes>
 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes* aMapped)
 {
   if (!mMappedAttrTable.IsInitialized()) {
     PL_DHashTableInit(&mMappedAttrTable, &MappedAttrTable_Ops,
                       sizeof(MappedAttrTableEntry));
   }
-  MappedAttrTableEntry *entry =
-    static_cast<MappedAttrTableEntry*>
-               (PL_DHashTableAdd(&mMappedAttrTable, aMapped, fallible));
+  MappedAttrTableEntry *entry = static_cast<MappedAttrTableEntry*>
+                                           (PL_DHashTableAdd(&mMappedAttrTable, aMapped));
   if (!entry)
     return nullptr;
   if (!entry->mAttributes) {
     // We added a new entry to the hashtable, so we have a new unique set.
     entry->mAttributes = aMapped;
   }
   nsRefPtr<nsMappedAttributes> ret = entry->mAttributes;
   return ret.forget();
@@ -514,17 +513,17 @@ nsHTMLStyleSheet::DropMappedAttributes(n
 nsIStyleRule*
 nsHTMLStyleSheet::LangRuleFor(const nsString& aLanguage)
 {
   if (!mLangRuleTable.IsInitialized()) {
     PL_DHashTableInit(&mLangRuleTable, &LangRuleTable_Ops,
                       sizeof(LangRuleTableEntry));
   }
   LangRuleTableEntry *entry = static_cast<LangRuleTableEntry*>
-    (PL_DHashTableAdd(&mLangRuleTable, &aLanguage, fallible));
+    (PL_DHashTableAdd(&mLangRuleTable, &aLanguage));
   if (!entry) {
     NS_ASSERTION(false, "out of memory");
     return nullptr;
   }
   return entry->mRule;
 }
 
 static size_t
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1415,18 +1415,17 @@ nsRuleNode::DestroyInternal(nsRuleNode *
     destroyQueueTail = &destroyQueue;
   }
 
   if (ChildrenAreHashed()) {
     PLDHashTable *children = ChildrenHash();
     PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
                            &destroyQueueTail);
     *destroyQueueTail = nullptr; // ensure null-termination
-    PL_DHashTableFinish(children);
-    delete children;
+    PL_DHashTableDestroy(children);
   } else if (HaveChildren()) {
     *destroyQueueTail = ChildrenList();
     do {
       destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
     } while (*destroyQueueTail);
   }
   mChildren.asVoid = nullptr;
 
@@ -1529,17 +1528,17 @@ nsRuleNode::Transition(nsIStyleRule* aRu
     if (curr)
       next = curr;
     else if (numKids >= kMaxChildrenInList)
       ConvertChildrenToHash(numKids);
   }
 
   if (ChildrenAreHashed()) {
     ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
-      (PL_DHashTableAdd(ChildrenHash(), &key, fallible));
+                                          (PL_DHashTableAdd(ChildrenHash(), &key));
     if (!entry) {
       NS_WARNING("out of memory");
       return this;
     }
     if (entry->mRuleNode)
       next = entry->mRuleNode;
     else {
       next = entry->mRuleNode = new (mPresContext)
@@ -1599,23 +1598,25 @@ void nsRuleNode::SetUsedDirectly()
   }
 }
 
 void
 nsRuleNode::ConvertChildrenToHash(int32_t aNumKids)
 {
   NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
                "must have a non-empty list of children");
-  PLDHashTable *hash = new PLDHashTable();
-  PL_DHashTableInit(hash, &ChildrenHashOps, sizeof(ChildrenHashEntry),
-                    aNumKids);
+  PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps,
+                                        sizeof(ChildrenHashEntry),
+                                        aNumKids);
+  if (!hash)
+    return;
   for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
     // This will never fail because of the initial size we gave the table.
     ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
-      PL_DHashTableAdd(hash, curr->mRule, fallible));
+      PL_DHashTableAdd(hash, curr->mRule));
     NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
     entry->mRuleNode = curr;
   }
   SetChildrenHash(hash);
 }
 
 inline void
 nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
@@ -9226,18 +9227,17 @@ nsRuleNode::SweepChildren(nsTArray<nsRul
   uint32_t childrenDestroyed = 0;
   nsRuleNode* survivorsWithChildren = nullptr;
   if (ChildrenAreHashed()) {
     PLDHashTable* children = ChildrenHash();
     uint32_t oldChildCount = children->EntryCount();
     PL_DHashTableEnumerate(children, SweepHashEntry, &survivorsWithChildren);
     childrenDestroyed = oldChildCount - children->EntryCount();
     if (childrenDestroyed == oldChildCount) {
-      PL_DHashTableFinish(children);
-      delete children;
+      PL_DHashTableDestroy(children);
       mChildren.asVoid = nullptr;
     }
   } else {
     for (nsRuleNode** children = ChildrenListPtr(); *children; ) {
       nsRuleNode* next = (*children)->mNextSibling;
       if ((*children)->DestroyIfNotMarked()) {
         // This rule node was destroyed, unlink it from the list by
         // making *children point to the next entry.
--- a/layout/tables/SpanningCellSorter.cpp
+++ b/layout/tables/SpanningCellSorter.cpp
@@ -70,18 +70,17 @@ SpanningCellSorter::AddCell(int32_t aCol
         i->next = mArray[index];
         mArray[index] = i;
     } else {
         if (!mHashTable.IsInitialized()) {
             PL_DHashTableInit(&mHashTable, &HashTableOps,
                               sizeof(HashTableEntry));
         }
         HashTableEntry *entry = static_cast<HashTableEntry*>
-            (PL_DHashTableAdd(&mHashTable, NS_INT32_TO_PTR(aColSpan),
-                              fallible));
+                                           (PL_DHashTableAdd(&mHashTable, NS_INT32_TO_PTR(aColSpan)));
         NS_ENSURE_TRUE(entry, false);
 
         NS_ASSERTION(entry->mColSpan == 0 || entry->mColSpan == aColSpan,
                      "wrong entry");
         NS_ASSERTION((entry->mColSpan == 0) == (entry->mItems == nullptr),
                      "entry should be either new or properly initialized");
         entry->mColSpan = aColSpan;
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -518,17 +518,18 @@ NS_INTERFACE_MAP_END
  * nsIPrefService Implementation
  */
 
 nsresult
 Preferences::Init()
 {
   nsresult rv;
 
-  PREF_Init();
+  rv = PREF_Init();
+  NS_ENSURE_SUCCESS(rv, rv);
 
   rv = pref_InitInitialObjects();
   NS_ENSURE_SUCCESS(rv, rv);
 
   using mozilla::dom::ContentChild;
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     InfallibleTArray<PrefSetting> prefs;
     ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
@@ -638,17 +639,18 @@ Preferences::ResetPrefs()
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     NS_ERROR("cannot reset prefs from content process");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
   PREF_CleanupPrefs();
 
-  PREF_Init();
+  nsresult rv = PREF_Init();
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return pref_InitInitialObjects();
 }
 
 NS_IMETHODIMP
 Preferences::ResetUserPrefs()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -138,24 +138,29 @@ static nsresult pref_DoCallback(const ch
 enum {
     kPrefSetDefault = 1,
     kPrefForceSet = 2
 };
 static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags);
 
 #define PREF_HASHTABLE_INITIAL_LENGTH   1024
 
-void PREF_Init()
+nsresult PREF_Init()
 {
     if (!gHashTable.IsInitialized()) {
-        PL_DHashTableInit(&gHashTable, &pref_HashTableOps,
-                          sizeof(PrefHashEntry), PREF_HASHTABLE_INITIAL_LENGTH);
+        if (!PL_DHashTableInit(&gHashTable, &pref_HashTableOps,
+                               sizeof(PrefHashEntry), fallible,
+                               PREF_HASHTABLE_INITIAL_LENGTH)) {
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
+
         PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
                            PREFNAME_ARENA_SIZE);
     }
+    return NS_OK;
 }
 
 /* Frees the callback list. */
 void PREF_Cleanup()
 {
     NS_ASSERTION(!gCallbacksInProgress,
         "PREF_Cleanup was called while gCallbacksInProgress is true!");
     struct CallbackNode* node = gCallbacks;
@@ -730,18 +735,17 @@ nsresult pref_HashPref(const char *key, 
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
     if (!gHashTable.IsInitialized())
         return NS_ERROR_OUT_OF_MEMORY;
 
-    PrefHashEntry* pref = static_cast<PrefHashEntry*>
-        (PL_DHashTableAdd(&gHashTable, key, fallible));
+    PrefHashEntry* pref = static_cast<PrefHashEntry*>(PL_DHashTableAdd(&gHashTable, key));
 
     if (!pref)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // new entry, better initialize
     if (!pref->key) {
 
         // initialize the pref entry
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -37,17 +37,17 @@ struct PrefHashEntry : PLDHashEntryHdr
 };
 
 /*
 // <font color=blue>
 // The Init function initializes the preference context and creates
 // the preference hashtable.
 // </font>
 */
-void        PREF_Init();
+nsresult    PREF_Init();
 
 /*
 // Cleanup should be called at program exit to free the 
 // list of registered callbacks.
 */
 void        PREF_Cleanup();
 void        PREF_CleanupPrefs();
 
--- a/netwerk/base/nsLoadGroup.cpp
+++ b/netwerk/base/nsLoadGroup.cpp
@@ -506,18 +506,19 @@ nsLoadGroup::AddRequest(nsIRequest *requ
     else
         rv = MergeLoadFlags(request, flags);
     if (NS_FAILED(rv)) return rv;
     
     //
     // Add the request to the list of active requests...
     //
 
-    RequestMapEntry *entry = static_cast<RequestMapEntry *>
-        (PL_DHashTableAdd(&mRequests, request, fallible));
+    RequestMapEntry *entry =
+        static_cast<RequestMapEntry *>
+                   (PL_DHashTableAdd(&mRequests, request));
 
     if (!entry) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (mPriority != 0)
         RescheduleRequest(request, mPriority);
 
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -380,101 +380,107 @@ nsCacheEntryHashTable::ops =
     HashKey,
     MatchEntry,
     MoveEntry,
     ClearEntry
 };
 
 
 nsCacheEntryHashTable::nsCacheEntryHashTable()
+    : initialized(false)
 {
     MOZ_COUNT_CTOR(nsCacheEntryHashTable);
 }
 
 
 nsCacheEntryHashTable::~nsCacheEntryHashTable()
 {
     MOZ_COUNT_DTOR(nsCacheEntryHashTable);
-    Shutdown();
+    if (initialized)
+        Shutdown();
 }
 
 
-void
+nsresult
 nsCacheEntryHashTable::Init()
 {
-    PL_DHashTableInit(&table, &ops, sizeof(nsCacheEntryHashTableEntry), 256);
+    nsresult rv = NS_OK;
+    initialized = PL_DHashTableInit(&table, &ops,
+                                    sizeof(nsCacheEntryHashTableEntry),
+                                    fallible, 256);
+
+    if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
+
+    return rv;
 }
 
 void
 nsCacheEntryHashTable::Shutdown()
 {
-    if (table.IsInitialized()) {
+    if (initialized) {
         PL_DHashTableFinish(&table);
+        initialized = false;
     }
 }
 
 
 nsCacheEntry *
 nsCacheEntryHashTable::GetEntry( const nsCString * key)
 {
-    NS_ASSERTION(table.IsInitialized(),
-                 "nsCacheEntryHashTable not initialized");
-    if (!table.IsInitialized())  return nullptr;
+    NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
+    if (!initialized)  return nullptr;
 
     PLDHashEntryHdr *hashEntry = PL_DHashTableSearch(&table, key);
     return hashEntry ? ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry
                      : nullptr;
 }
 
 
 nsresult
 nsCacheEntryHashTable::AddEntry( nsCacheEntry *cacheEntry)
 {
     PLDHashEntryHdr    *hashEntry;
 
-    NS_ASSERTION(table.IsInitialized(),
-                 "nsCacheEntryHashTable not initialized");
-    if (!table.IsInitialized())  return NS_ERROR_NOT_INITIALIZED;
+    NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
+    if (!initialized)  return NS_ERROR_NOT_INITIALIZED;
     if (!cacheEntry)   return NS_ERROR_NULL_POINTER;
 
-    hashEntry = PL_DHashTableAdd(&table, &(cacheEntry->mKey), fallible);
+    hashEntry = PL_DHashTableAdd(&table, &(cacheEntry->mKey));
 #ifndef DEBUG_dougt
     NS_ASSERTION(((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry == 0,
                  "### nsCacheEntryHashTable::AddEntry - entry already used");
 #endif
     ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = cacheEntry;
 
     return NS_OK;
 }
 
 
 void
 nsCacheEntryHashTable::RemoveEntry( nsCacheEntry *cacheEntry)
 {
-    NS_ASSERTION(table.IsInitialized(),
-                 "nsCacheEntryHashTable not initialized");
+    NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
     NS_ASSERTION(cacheEntry, "### cacheEntry == nullptr");
 
-    if (!table.IsInitialized())  return; // NS_ERROR_NOT_INITIALIZED
+    if (!initialized)  return; // NS_ERROR_NOT_INITIALIZED
 
 #if DEBUG
     // XXX debug code to make sure we have the entry we're trying to remove
     nsCacheEntry *check = GetEntry(&(cacheEntry->mKey));
     NS_ASSERTION(check == cacheEntry, "### Attempting to remove unknown cache entry!!!");
 #endif
     PL_DHashTableRemove(&table, &(cacheEntry->mKey));
 }
 
 
 void
 nsCacheEntryHashTable::VisitEntries( PLDHashEnumerator etor, void *arg)
 {
-    NS_ASSERTION(table.IsInitialized(),
-                 "nsCacheEntryHashTable not initialized");
-    if (!table.IsInitialized())  return; // NS_ERROR_NOT_INITIALIZED
+    NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
+    if (!initialized)  return; // NS_ERROR_NOT_INITIALIZED
     PL_DHashTableEnumerate(&table, etor, arg);
 }
 
 
 /**
  *  hash table operation callback functions
  */
 
--- a/netwerk/cache/nsCacheEntry.h
+++ b/netwerk/cache/nsCacheEntry.h
@@ -262,17 +262,17 @@ typedef struct {
 
 
 class nsCacheEntryHashTable
 {
 public:
     nsCacheEntryHashTable();
     ~nsCacheEntryHashTable();
 
-    void          Init();
+    nsresult      Init();
     void          Shutdown();
 
     nsCacheEntry *GetEntry( const nsCString * key);
     nsresult      AddEntry( nsCacheEntry *entry);
     void          RemoveEntry( nsCacheEntry *entry);
     
     void          VisitEntries( PLDHashEnumerator etor, void *arg);
 
@@ -301,11 +301,12 @@ private:
     PLDHashOperator       VisitEntry(PLDHashTable *         table,
                                      PLDHashEntryHdr *      hdr,
                                      uint32_t               number,
                                      void *                 arg);
                                      
     // member variables
     static const PLDHashTableOps ops;
     PLDHashTable                 table;
+    bool                         initialized;
 };
 
 #endif // _nsCacheEntry_h_
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1150,17 +1150,18 @@ nsCacheService::Init()
     }
 
     rv = nsDeleteDir::Init();
     if (NS_FAILED(rv)) {
         NS_WARNING("Can't initialize nsDeleteDir");
     }
 
     // initialize hashtable for active cache entries
-    mActiveEntries.Init();
+    rv = mActiveEntries.Init();
+    if (NS_FAILED(rv)) return rv;
 
     // create profile/preference observer
     if (!mObserver) {
       mObserver = new nsCacheProfilePrefObserver();
       NS_ADDREF(mObserver);
       mObserver->Install();
     }
 
--- a/netwerk/cache/nsDiskCacheBinding.cpp
+++ b/netwerk/cache/nsDiskCacheBinding.cpp
@@ -231,18 +231,17 @@ nsDiskCacheBindery::AddBinding(nsDiskCac
 {
     NS_ENSURE_ARG_POINTER(binding);
     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
 
     // find hash entry for key
     HashTableEntry * hashEntry;
     hashEntry = (HashTableEntry *)
       PL_DHashTableAdd(&table,
-                       (void *)(uintptr_t) binding->mRecord.HashNumber(),
-                       fallible);
+                       (void *)(uintptr_t) binding->mRecord.HashNumber());
     if (!hashEntry) return NS_ERROR_OUT_OF_MEMORY;
     
     if (hashEntry->mBinding == nullptr) {
         hashEntry->mBinding = binding;
         if (binding->mGeneration == 0)
             binding->mGeneration = 1;   // if generation uninitialized, set it to 1
             
         return NS_OK;
--- a/netwerk/cache/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/nsMemoryCacheDevice.cpp
@@ -50,19 +50,19 @@ nsMemoryCacheDevice::~nsMemoryCacheDevic
 }
 
 
 nsresult
 nsMemoryCacheDevice::Init()
 {
     if (mInitialized)  return NS_ERROR_ALREADY_INITIALIZED;
 
-    mMemCacheEntries.Init();
-    mInitialized = true;
-    return NS_OK;
+    nsresult  rv = mMemCacheEntries.Init();
+    mInitialized = NS_SUCCEEDED(rv);
+    return rv;
 }
 
 
 nsresult
 nsMemoryCacheDevice::Shutdown()
 {
     NS_ASSERTION(mInitialized, "### attempting shutdown while not initialized");
     NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -759,17 +759,17 @@ nsHostResolver::ResolveHost(const char  
             // in the hash table.  if so, then check to see if we can't
             // just reuse the lookup result.  otherwise, if there are
             // any pending callbacks, then add to pending callbacks queue,
             // and return.  otherwise, add ourselves as first pending
             // callback, and proceed to do the lookup.
 
             nsHostKey key = { host, flags, af };
             nsHostDBEnt *he = static_cast<nsHostDBEnt *>
-                (PL_DHashTableAdd(&mDB, &key, fallible));
+                                         (PL_DHashTableAdd(&mDB, &key));
 
             // if the record is null, the hash table OOM'd.
             if (!he) {
                 LOG(("  Out of memory: no cache entry for [%s].\n", host));
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             // do we have a cached result that we can reuse?
             else if (!(flags & RES_BYPASS_CACHE) &&
--- a/netwerk/protocol/http/nsHttp.cpp
+++ b/netwerk/protocol/http/nsHttp.cpp
@@ -100,30 +100,32 @@ nsHttp::CreateAtomTable()
 
     if (!sLock) {
         sLock = new Mutex("nsHttp.sLock");
     }
 
     // The initial length for this table is a value greater than the number of
     // known atoms (NUM_HTTP_ATOMS) because we expect to encounter a few random
     // headers right off the bat.
-    PL_DHashTableInit(&sAtomTable, &ops, sizeof(PLDHashEntryStub),
-                      NUM_HTTP_ATOMS + 10);
+    if (!PL_DHashTableInit(&sAtomTable, &ops, sizeof(PLDHashEntryStub),
+                           fallible, NUM_HTTP_ATOMS + 10)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     // fill the table with our known atoms
     const char *const atoms[] = {
 #define HTTP_ATOM(_name, _value) nsHttp::_name._val,
 #include "nsHttpAtomList.h"
 #undef HTTP_ATOM
         nullptr
     };
 
     for (int i = 0; atoms[i]; ++i) {
         PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
-            (PL_DHashTableAdd(&sAtomTable, atoms[i], fallible));
+                                                 (PL_DHashTableAdd(&sAtomTable, atoms[i]));
         if (!stub)
             return NS_ERROR_OUT_OF_MEMORY;
 
         MOZ_ASSERT(!stub->key, "duplicate static atom");
         stub->key = atoms[i];
     }
 
     return NS_OK;
@@ -161,17 +163,17 @@ nsHttp::ResolveAtom(const char *str)
     nsHttpAtom atom = { nullptr };
 
     if (!str || !sAtomTable.IsInitialized())
         return atom;
 
     MutexAutoLock lock(*sLock);
 
     PLDHashEntryStub *stub = reinterpret_cast<PLDHashEntryStub *>
-        (PL_DHashTableAdd(&sAtomTable, str, fallible));
+                                             (PL_DHashTableAdd(&sAtomTable, str));
     if (!stub)
         return atom;  // out of memory
 
     if (stub->key) {
         atom._val = reinterpret_cast<const char *>(stub->key);
         return atom;
     }
 
--- a/parser/htmlparser/nsHTMLEntities.cpp
+++ b/parser/htmlparser/nsHTMLEntities.cpp
@@ -78,38 +78,44 @@ static const EntityNode gEntityArray[] =
 #undef HTML_ENTITY
 
 #define NS_HTML_ENTITY_COUNT ((int32_t)ArrayLength(gEntityArray))
 
 nsresult
 nsHTMLEntities::AddRefTable(void)
 {
   if (!gTableRefCnt) {
-    PL_DHashTableInit(&gEntityToUnicode, &EntityToUnicodeOps,
-                      sizeof(EntityNodeEntry), NS_HTML_ENTITY_COUNT);
-    PL_DHashTableInit(&gUnicodeToEntity, &UnicodeToEntityOps,
-                      sizeof(EntityNodeEntry), NS_HTML_ENTITY_COUNT);
+    if (!PL_DHashTableInit(&gEntityToUnicode, &EntityToUnicodeOps,
+                           sizeof(EntityNodeEntry),
+                           fallible, NS_HTML_ENTITY_COUNT)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    if (!PL_DHashTableInit(&gUnicodeToEntity, &UnicodeToEntityOps,
+                           sizeof(EntityNodeEntry),
+                           fallible, NS_HTML_ENTITY_COUNT)) {
+      PL_DHashTableFinish(&gEntityToUnicode);
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
     for (const EntityNode *node = gEntityArray,
                  *node_end = ArrayEnd(gEntityArray);
          node < node_end; ++node) {
 
       // add to Entity->Unicode table
       EntityNodeEntry* entry =
         static_cast<EntityNodeEntry*>
-                   (PL_DHashTableAdd(&gEntityToUnicode, node->mStr, fallible));
+                   (PL_DHashTableAdd(&gEntityToUnicode, node->mStr));
       NS_ASSERTION(entry, "Error adding an entry");
       // Prefer earlier entries when we have duplication.
       if (!entry->node)
         entry->node = node;
 
       // add to Unicode->Entity table
       entry = static_cast<EntityNodeEntry*>
                          (PL_DHashTableAdd(&gUnicodeToEntity,
-                                           NS_INT32_TO_PTR(node->mUnicode),
-                                           fallible));
+                                           NS_INT32_TO_PTR(node->mUnicode)));
       NS_ASSERTION(entry, "Error adding an entry");
       // Prefer earlier entries when we have duplication.
       if (!entry->node)
         entry->node = node;
     }
 #ifdef DEBUG
     PL_DHashMarkTableImmutable(&gUnicodeToEntity);
     PL_DHashMarkTableImmutable(&gEntityToUnicode);
--- a/rdf/base/nsInMemoryDataSource.cpp
+++ b/rdf/base/nsInMemoryDataSource.cpp
@@ -157,19 +157,18 @@ Assertion::Assertion(nsIRDFResource* aSo
       mNext(nullptr),
       mRefCnt(0),
       mHashEntry(true)
 {
     MOZ_COUNT_CTOR(Assertion);
 
     NS_ADDREF(mSource);
 
-    u.hash.mPropertyHash = new PLDHashTable();
-    PL_DHashTableInit(u.hash.mPropertyHash, PL_DHashGetStubOps(),
-                      sizeof(Entry));
+    u.hash.mPropertyHash =
+        PL_NewDHashTable(PL_DHashGetStubOps(), sizeof(Entry));
 }
 
 Assertion::Assertion(nsIRDFResource* aSource,
                      nsIRDFResource* aProperty,
                      nsIRDFNode* aTarget,
                      bool aTruthValue)
     : mSource(aSource),
       mNext(nullptr),
@@ -190,18 +189,17 @@ Assertion::Assertion(nsIRDFResource* aSo
     u.as.mMarked = false;
 }
 
 Assertion::~Assertion()
 {
     if (mHashEntry && u.hash.mPropertyHash) {
         PL_DHashTableEnumerate(u.hash.mPropertyHash, DeletePropertyHashEntry,
                                nullptr);
-        PL_DHashTableFinish(u.hash.mPropertyHash);
-        delete u.hash.mPropertyHash;
+        PL_DHashTableDestroy(u.hash.mPropertyHash);
         u.hash.mPropertyHash = nullptr;
     }
 
     MOZ_COUNT_DTOR(Assertion);
 #ifdef DEBUG_REFS
     --gInstanceCount;
     fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
 #endif
@@ -329,33 +327,31 @@ public:
     GetReverseArcs(nsIRDFNode* v) {
         PLDHashEntryHdr* hdr = PL_DHashTableSearch(&mReverseArcs, v);
         return hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
     }
 
     void
     SetForwardArcs(nsIRDFResource* u, Assertion* as) {
         if (as) {
-            Entry* entry = static_cast<Entry*>
-                (PL_DHashTableAdd(&mForwardArcs, u, mozilla::fallible));
+            Entry* entry = static_cast<Entry*>(PL_DHashTableAdd(&mForwardArcs, u));
             if (entry) {
                 entry->mNode = u;
                 entry->mAssertions = as;
             }
         }
         else {
             PL_DHashTableRemove(&mForwardArcs, u);
         }
     }
 
     void
     SetReverseArcs(nsIRDFNode* v, Assertion* as) {
         if (as) {
-            Entry* entry = static_cast<Entry*>
-                (PL_DHashTableAdd(&mReverseArcs, v, mozilla::fallible));
+            Entry* entry = static_cast<Entry*>(PL_DHashTableAdd(&mReverseArcs, v));
             if (entry) {
                 entry->mNode = v;
                 entry->mAssertions = as;
             }
         }
         else {
             PL_DHashTableRemove(&mReverseArcs, v);
         }
@@ -1183,18 +1179,17 @@ InMemoryDataSource::LockedAssert(nsIRDFR
             hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
         if (asRef)
         {
             as->mNext = asRef->mNext;
             asRef->mNext = as;
         }
         else
         {
-            hdr = PL_DHashTableAdd(next->u.hash.mPropertyHash, aProperty,
-                                   mozilla::fallible);
+            hdr = PL_DHashTableAdd(next->u.hash.mPropertyHash, aProperty);
             if (hdr)
             {
                 Entry* entry = static_cast<Entry*>(hdr);
                 entry->mNode = aProperty;
                 entry->mAssertions = as;
             }
         }
     }
@@ -1295,19 +1290,18 @@ InMemoryDataSource::LockedUnassert(nsIRD
             return NS_OK;
 
         as = next;
 
         if (first) {
             PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
 
             if (next && next->mNext) {
-                PLDHashEntryHdr* hdr =
-                    PL_DHashTableAdd(root->u.hash.mPropertyHash, aProperty,
-                                     mozilla::fallible);
+                PLDHashEntryHdr* hdr = PL_DHashTableAdd(root->u.hash.mPropertyHash,
+                                     aProperty);
                 if (hdr) {
                     Entry* entry = static_cast<Entry*>(hdr);
                     entry->mNode = aProperty;
                     entry->mAssertions = next->mNext;
                 }
             }
             else {
                 // If this second-level hash empties out, clean it up.
@@ -1741,18 +1735,17 @@ InMemoryDataSource::EnsureFastContainmen
 
         PLDHashEntryHdr* hdr = PL_DHashTableSearch(table, prop);
         Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
         if (val) {
             first->mNext = val->mNext;
             val->mNext = first;
         }
         else {
-            PLDHashEntryHdr* hdr = PL_DHashTableAdd(table, prop,
-                                                    mozilla::fallible);
+            PLDHashEntryHdr* hdr = PL_DHashTableAdd(table, prop);
             if (hdr) {
                 Entry* entry = static_cast<Entry*>(hdr);
                 entry->mNode = prop;
                 entry->mAssertions = first;
                 first->mNext = nullptr;
             }
         }
         first = nextRef;
--- a/rdf/base/nsRDFService.cpp
+++ b/rdf/base/nsRDFService.cpp
@@ -1157,17 +1157,17 @@ RDFServiceImpl::RegisterResource(nsIRDFR
         // it.
 
         PR_LOG(gLog, PR_LOG_DEBUG,
                ("rdfserv   replace-resource [%p] <-- [%p] %s",
                 static_cast<ResourceHashEntry *>(hdr)->mResource,
                 aResource, (const char*) uri));
     }
     else {
-        hdr = PL_DHashTableAdd(&mResources, uri, fallible);
+        hdr = PL_DHashTableAdd(&mResources, uri);
         if (! hdr)
             return NS_ERROR_OUT_OF_MEMORY;
 
         PR_LOG(gLog, PR_LOG_DEBUG,
                ("rdfserv   register-resource [%p] %s",
                 aResource, (const char*) uri));
     }
 
@@ -1394,17 +1394,17 @@ nsresult
 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral)
 {
     const char16_t* value;
     aLiteral->GetValueConst(&value);
 
     NS_ASSERTION(!PL_DHashTableSearch(&mLiterals, value),
                  "literal already registered");
 
-    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mLiterals, value, fallible);
+    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mLiterals, value);
     if (! hdr)
         return NS_ERROR_OUT_OF_MEMORY;
 
     LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
 
     // N.B., we only hold a weak reference to the literal: that
     // way, the literal can be destroyed when the last refcount
     // goes away. The single addref that the CreateLiteral() call
@@ -1446,17 +1446,17 @@ nsresult
 RDFServiceImpl::RegisterInt(nsIRDFInt* aInt)
 {
     int32_t value;
     aInt->GetValue(&value);
 
     NS_ASSERTION(!PL_DHashTableSearch(&mInts, &value),
                  "int already registered");
 
-    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mInts, &value, fallible);
+    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mInts, &value);
     if (! hdr)
         return NS_ERROR_OUT_OF_MEMORY;
 
     IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
 
     // N.B., we only hold a weak reference to the literal: that
     // way, the literal can be destroyed when the last refcount
     // goes away. The single addref that the CreateInt() call
@@ -1498,17 +1498,17 @@ nsresult
 RDFServiceImpl::RegisterDate(nsIRDFDate* aDate)
 {
     PRTime value;
     aDate->GetValue(&value);
 
     NS_ASSERTION(!PL_DHashTableSearch(&mDates, &value),
                  "date already registered");
 
-    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mDates, &value, fallible);
+    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mDates, &value);
     if (! hdr)
         return NS_ERROR_OUT_OF_MEMORY;
 
     DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
 
     // N.B., we only hold a weak reference to the literal: that
     // way, the literal can be destroyed when the last refcount
     // goes away. The single addref that the CreateDate() call
@@ -1545,17 +1545,17 @@ RDFServiceImpl::UnregisterDate(nsIRDFDat
 }
 
 nsresult
 RDFServiceImpl::RegisterBlob(BlobImpl *aBlob)
 {
     NS_ASSERTION(!PL_DHashTableSearch(&mBlobs, &aBlob->mData),
                  "blob already registered");
 
-    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mBlobs, &aBlob->mData, fallible);
+    PLDHashEntryHdr *hdr = PL_DHashTableAdd(&mBlobs, &aBlob->mData);
     if (! hdr)
         return NS_ERROR_OUT_OF_MEMORY;
 
     BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
 
     // N.B., we only hold a weak reference to the literal: that
     // way, the literal can be destroyed when the last refcount
     // goes away. The single addref that the CreateInt() call
--- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp
+++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp
@@ -857,18 +857,18 @@ nsSecureBrowserUIImpl::OnStateChange(nsI
   if (aProgressStateFlags & STATE_TRANSFERRING
       &&
       aProgressStateFlags & STATE_IS_REQUEST)
   {
     // The listing of a request in mTransferringRequests
     // means, there has already been data transfered.
 
     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
-    PL_DHashTableAdd(&mTransferringRequests, aRequest, fallible);
-
+    PL_DHashTableAdd(&mTransferringRequests, aRequest);
+    
     return NS_OK;
   }
 
   bool requestHasTransferedData = false;
 
   if (aProgressStateFlags & STATE_STOP
       &&
       aProgressStateFlags & STATE_IS_REQUEST)
--- a/security/manager/ssl/src/nsCertTree.cpp
+++ b/security/manager/ssl/src/nsCertTree.cpp
@@ -173,21 +173,24 @@ nsCertTree::nsCertTree() : mTreeArray(nu
 
 void nsCertTree::ClearCompareHash()
 {
   if (mCompareCache.IsInitialized()) {
     PL_DHashTableFinish(&mCompareCache);
   }
 }
 
-void nsCertTree::InitCompareHash()
+nsresult nsCertTree::InitCompareHash()
 {
   ClearCompareHash();
-  PL_DHashTableInit(&mCompareCache, &gMapOps,
-                    sizeof(CompareCacheHashEntryPtr), 64);
+  if (!PL_DHashTableInit(&mCompareCache, &gMapOps,
+                         sizeof(CompareCacheHashEntryPtr), fallible, 64)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return NS_OK;
 }
 
 nsCertTree::~nsCertTree()
 {
   ClearCompareHash();
   delete [] mTreeArray;
 }
 
@@ -196,18 +199,19 @@ nsCertTree::FreeCertArray()
 {
   mDispInfo.Clear();
 }
 
 CompareCacheHashEntry *
 nsCertTree::getCacheEntry(void *cache, void *aCert)
 {
   PLDHashTable &aCompareCache = *reinterpret_cast<PLDHashTable*>(cache);
-  CompareCacheHashEntryPtr *entryPtr = static_cast<CompareCacheHashEntryPtr*>
-    (PL_DHashTableAdd(&aCompareCache, aCert, fallible));
+  CompareCacheHashEntryPtr *entryPtr = 
+    static_cast<CompareCacheHashEntryPtr*>
+               (PL_DHashTableAdd(&aCompareCache, aCert));
   return entryPtr ? entryPtr->entry : nullptr;
 }
 
 void nsCertTree::RemoveCacheEntry(void *key)
 {
   PL_DHashTableRemove(&mCompareCache, key);
 }
 
@@ -654,38 +658,39 @@ NS_IMETHODIMP
 nsCertTree::LoadCertsFromCache(nsINSSCertCache *aCache, uint32_t aType)
 {
   if (mTreeArray) {
     FreeCertArray();
     delete [] mTreeArray;
     mTreeArray = nullptr;
     mNumRows = 0;
   }
-  InitCompareHash();
+  nsresult rv = InitCompareHash();
+  if (NS_FAILED(rv)) return rv;
 
-  nsresult rv =
-    GetCertsByTypeFromCache(aCache, aType, GetCompareFuncFromCertType(aType),
-                            &mCompareCache);
+  rv = GetCertsByTypeFromCache(aCache, aType, 
+                               GetCompareFuncFromCertType(aType), &mCompareCache);
   if (NS_FAILED(rv)) return rv;
   return UpdateUIContents();
 }
 
 NS_IMETHODIMP 
 nsCertTree::LoadCerts(uint32_t aType)
 {
   if (mTreeArray) {
     FreeCertArray();
     delete [] mTreeArray;
     mTreeArray = nullptr;
     mNumRows = 0;
   }
-  InitCompareHash();
+  nsresult rv = InitCompareHash();
+  if (NS_FAILED(rv)) return rv;
 
-  nsresult rv =
-    GetCertsByType(aType, GetCompareFuncFromCertType(aType), &mCompareCache);
+  rv = GetCertsByType(aType, 
+                      GetCompareFuncFromCertType(aType), &mCompareCache);
   if (NS_FAILED(rv)) return rv;
   return UpdateUIContents();
 }
 
 nsresult
 nsCertTree::UpdateUIContents()
 {
   uint32_t count = mDispInfo.Length();
--- a/security/manager/ssl/src/nsCertTree.h
+++ b/security/manager/ssl/src/nsCertTree.h
@@ -85,17 +85,17 @@ public:
   nsCertTree();
 
   enum sortCriterion { sort_IssuerOrg, sort_Org, sort_Token, 
     sort_CommonName, sort_IssuedDateDescending, sort_Email, sort_None };
 
 protected:
   virtual ~nsCertTree();
 
-  void InitCompareHash();
+  nsresult InitCompareHash();
   void ClearCompareHash();
   void RemoveCacheEntry(void *key);
 
   typedef int (*nsCertCompareFunc)(void *, nsIX509Cert *a, nsIX509Cert *b);
 
   static CompareCacheHashEntry *getCacheEntry(void *cache, void *aCert);
   static void CmpInitCriterion(nsIX509Cert *cert, CompareCacheHashEntry *entry,
                                sortCriterion crit, int32_t level);
--- a/security/manager/ssl/src/nsNSSShutDown.cpp
+++ b/security/manager/ssl/src/nsNSSShutDown.cpp
@@ -65,17 +65,17 @@ nsNSSShutDownList::~nsNSSShutDownList()
 
 void nsNSSShutDownList::remember(nsNSSShutDownObject *o)
 {
   if (!singleton)
     return;
   
   PR_ASSERT(o);
   MutexAutoLock lock(singleton->mListLock);
-  PL_DHashTableAdd(&singleton->mObjects, o, fallible);
+  PL_DHashTableAdd(&singleton->mObjects, o);
 }
 
 void nsNSSShutDownList::forget(nsNSSShutDownObject *o)
 {
   if (!singleton)
     return;
   
   PR_ASSERT(o);
@@ -85,17 +85,17 @@ void nsNSSShutDownList::forget(nsNSSShut
 
 void nsNSSShutDownList::remember(nsOnPK11LogoutCancelObject *o)
 {
   if (!singleton)
     return;
   
   PR_ASSERT(o);
   MutexAutoLock lock(singleton->mListLock);
-  PL_DHashTableAdd(&singleton->mPK11LogoutCancelObjects, o, fallible);
+  PL_DHashTableAdd(&singleton->mPK11LogoutCancelObjects, o);
 }
 
 void nsNSSShutDownList::forget(nsOnPK11LogoutCancelObject *o)
 {
   if (!singleton)
     return;
   
   PR_ASSERT(o);
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -1335,17 +1335,17 @@ nsDocLoader::RefreshAttempted(nsIWebProg
       mParent->RefreshAttempted(aWebProgress, aURI, aDelay, aSameURI);
   }
 
   return allowRefresh;
 }
 
 nsresult nsDocLoader::AddRequestInfo(nsIRequest *aRequest)
 {
-  if (!PL_DHashTableAdd(&mRequestInfoHash, aRequest, mozilla::fallible)) {
+  if (!PL_DHashTableAdd(&mRequestInfoHash, aRequest)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
 void nsDocLoader::RemoveRequestInfo(nsIRequest *aRequest)
 {
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -895,18 +895,23 @@ CCGraph::FindNode(void* aPtr)
     static_cast<PtrToNodeEntry*>(PL_DHashTableSearch(&mPtrToNodeMap, aPtr));
   return e ? e->mNode : nullptr;
 }
 
 PtrToNodeEntry*
 CCGraph::AddNodeToMap(void* aPtr)
 {
   JS::AutoSuppressGCAnalysis suppress;
-  return static_cast<PtrToNodeEntry*>
-    (PL_DHashTableAdd(&mPtrToNodeMap, aPtr)); // infallible add
+  PtrToNodeEntry* e =
+    static_cast<PtrToNodeEntry*>(PL_DHashTableAdd(&mPtrToNodeMap, aPtr));
+  if (!e) {
+    // Caller should track OOMs
+    return nullptr;
+  }
+  return e;
 }
 
 void
 CCGraph::RemoveNodeFromMap(void* aPtr)
 {
   PL_DHashTableRemove(&mPtrToNodeMap, aPtr);
 }
 
@@ -2027,16 +2032,17 @@ private:
   NodePool::Builder mNodeBuilder;
   EdgePool::Builder mEdgeBuilder;
   PtrInfo* mCurrPi;
   nsCycleCollectionParticipant* mJSParticipant;
   nsCycleCollectionParticipant* mJSZoneParticipant;
   nsCString mNextEdgeName;
   nsCOMPtr<nsICycleCollectorListener> mListener;
   bool mMergeZones;
+  bool mRanOutOfMemory;
   nsAutoPtr<NodePool::Enumerator> mCurrNode;
 
 public:
   CCGraphBuilder(CCGraph& aGraph,
                  CycleCollectorResults& aResults,
                  CycleCollectedJSRuntime* aJSRuntime,
                  nsICycleCollectorListener* aListener,
                  bool aMergeZones);
@@ -2141,16 +2147,17 @@ CCGraphBuilder::CCGraphBuilder(CCGraph& 
   : mGraph(aGraph)
   , mResults(aResults)
   , mNodeBuilder(aGraph.mNodes)
   , mEdgeBuilder(aGraph.mEdges)
   , mJSParticipant(nullptr)
   , mJSZoneParticipant(nullptr)
   , mListener(aListener)
   , mMergeZones(aMergeZones)
+  , mRanOutOfMemory(false)
 {
   if (aJSRuntime) {
     mJSParticipant = aJSRuntime->GCThingParticipant();
     mJSZoneParticipant = aJSRuntime->ZoneParticipant();
   }
 
   uint32_t flags = 0;
   if (!flags && mListener) {
@@ -2174,16 +2181,21 @@ CCGraphBuilder::CCGraphBuilder(CCGraph& 
 CCGraphBuilder::~CCGraphBuilder()
 {
 }
 
 PtrInfo*
 CCGraphBuilder::AddNode(void* aPtr, nsCycleCollectionParticipant* aParticipant)
 {
   PtrToNodeEntry* e = mGraph.AddNodeToMap(aPtr);
+  if (!e) {
+    mRanOutOfMemory = true;
+    return nullptr;
+  }
+
   PtrInfo* result;
   if (!e->mNode) {
     // New entry.
     result = mNodeBuilder.Add(aPtr, aParticipant);
     e->mNode = result;
     NS_ASSERTION(result, "mNodeBuilder.Add returned null");
   } else {
     result = e->mNode;
@@ -2254,16 +2266,21 @@ CCGraphBuilder::BuildGraph(SliceBudget& 
   if (!mCurrNode->IsDone()) {
     return false;
   }
 
   if (mGraph.mRootCount > 0) {
     SetLastChild();
   }
 
+  if (mRanOutOfMemory) {
+    MOZ_ASSERT(false, "Ran out of memory while building cycle collector graph");
+    CC_TELEMETRY(_OOM, true);
+  }
+
   mCurrNode = nullptr;
 
   return true;
 }
 
 NS_IMETHODIMP_(void)
 CCGraphBuilder::NoteXPCOMRoot(nsISupports* aRoot)
 {
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -551,28 +551,36 @@ EnsureTableExists()
 }
 
 static inline AtomTableEntry*
 GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t* aHashOut)
 {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   EnsureTableExists();
   AtomTableKey key(aString, aLength, aHashOut);
-  // This is an infallible add.
-  return static_cast<AtomTableEntry*>(PL_DHashTableAdd(&gAtomTable, &key));
+  AtomTableEntry* e = static_cast<AtomTableEntry*>(
+    PL_DHashTableAdd(&gAtomTable, &key));
+  if (!e) {
+    NS_ABORT_OOM(gAtomTable.EntryCount() * gAtomTable.EntrySize());
+  }
+  return e;
 }
 
 static inline AtomTableEntry*
 GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t* aHashOut)
 {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   EnsureTableExists();
   AtomTableKey key(aString, aLength, aHashOut);
-  // This is an infallible add.
-  return static_cast<AtomTableEntry*>(PL_DHashTableAdd(&gAtomTable, &key));
+  AtomTableEntry* e = static_cast<AtomTableEntry*>(
+    PL_DHashTableAdd(&gAtomTable, &key));
+  if (!e) {
+    NS_ABORT_OOM(gAtomTable.EntryCount() * gAtomTable.EntrySize());
+  }
+  return e;
 }
 
 class CheckStaticAtomSizes
 {
   CheckStaticAtomSizes()
   {
     static_assert((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
                    sizeof(nsStringBuffer().mRefCount)) &&
--- a/xpcom/ds/nsPersistentProperties.cpp
+++ b/xpcom/ds/nsPersistentProperties.cpp
@@ -523,17 +523,17 @@ nsPersistentProperties::Load(nsIInputStr
 
 NS_IMETHODIMP
 nsPersistentProperties::SetStringProperty(const nsACString& aKey,
                                           const nsAString& aNewValue,
                                           nsAString& aOldValue)
 {
   const nsAFlatCString&  flatKey = PromiseFlatCString(aKey);
   PropertyTableEntry* entry = static_cast<PropertyTableEntry*>(
-    PL_DHashTableAdd(&mTable, flatKey.get(), mozilla::fallible));
+    PL_DHashTableAdd(&mTable, flatKey.get()));
 
   if (entry->mKey) {
     aOldValue = entry->mValue;
     NS_WARNING(nsPrintfCString("the property %s already exists\n",
                                flatKey.get()).get());
   } else {
     aOldValue.Truncate();
   }
--- a/xpcom/ds/nsStaticNameTable.cpp
+++ b/xpcom/ds/nsStaticNameTable.cpp
@@ -133,18 +133,21 @@ nsStaticCaseInsensitiveNameTable::Init(c
   NS_ASSERTION(aLength, "0 length");
 
   mNameArray = (nsDependentCString*)
     nsMemory::Alloc(aLength * sizeof(nsDependentCString));
   if (!mNameArray) {
     return false;
   }
 
-  PL_DHashTableInit(&mNameTable, &nametable_CaseInsensitiveHashTableOps,
-                    sizeof(NameTableEntry), aLength);
+  if (!PL_DHashTableInit(&mNameTable, &nametable_CaseInsensitiveHashTableOps,
+                         sizeof(NameTableEntry), fallible,
+                         aLength)) {
+    return false;
+  }
 
   for (int32_t index = 0; index < aLength; ++index) {
     const char* raw = aNames[index];
 #ifdef DEBUG
     {
       // verify invariants of contents
       nsAutoCString temp1(raw);
       nsDependentCString temp2(raw);
@@ -156,18 +159,18 @@ nsStaticCaseInsensitiveNameTable::Init(c
     }
 #endif
     // use placement-new to initialize the string object
     nsDependentCString* strPtr = &mNameArray[index];
     new (strPtr) nsDependentCString(raw);
 
     NameTableKey key(strPtr);
 
-    NameTableEntry* entry = static_cast<NameTableEntry*>
-      (PL_DHashTableAdd(&mNameTable, &key, fallible));
+    NameTableEntry* entry =
+      static_cast<NameTableEntry*>(PL_DHashTableAdd(&mNameTable, &key));
     if (!entry) {
       continue;
     }
 
     NS_ASSERTION(entry->mString == 0, "Entry already exists!");
 
     entry->mString = strPtr;      // not owned!
     entry->mIndex = index;
--- a/xpcom/glue/nsTHashtable.h
+++ b/xpcom/glue/nsTHashtable.h
@@ -144,31 +144,29 @@ public:
   /**
    * Get the entry associated with a key, or create a new entry,
    * @param     aKey the key to retrieve
    * @return    pointer to the entry class retreived; nullptr only if memory
                 can't be allocated
    */
   EntryType* PutEntry(KeyType aKey)
   {
+    EntryType* e = PutEntry(aKey, mozilla::fallible);
+    if (!e) {
+      NS_ABORT_OOM(mTable.EntrySize() * mTable.EntryCount());
+    }
+    return e;
+  }
+
+  EntryType* PutEntry(KeyType aKey, const fallible_t&) NS_WARN_UNUSED_RESULT {
     NS_ASSERTION(mTable.IsInitialized(),
                  "nsTHashtable was not initialized properly.");
 
-    return static_cast<EntryType*>  // infallible add
-      (PL_DHashTableAdd(&mTable, EntryType::KeyToPointer(aKey)));
-  }
-
-  EntryType* PutEntry(KeyType aKey, const fallible_t&) NS_WARN_UNUSED_RESULT
-  {
-    NS_ASSERTION(mTable.IsInitialized(),
-                 "nsTHashtable was not initialized properly.");
-
-    return static_cast<EntryType*>
-      (PL_DHashTableAdd(&mTable, EntryType::KeyToPointer(aKey),
-                        mozilla::fallible));
+    return static_cast<EntryType*>(PL_DHashTableAdd(
+      &mTable, EntryType::KeyToPointer(aKey)));
   }
 
   /**
    * Remove the entry associated with a key.
    * @param     aKey of the entry to remove
    */
   void RemoveEntry(KeyType aKey)
   {
--- a/xpcom/glue/pldhash.cpp
+++ b/xpcom/glue/pldhash.cpp
@@ -162,16 +162,39 @@ PL_DHashGetStubOps(void)
 static bool
 SizeOfEntryStore(uint32_t aCapacity, uint32_t aEntrySize, uint32_t* aNbytes)
 {
   uint64_t nbytes64 = uint64_t(aCapacity) * uint64_t(aEntrySize);
   *aNbytes = aCapacity * aEntrySize;
   return uint64_t(*aNbytes) == nbytes64;   // returns false on overflow
 }
 
+PLDHashTable*
+PL_NewDHashTable(const PLDHashTableOps* aOps, uint32_t aEntrySize,
+                 uint32_t aLength)
+{
+  PLDHashTable* table = (PLDHashTable*)malloc(sizeof(*table));
+
+  if (!table) {
+    return nullptr;
+  }
+  if (!PL_DHashTableInit(table, aOps, aEntrySize, fallible, aLength)) {
+    free(table);
+    return nullptr;
+  }
+  return table;
+}
+
+void
+PL_DHashTableDestroy(PLDHashTable* aTable)
+{
+  PL_DHashTableFinish(aTable);
+  free(aTable);
+}
+
 /*
  * Compute max and min load numbers (entry counts).  We have a secondary max
  * that allows us to overload a table reasonably if it cannot be grown further
  * (i.e. if ChangeTable() fails).  The table slows down drastically if the
  * secondary max is too close to 1, but 0.96875 gives only a slight slowdown
  * while allowing 1.3x more elements.
  */
 static inline uint32_t
@@ -191,59 +214,83 @@ MinLoad(uint32_t aCapacity)
 }
 
 static inline uint32_t
 MinCapacity(uint32_t aLength)
 {
   return (aLength * 4 + (3 - 1)) / 3;   // == ceil(aLength * 4 / 3)
 }
 
-MOZ_ALWAYS_INLINE void
+MOZ_ALWAYS_INLINE bool
 PLDHashTable::Init(const PLDHashTableOps* aOps,
-                   uint32_t aEntrySize, uint32_t aLength)
+                   uint32_t aEntrySize, const fallible_t&, uint32_t aLength)
 {
   if (aLength > PL_DHASH_MAX_INITIAL_LENGTH) {
-    MOZ_CRASH("Initial length is too large");
+    return false;
   }
 
   // Compute the smallest capacity allowing |aLength| elements to be inserted
   // without rehashing.
   uint32_t capacity = MinCapacity(aLength);
   if (capacity < PL_DHASH_MIN_CAPACITY) {
     capacity = PL_DHASH_MIN_CAPACITY;
   }
 
   int log2 = CeilingLog2(capacity);
 
   capacity = 1u << log2;
   MOZ_ASSERT(capacity <= PL_DHASH_MAX_CAPACITY);
-  mOps = aOps;
   mHashShift = PL_DHASH_BITS - log2;
   mEntrySize = aEntrySize;
   mEntryCount = mRemovedCount = 0;
   mGeneration = 0;
   uint32_t nbytes;
   if (!SizeOfEntryStore(capacity, aEntrySize, &nbytes)) {
-    MOZ_CRASH("Initial entry store size is too large");
+    return false;  // overflowed
   }
 
-  mEntryStore = nullptr;
+  mEntryStore = (char*)malloc(nbytes);
+  if (!mEntryStore) {
+    return false;
+  }
+  memset(mEntryStore, 0, nbytes);
+  METER(memset(&mStats, 0, sizeof(mStats)));
 
-  METER(memset(&mStats, 0, sizeof(mStats)));
+  // Set this only once we reach a point where we know we can't fail.
+  mOps = aOps;
 
 #ifdef DEBUG
   mRecursionLevel = 0;
 #endif
+
+  return true;
+}
+
+bool
+PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
+                  uint32_t aEntrySize,
+                  const fallible_t& aFallible, uint32_t aLength)
+{
+  return aTable->Init(aOps, aEntrySize, aFallible, aLength);
 }
 
 void
 PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
                   uint32_t aEntrySize, uint32_t aLength)
 {
-  aTable->Init(aOps, aEntrySize, aLength);
+  if (!PL_DHashTableInit(aTable, aOps, aEntrySize, fallible, aLength)) {
+    if (aLength > PL_DHASH_MAX_INITIAL_LENGTH) {
+      MOZ_CRASH();          // the asked-for length was too big
+    }
+    uint32_t capacity = MinCapacity(aLength), nbytes;
+    if (!SizeOfEntryStore(capacity, aEntrySize, &nbytes)) {
+      MOZ_CRASH();          // the required mEntryStore size was too big
+    }
+    NS_ABORT_OOM(nbytes);   // allocation failed
+  }
 }
 
 /*
  * Double hashing needs the second hash code to be relatively prime to table
  * size, so we simply make hash2 odd.
  */
 #define HASH1(hash0, shift)         ((hash0) >> (shift))
 #define HASH2(hash0,log2,shift)     ((((hash0) << (log2)) >> (shift)) | 1)
@@ -296,17 +343,16 @@ PLDHashTable::Finish()
 
   mOps = nullptr;
 
   DECREMENT_RECURSION_LEVEL(this);
   MOZ_ASSERT(RECURSION_LEVEL_SAFE_TO_FINISH(this));
 
   /* Free entry storage last. */
   free(mEntryStore);
-  mEntryStore = nullptr;
 }
 
 void
 PL_DHashTableFinish(PLDHashTable* aTable)
 {
   aTable->Finish();
 }
 
@@ -314,17 +360,16 @@ PL_DHashTableFinish(PLDHashTable* aTable
 // previously-removed entry. If |IsAdd| is false, the return value is null on a
 // miss, and will never be a previously-removed entry on a hit. This
 // distinction is a bit grotty but this function is hot enough that these
 // differences are worthwhile.
 template <PLDHashTable::SearchReason Reason>
 PLDHashEntryHdr* PL_DHASH_FASTCALL
 PLDHashTable::SearchTable(const void* aKey, PLDHashNumber aKeyHash)
 {
-  MOZ_ASSERT(mEntryStore);
   METER(mStats.mSearches++);
   NS_ASSERTION(!(aKeyHash & COLLISION_FLAG),
                "!(aKeyHash & COLLISION_FLAG)");
 
   /* Compute the primary hash address. */
   PLDHashNumber hash1 = HASH1(aKeyHash, mHashShift);
   PLDHashEntryHdr* entry = ADDRESS_ENTRY(this, hash1);
 
@@ -395,17 +440,16 @@ PLDHashTable::SearchTable(const void* aK
  * Avoiding the need for |aKey| means we can avoid needing a way to map
  * entries to keys, which means callers can use complex key types more
  * easily.
  */
 PLDHashEntryHdr* PL_DHASH_FASTCALL
 PLDHashTable::FindFreeEntry(PLDHashNumber aKeyHash)
 {
   METER(mStats.mSearches++);
-  MOZ_ASSERT(mEntryStore);
   NS_ASSERTION(!(aKeyHash & COLLISION_FLAG),
                "!(aKeyHash & COLLISION_FLAG)");
 
   /* Compute the primary hash address. */
   PLDHashNumber hash1 = HASH1(aKeyHash, mHashShift);
   PLDHashEntryHdr* entry = ADDRESS_ENTRY(this, hash1);
 
   /* Miss: return space for a new entry. */
@@ -437,18 +481,16 @@ PLDHashTable::FindFreeEntry(PLDHashNumbe
 
   /* NOTREACHED */
   return nullptr;
 }
 
 bool
 PLDHashTable::ChangeTable(int aDeltaLog2)
 {
-  MOZ_ASSERT(mEntryStore);
-
   /* Look, but don't touch, until we succeed in getting new entry store. */
   int oldLog2 = PL_DHASH_BITS - mHashShift;
   int newLog2 = oldLog2 + aDeltaLog2;
   uint32_t newCapacity = 1u << newLog2;
   if (newCapacity > PL_DHASH_MAX_CAPACITY) {
     return false;
   }
 
@@ -514,53 +556,39 @@ PLDHashTable::ComputeKeyHash(const void*
 
 MOZ_ALWAYS_INLINE PLDHashEntryHdr*
 PLDHashTable::Search(const void* aKey)
 {
   INCREMENT_RECURSION_LEVEL(this);
 
   METER(mStats.mSearches++);
 
-  PLDHashEntryHdr* entry =
-    mEntryStore ? SearchTable<ForSearchOrRemove>(aKey, ComputeKeyHash(aKey))
-                : nullptr;
+  PLDHashNumber keyHash = ComputeKeyHash(aKey);
+  PLDHashEntryHdr* entry = SearchTable<ForSearchOrRemove>(aKey, keyHash);
 
   DECREMENT_RECURSION_LEVEL(this);
 
   return entry;
 }
 
 MOZ_ALWAYS_INLINE PLDHashEntryHdr*
-PLDHashTable::Add(const void* aKey, const mozilla::fallible_t&)
+PLDHashTable::Add(const void* aKey)
 {
   PLDHashNumber keyHash;
   PLDHashEntryHdr* entry;
-  uint32_t capacity;
 
   MOZ_ASSERT(mRecursionLevel == 0);
   INCREMENT_RECURSION_LEVEL(this);
 
-  // Allocate the entry storage if it hasn't already been allocated.
-  if (!mEntryStore) {
-    uint32_t nbytes;
-    if (!SizeOfEntryStore(CapacityFromHashShift(), mEntrySize, &nbytes) ||
-        !(mEntryStore = (char*)malloc(nbytes))) {
-      METER(mStats.mAddFailures++);
-      entry = nullptr;
-      goto exit;
-    }
-    memset(mEntryStore, 0, nbytes);
-  }
-
   /*
    * If alpha is >= .75, grow or compress the table.  If aKey is already
    * in the table, we may grow once more than necessary, but only if we
    * are on the edge of being overloaded.
    */
-  capacity = Capacity();
+  uint32_t capacity = Capacity();
   if (mEntryCount + mRemovedCount >= MaxLoad(capacity)) {
     /* Compress if a quarter or more of all entries are removed. */
     int deltaLog2;
     if (mRemovedCount >= capacity >> 2) {
       METER(mStats.mCompresses++);
       deltaLog2 = 0;
     } else {
       METER(mStats.mGrows++);
@@ -580,17 +608,17 @@ PLDHashTable::Add(const void* aKey, cons
     }
   }
 
   /*
    * Look for entry after possibly growing, so we don't have to add it,
    * then skip it while growing the table and re-add it after.
    */
   keyHash = ComputeKeyHash(aKey);
-  entry = mEntryStore ? SearchTable<ForAdd>(aKey, keyHash) : nullptr;
+  entry = SearchTable<ForAdd>(aKey, keyHash);
   if (!ENTRY_IS_LIVE(entry)) {
     /* Initialize the entry, indicating that it's no longer free. */
     METER(mStats.mAddMisses++);
     if (ENTRY_IS_REMOVED(entry)) {
       METER(mStats.mAddOverRemoved++);
       mRemovedCount--;
       keyHash |= COLLISION_FLAG;
     }
@@ -613,19 +641,18 @@ exit:
 }
 
 MOZ_ALWAYS_INLINE void
 PLDHashTable::Remove(const void* aKey)
 {
   MOZ_ASSERT(mRecursionLevel == 0);
   INCREMENT_RECURSION_LEVEL(this);
 
-  PLDHashEntryHdr* entry =
-    mEntryStore ? SearchTable<ForSearchOrRemove>(aKey, ComputeKeyHash(aKey))
-                : nullptr;
+  PLDHashNumber keyHash = ComputeKeyHash(aKey);
+  PLDHashEntryHdr* entry = SearchTable<ForSearchOrRemove>(aKey, keyHash);
   if (entry) {
     /* Clear this entry and mark it as "removed". */
     METER(mStats.mRemoveHits++);
     PL_DHashTableRawRemove(this, entry);
 
     /* Shrink if alpha is <= .25 and the table isn't too small already. */
     uint32_t capacity = Capacity();
     if (capacity > PL_DHASH_MIN_CAPACITY &&
@@ -643,33 +670,19 @@ PLDHashTable::Remove(const void* aKey)
 
 PLDHashEntryHdr* PL_DHASH_FASTCALL
 PL_DHashTableSearch(PLDHashTable* aTable, const void* aKey)
 {
   return aTable->Search(aKey);
 }
 
 PLDHashEntryHdr* PL_DHASH_FASTCALL
-PL_DHashTableAdd(PLDHashTable* aTable, const void* aKey,
-                 const fallible_t& aFallible)
-{
-  return aTable->Add(aKey, aFallible);
-}
-
-PLDHashEntryHdr* PL_DHASH_FASTCALL
 PL_DHashTableAdd(PLDHashTable* aTable, const void* aKey)
 {
-  PLDHashEntryHdr* entry = PL_DHashTableAdd(aTable, aKey, fallible);
-  if (!entry) {
-    // There are two ways the Add could fail: (a) a entry storage reallocation
-    // failed, or (b) mOps->initEntry failed. The number we're reporting here
-    // is the one for case (a), which is the more likely of the two.
-    NS_ABORT_OOM(aTable->EntrySize() * aTable->EntryCount());
-  }
-  return entry;
+  return aTable->Add(aKey);
 }
 
 void PL_DHASH_FASTCALL
 PL_DHashTableRemove(PLDHashTable* aTable, const void* aKey)
 {
   aTable->Remove(aKey);
 }
 
@@ -718,17 +731,16 @@ PLDHashTable::Enumerate(PLDHashEnumerato
     // even more chaotic to iterate in fully random order, but that's a lot
     // more work.
     entryAddr += ChaosMode::randomUint32LessThan(capacity) * mEntrySize;
     if (entryAddr >= entryLimit) {
       entryAddr -= tableSize;
     }
   }
 
-  MOZ_ASSERT_IF(capacity > 0, mEntryStore);
   for (uint32_t e = 0; e < capacity; ++e) {
     PLDHashEntryHdr* entry = (PLDHashEntryHdr*)entryAddr;
     if (ENTRY_IS_LIVE(entry)) {
       PLDHashOperator op = aEtor(this, entry, i++, aArg);
       if (op & PL_DHASH_REMOVE) {
         METER(mStats.mRemoveEnums++);
         PL_DHashTableRawRemove(this, entry);
         didRemove = true;
@@ -798,20 +810,16 @@ SizeOfEntryExcludingThisEnumerator(PLDHa
   return PL_DHASH_NEXT;
 }
 
 MOZ_ALWAYS_INLINE size_t
 PLDHashTable::SizeOfExcludingThis(
     PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
     MallocSizeOf aMallocSizeOf, void* aArg /* = nullptr */) const
 {
-  if (!mEntryStore) {
-    return 0;
-  }
-
   size_t n = 0;
   n += aMallocSizeOf(mEntryStore);
   if (aSizeOfEntryExcludingThis) {
     SizeOfEntryExcludingThisArg arg2 = {
       0, aSizeOfEntryExcludingThis, aMallocSizeOf, aArg
     };
     PL_DHashTableEnumerate(const_cast<PLDHashTable*>(this),
                            SizeOfEntryExcludingThisEnumerator, &arg2);
@@ -914,17 +922,16 @@ PLDHashEntryHdr* PLDHashTable::Iterator:
   char* entryLimit = mEntryAddr + tableSize;
 
   // Strictly speaking, we don't need to iterate over the full capacity each
   // time. However, it is simpler to do so rather than unnecessarily track the
   // current number of entries checked as opposed to only live entries. If debug
   // checks pass, then this method will only iterate through the full capacity
   // once. If they fail, then this loop may end up returning the early entries
   // more than once.
-  MOZ_ASSERT_IF(capacity > 0, mTable->mEntryStore);
   for (uint32_t e = 0; e < capacity; ++e) {
     PLDHashEntryHdr* entry = (PLDHashEntryHdr*)mEntryAddr;
 
     // Increment the count before returning so we don't keep returning the same
     // address. This may wrap around if ChaosMode is enabled.
     mEntryAddr += mTable->mEntrySize;
     if (mEntryAddr >= entryLimit) {
       mEntryAddr -= tableSize;
@@ -968,17 +975,16 @@ PLDHashTable::DumpMeter(PLDHashEnumerato
   char* entryAddr = mEntryStore;
   int sizeLog2 = PL_DHASH_BITS - mHashShift;
   uint32_t capacity = Capacity();
   uint32_t sizeMask = (1u << sizeLog2) - 1;
   uint32_t chainCount = 0, maxChainLen = 0;
   hash2 = 0;
   sqsum = 0;
 
-  MOZ_ASSERT_IF(capacity > 0, mEntryStore);
   for (uint32_t i = 0; i < capacity; i++) {
     entry = (PLDHashEntryHdr*)entryAddr;
     entryAddr += mEntrySize;
     if (!ENTRY_IS_LIVE(entry)) {
       continue;
     }
     hash1 = HASH1(entry->mKeyHash & ~COLLISION_FLAG, mHashShift);
     PLDHashNumber saveHash1 = hash1;
--- a/xpcom/glue/pldhash.h
+++ b/xpcom/glue/pldhash.h
@@ -142,19 +142,16 @@ typedef PLDHashOperator (*PLDHashEnumera
 typedef size_t (*PLDHashSizeOfEntryExcludingThisFun)(
   PLDHashEntryHdr* aHdr, mozilla::MallocSizeOf aMallocSizeOf, void* aArg);
 
 /*
  * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead)
  * on most architectures, and may be allocated on the stack or within another
  * structure or class (see below for the Init and Finish functions to use).
  *
- * No entry storage is allocated until the first element is added. This means
- * that empty hash tables are cheap, which is good because they are common.
- *
  * There used to be a long, math-heavy comment here about the merits of
  * double hashing vs. chaining; it was removed in bug 1058335. In short, double
  * hashing is more space-efficient unless the element size gets large (in which
  * case you should keep using double hashing but switch to using pointer
  * elements). Also, with double hashing, you can't safely hold an entry pointer
  * and use it after an ADD or REMOVE operation, unless you sample
  * aTable->mGeneration before adding or removing, and compare the sample after,
  * dereferencing the entry pointer only if aTable->mGeneration has not changed.
@@ -173,17 +170,18 @@ private:
    */
 protected:
   mutable uint16_t    mRecursionLevel;/* used to detect unsafe re-entry */
 private:
   uint32_t            mEntrySize;     /* number of bytes in an entry */
   uint32_t            mEntryCount;    /* number of entries in table */
   uint32_t            mRemovedCount;  /* removed entry sentinels in table */
   uint32_t            mGeneration;    /* entry storage generation number */
-  char*               mEntryStore;    /* entry storage; allocated lazily */
+  char*               mEntryStore;    /* entry storage */
+
 #ifdef PL_DHASHMETER
   struct PLDHashStats
   {
     uint32_t        mSearches;      /* total number of table searches */
     uint32_t        mSteps;         /* hash chain links traversed */
     uint32_t        mHits;          /* searches that found key */
     uint32_t        mMisses;        /* searches that didn't find key */
     uint32_t        mSearches;      /* number of Search() calls */
@@ -223,34 +221,35 @@ public:
   bool IsInitialized() const { return !!mOps; }
 
   // These should be used rarely.
   const PLDHashTableOps* const Ops() { return mOps; }
   void SetOps(const PLDHashTableOps* aOps) { mOps = aOps; }
 
   /*
    * Size in entries (gross, not net of free and removed sentinels) for table.
-   * This can be zero if no elements have been added yet, in which case the
-   * entry storage will not have yet been allocated.
+   * We store mHashShift rather than sizeLog2 to optimize the collision-free
+   * case in SearchTable.
    */
   uint32_t Capacity() const
   {
-    return mEntryStore ? CapacityFromHashShift() : 0;
+    return ((uint32_t)1 << (PL_DHASH_BITS - mHashShift));
   }
 
   uint32_t EntrySize()  const { return mEntrySize; }
   uint32_t EntryCount() const { return mEntryCount; }
   uint32_t Generation() const { return mGeneration; }
 
-  void Init(const PLDHashTableOps* aOps, uint32_t aEntrySize, uint32_t aLength);
+  bool Init(const PLDHashTableOps* aOps, uint32_t aEntrySize,
+            const mozilla::fallible_t&, uint32_t aLength);
 
   void Finish();
 
   PLDHashEntryHdr* Search(const void* aKey);
-  PLDHashEntryHdr* Add(const void* aKey, const mozilla::fallible_t&);
+  PLDHashEntryHdr* Add(const void* aKey);
   void Remove(const void* aKey);
 
   void RawRemove(PLDHashEntryHdr* aEntry);
 
   uint32_t Enumerate(PLDHashEnumerator aEtor, void* aArg);
 
   size_t SizeOfIncludingThis(
     PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
@@ -293,23 +292,16 @@ public:
     uint32_t mEntryOffset;            /* The number of the elements returned */
   };
 
   Iterator Iterate() const { return Iterator(this); }
 
 private:
   static bool EntryIsFree(PLDHashEntryHdr* aEntry);
 
-  // We store mHashShift rather than sizeLog2 to optimize the collision-free
-  // case in SearchTable.
-  uint32_t CapacityFromHashShift() const
-  {
-    return ((uint32_t)1 << (PL_DHASH_BITS - mHashShift));
-  }
-
   PLDHashNumber ComputeKeyHash(const void* aKey);
 
   enum SearchReason { ForSearchOrRemove, ForAdd };
 
   template <SearchReason Reason>
   PLDHashEntryHdr* PL_DHASH_FASTCALL
     SearchTable(const void* aKey, PLDHashNumber aKeyHash);
 
@@ -429,32 +421,55 @@ void PL_DHashFreeStringKey(PLDHashTable*
 /*
  * If you use PLDHashEntryStub or a subclass of it as your entry struct, and
  * if your entries move via memcpy and clear via memset(0), you can use these
  * stub operations.
  */
 const PLDHashTableOps* PL_DHashGetStubOps(void);
 
 /*
- * Initialize aTable with aOps and aEntrySize. The table's initial capacity
- * will be chosen such that |aLength| elements can be inserted without
- * rehashing; if |aLength| is a power-of-two, this capacity will be |2*length|.
- * However, because entry storage is allocated lazily, this initial capacity
- * won't be relevant until the first element is added; prior to that the
- * capacity will be zero.
+ * Dynamically allocate a new PLDHashTable, initialize it using
+ * PL_DHashTableInit, and return its address. Return null on allocation failure.
+ */
+PLDHashTable* PL_NewDHashTable(
+  const PLDHashTableOps* aOps, uint32_t aEntrySize,
+  uint32_t aLength = PL_DHASH_DEFAULT_INITIAL_LENGTH);
+
+/*
+ * Free |aTable|'s entry storage and |aTable| itself (both via
+ * aTable->mOps->freeTable). Use this function to destroy a PLDHashTable that
+ * was allocated on the heap via PL_NewDHashTable().
+ */
+void PL_DHashTableDestroy(PLDHashTable* aTable);
+
+/*
+ * Initialize aTable with aOps, aEntrySize, and aCapacity. The table's initial
+ * capacity will be chosen such that |aLength| elements can be inserted without
+ * rehashing. If |aLength| is a power-of-two, this capacity will be |2*length|.
  *
- * This function will crash if |aEntrySize| and/or |aLength| are too large.
+ * This function will crash if it can't allocate enough memory, or if
+ * |aEntrySize| and/or |aLength| are too large.
  */
 void PL_DHashTableInit(
   PLDHashTable* aTable, const PLDHashTableOps* aOps,
   uint32_t aEntrySize, uint32_t aLength = PL_DHASH_DEFAULT_INITIAL_LENGTH);
 
 /*
- * Clear |aTable|'s elements (via aTable->mOps->clearEntry) and free its entry
- * storage, if has any.
+ * Initialize aTable. This is the same as PL_DHashTableInit, except that it
+ * returns a boolean indicating success, rather than crashing on failure.
+ */
+MOZ_WARN_UNUSED_RESULT bool PL_DHashTableInit(
+  PLDHashTable* aTable, const PLDHashTableOps* aOps,
+  uint32_t aEntrySize, const mozilla::fallible_t&,
+  uint32_t aLength = PL_DHASH_DEFAULT_INITIAL_LENGTH);
+
+/*
+ * Free |aTable|'s entry storage (via aTable->mOps->freeTable). Use this
+ * function to destroy a PLDHashTable that is allocated on the stack or in
+ * static memory and was created via PL_DHashTableInit().
  */
 void PL_DHashTableFinish(PLDHashTable* aTable);
 
 /*
  * To search for a key in |table|, call:
  *
  *  entry = PL_DHashTableSearch(table, key);
  *
@@ -462,38 +477,30 @@ void PL_DHashTableFinish(PLDHashTable* a
  * found.
  */
 PLDHashEntryHdr* PL_DHASH_FASTCALL
 PL_DHashTableSearch(PLDHashTable* aTable, const void* aKey);
 
 /*
  * To add an entry identified by key to table, call:
  *
- *  entry = PL_DHashTableAdd(table, key, mozilla::fallible);
+ *  entry = PL_DHashTableAdd(table, key);
  *
  * If entry is null upon return, then either (a) the table is severely
  * overloaded and memory can't be allocated for entry storage, or (b)
  * aTable->mOps->initEntry is non-null and aTable->mOps->initEntry op has
  * returned false.
  *
  * Otherwise, aEntry->mKeyHash has been set so that
  * PLDHashTable::EntryIsFree(entry) is false, and it is up to the caller to
  * initialize the key and value parts of the entry sub-type, if they have not
  * been set already (i.e. if entry was not already in the table, and if the
  * optional initEntry hook was not used).
  */
 PLDHashEntryHdr* PL_DHASH_FASTCALL
-PL_DHashTableAdd(PLDHashTable* aTable, const void* aKey,
-                 const mozilla::fallible_t&);
-
-/*
- * This is like the other PL_DHashTableAdd() function, but infallible, and so
- * never returns null.
- */
-PLDHashEntryHdr* PL_DHASH_FASTCALL
 PL_DHashTableAdd(PLDHashTable* aTable, const void* aKey);
 
 /*
  * To remove an entry identified by key from table, call:
  *
  *  PL_DHashTableRemove(table, key);
  *
  * If key's entry is found, it is cleared (via table->mOps->clearEntry) and
--- a/xpcom/tests/TestPLDHash.cpp
+++ b/xpcom/tests/TestPLDHash.cpp
@@ -2,117 +2,111 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <stdio.h>
 #include "pldhash.h"
 
-// This test mostly focuses on edge cases. But more coverage of normal
-// operations wouldn't be a bad thing.
+// pldhash is very widely used and so any basic bugs in it are likely to be
+// exposed through normal usage.  Therefore, this test currently focusses on
+// extreme cases relating to maximum table capacity and potential overflows,
+// which are unlikely to be hit during normal execution.
 
 namespace TestPLDHash {
 
 static bool test_pldhash_Init_capacity_ok()
 {
   PLDHashTable t;
 
   // Check that the constructor nulls |ops|.
   if (t.IsInitialized()) {
     return false;
   }
 
   // Try the largest allowed capacity.  With PL_DHASH_MAX_CAPACITY==1<<26, this
-  // would allocate (if we added an element) 0.5GB of entry store on 32-bit
-  // platforms and 1GB on 64-bit platforms.
-  //
-  // Ideally we'd also try (a) a too-large capacity, and (b) a large capacity
-  // combined with a large entry size that when multipled overflow. But those
-  // cases would cause the test to abort immediately.
-  //
-  // Furthermore, ideally we'd also try a large-but-ok capacity that almost but
-  // doesn't quite overflow, but that would result in allocating just under 4GB
-  // of entry storage.  That's very likely to fail on 32-bit platforms, so such
-  // a test wouldn't be reliable.
-  //
-  PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
-                    PL_DHASH_MAX_INITIAL_LENGTH);
+  // will allocate 0.5GB of entry store on 32-bit platforms and 1GB on 64-bit
+  // platforms.
+  if (!PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(PLDHashEntryStub),
+                         mozilla::fallible, PL_DHASH_MAX_INITIAL_LENGTH)) {
+    return false;
+  }
 
   // Check that Init() sets |ops|.
   if (!t.IsInitialized()) {
     return false;
   }
 
   // Check that Finish() nulls |ops|.
   PL_DHashTableFinish(&t);
   if (t.IsInitialized()) {
     return false;
   }
 
   return true;
 }
 
-static bool test_pldhash_lazy_storage()
+static bool test_pldhash_Init_capacity_too_large()
 {
   PLDHashTable t;
-  PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(PLDHashEntryStub));
 
-  // PLDHashTable allocates entry storage lazily. Check that all the non-add
-  // operations work appropriately when the table is empty and the storage
-  // hasn't yet been allocated.
-
-  if (!t.IsInitialized()) {
+  // Check that the constructor nulls |ops|.
+  if (t.IsInitialized()) {
     return false;
   }
 
-  if (t.Capacity() != 0) {
-    return false;
-  }
-
-  if (t.EntrySize() != sizeof(PLDHashEntryStub)) {
-    return false;
+  // Try the smallest too-large capacity.
+  if (PL_DHashTableInit(&t, PL_DHashGetStubOps(),
+                        sizeof(PLDHashEntryStub),
+                        mozilla::fallible,
+                        PL_DHASH_MAX_INITIAL_LENGTH + 1)) {
+    return false;   // it succeeded!?
   }
+  // Don't call PL_DHashTableFinish() here; it's not safe after Init() failure.
 
-  if (t.EntryCount() != 0) {
-    return false;
-  }
-
-  if (t.Generation() != 0) {
+  // Check that |ops| is still null.
+  if (t.IsInitialized()) {
     return false;
   }
 
-  if (PL_DHashTableSearch(&t, (const void*)1)) {
-    return false;   // search succeeded?
-  }
+  return true;
+}
 
-  // No result to check here, but call it to make sure it doesn't crash.
-  PL_DHashTableRemove(&t, (const void*)2);
+static bool test_pldhash_Init_overflow()
+{
+  PLDHashTable t;
 
-  // Using a null |enumerator| should be fine because it shouldn't be called
-  // for an empty table.
-  PLDHashEnumerator enumerator = nullptr;
-  if (PL_DHashTableEnumerate(&t, enumerator, nullptr) != 0) {
-    return false;   // enumeration count is non-zero?
+  // Check that the constructor nulls |ops|.
+  if (t.IsInitialized()) {
+    return false;
   }
 
-  for (PLDHashTable::Iterator iter = t.Iterate();
-       iter.HasMoreEntries();
-       iter.NextEntry()) {
-    return false; // shouldn't hit this on an empty table
-  }
+  // Try an acceptable capacity, but one whose byte size overflows uint32_t.
+  //
+  // Ideally we'd also try a large-but-ok capacity that almost but doesn't
+  // quite overflow, but that would result in allocating just under 4GB of
+  // entry storage.  That's very likely to fail on 32-bit platforms, so such a
+  // test wouldn't be reliable.
 
-  // Using a null |mallocSizeOf| should be fine because it shouldn't be called
-  // for an empty table.
-  mozilla::MallocSizeOf mallocSizeOf = nullptr;
-  if (PL_DHashTableSizeOfExcludingThis(&t, nullptr, mallocSizeOf) != 0) {
-    return false;   // size is non-zero?
+  struct OneKBEntry {
+      PLDHashEntryHdr hdr;
+      char buf[1024 - sizeof(PLDHashEntryHdr)];
+  };
+
+  if (PL_DHashTableInit(&t, PL_DHashGetStubOps(), sizeof(OneKBEntry),
+                        mozilla::fallible, PL_DHASH_MAX_INITIAL_LENGTH)) {
+    return false;   // it succeeded!?
   }
+  // Don't call PL_DHashTableFinish() here; it's not safe after Init() failure.
 
-  PL_DHashTableFinish(&t);
+  // Check that |ops| is still null.
+  if (t.IsInitialized()) {
+    return false;
+  }
 
   return true;
 }
 
 // See bug 931062, we skip this test on Android due to OOM.
 #ifndef MOZ_WIDGET_ANDROID
 // We insert the integers 0.., so this is has function is (a) as simple as
 // possible, and (b) collision-free.  Both of which are good, because we want
@@ -128,51 +122,57 @@ static bool test_pldhash_grow_to_max_cap
   static const PLDHashTableOps ops = {
     hash,
     PL_DHashMatchEntryStub,
     PL_DHashMoveEntryStub,
     PL_DHashClearEntryStub,
     nullptr
   };
 
-  PLDHashTable t;
-  PL_DHashTableInit(&t, &ops, sizeof(PLDHashEntryStub), 128);
+  // This is infallible.
+  PLDHashTable* t = PL_NewDHashTable(&ops, sizeof(PLDHashEntryStub), 128);
+
+  // Check that New() sets |t->ops|.
+  if (!t->IsInitialized()) {
+    return false;
+  }
 
   // Keep inserting elements until failure occurs because the table is full.
   size_t numInserted = 0;
   while (true) {
-    if (!PL_DHashTableAdd(&t, (const void*)numInserted, mozilla::fallible)) {
+    if (!PL_DHashTableAdd(t, (const void*)numInserted)) {
       break;
     }
     numInserted++;
   }
 
   // We stop when the element count is 96.875% of PL_DHASH_MAX_SIZE (see
   // MaxLoadOnGrowthFailure()).
   if (numInserted != PL_DHASH_MAX_CAPACITY - (PL_DHASH_MAX_CAPACITY >> 5)) {
     return false;
   }
 
-  PL_DHashTableFinish(&t);
+  PL_DHashTableDestroy(t);
 
   return true;
 }
 #endif
 
 //----
 
 typedef bool (*TestFunc)();
 #define DECL_TEST(name) { #name, name }
 
 static const struct Test {
   const char* name;
   TestFunc    func;
 } tests[] = {
   DECL_TEST(test_pldhash_Init_capacity_ok),
-  DECL_TEST(test_pldhash_lazy_storage),
+  DECL_TEST(test_pldhash_Init_capacity_too_large),
+  DECL_TEST(test_pldhash_Init_overflow),
 // See bug 931062, we skip this test on Android due to OOM.
 #ifndef MOZ_WIDGET_ANDROID
   DECL_TEST(test_pldhash_grow_to_max_capacity),
 #endif
   { nullptr, nullptr }
 };
 
 } // namespace TestPLDHash