author | Nicholas Nethercote <nnethercote@mozilla.com> |
Tue, 10 Feb 2015 14:39:49 -0800 | |
changeset 228575 | a4cf56d0e98ff7059ba78e8fdb34f8494cd01186 |
parent 228574 | 516285b8e2d9a1d1abdf8580cb3b9d8c5d6c5094 |
child 228576 | 09b002eaa381c992fa255074d482286a7a935681 |
push id | 28264 |
push user | cbook@mozilla.com |
push date | Wed, 11 Feb 2015 13:58:35 +0000 |
treeherder | mozilla-central@38058cb42a0e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1050035 |
milestone | 38.0a1 |
backs out | 2fcef6b54be7ec818a20f3f8039ebc09cefd77a4 2be07829fefc3e28a8fb8a1de18a04fc2a2d5ba7 66dfe37b8532cd188b528527e06086f3126d1259 df3fcd2be8fda0166301cab6d83087b24e1e9124 0a436bce77a6695f0b5a600b726cd3693c000213 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- 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