Bug 1057912 - Privatize most of PLDHashTable's fields. r=roc.

--HG--
extra : rebase_source : 0f55e70b63d9c191fbd9418cb1177ff534deeed9
This commit is contained in:
Nicholas Nethercote 2014-08-25 16:56:33 -07:00
Родитель 7d82bae00d
Коммит df1c26a45e
26 изменённых файлов: 452 добавлений и 343 удалений

Просмотреть файл

@ -993,7 +993,7 @@ nsContentList::RemoveFromHashtable()
&key,
PL_DHASH_REMOVE);
if (gContentListHashTable.entryCount == 0) {
if (gContentListHashTable.EntryCount() == 0) {
PL_DHashTableFinish(&gContentListHashTable);
gContentListHashTable.ops = nullptr;
}
@ -1036,7 +1036,7 @@ nsCacheableFuncStringContentList::RemoveFromFuncStringHashtable()
&key,
PL_DHASH_REMOVE);
if (gFuncStringContentListHashTable.entryCount == 0) {
if (gFuncStringContentListHashTable.EntryCount() == 0) {
PL_DHashTableFinish(&gFuncStringContentListHashTable);
gFuncStringContentListHashTable.ops = nullptr;
}

Просмотреть файл

@ -1781,7 +1781,7 @@ nsContentUtils::Shutdown()
sUserDefinedEvents = nullptr;
if (sEventListenerManagersHash.ops) {
NS_ASSERTION(sEventListenerManagersHash.entryCount == 0,
NS_ASSERTION(sEventListenerManagersHash.EntryCount() == 0,
"Event listener manager hash not empty at shutdown!");
// See comment above.
@ -1793,7 +1793,7 @@ nsContentUtils::Shutdown()
// it could leave dangling references in DOMClassInfo's preserved
// wrapper table.
if (sEventListenerManagersHash.entryCount == 0) {
if (sEventListenerManagersHash.EntryCount() == 0) {
PL_DHashTableFinish(&sEventListenerManagersHash);
sEventListenerManagersHash.ops = nullptr;
}

Просмотреть файл

@ -274,7 +274,7 @@ OnWrapperDestroyed()
}
if (sNPObjWrappers.ops) {
MOZ_ASSERT(sNPObjWrappers.entryCount == 0);
MOZ_ASSERT(sNPObjWrappers.EntryCount() == 0);
// No more wrappers, and our hash was initialized. Finish the
// hash to prevent leaking it.
@ -1763,14 +1763,14 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj)
entry->mNPObj = npobj;
entry->mNpp = npp;
uint32_t generation = sNPObjWrappers.generation;
uint32_t generation = sNPObjWrappers.Generation();
// No existing JSObject, create one.
JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, &sNPObjectJSWrapperClass, JS::NullPtr(),
JS::NullPtr()));
if (generation != sNPObjWrappers.generation) {
if (generation != sNPObjWrappers.Generation()) {
// Reload entry if the JS_NewObject call caused a GC and reallocated
// the table (see bug 445229). This is guaranteed to succeed.

Просмотреть файл

@ -485,7 +485,7 @@ void
IID2ThisTranslatorMap::Entry::Clear(PLDHashTable *table, PLDHashEntryHdr *entry)
{
static_cast<Entry*>(entry)->value = nullptr;
memset(entry, 0, table->entrySize);
memset(entry, 0, table->EntrySize());
}
const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps =

Просмотреть файл

@ -147,7 +147,7 @@ public:
PL_DHashTableOperate(mTable, wrapper->GetIdentityObject(), PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -209,7 +209,7 @@ public:
PL_DHashTableOperate(mTable, &clazz->GetIID(), PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -266,7 +266,7 @@ public:
PL_DHashTableOperate(mTable, iface->GetIID(), PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -325,7 +325,7 @@ public:
PL_DHashTableOperate(mTable, info, PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -385,7 +385,7 @@ public:
PL_DHashTableOperate(mTable, info, PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -458,7 +458,7 @@ public:
PL_DHashTableOperate(mTable, &key, PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -525,7 +525,7 @@ public:
PL_DHashTableOperate(mTable, &iid, PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -562,7 +562,7 @@ public:
bool GetNewOrUsed(uint32_t flags, char* name, uint32_t interfacesBitmap,
XPCNativeScriptableInfo* si);
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}
@ -600,7 +600,7 @@ public:
PL_DHashTableOperate(mTable, proto, PL_DHASH_REMOVE);
}
inline uint32_t Count() {return mTable->entryCount;}
inline uint32_t Count() { return mTable->EntryCount(); }
inline uint32_t Enumerate(PLDHashEnumerator f, void *arg)
{return PL_DHashTableEnumerate(mTable, f, arg);}

Просмотреть файл

@ -2550,7 +2550,7 @@ nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData)
{
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
if (cascade && cascade->mAnonBoxRules.entryCount) {
if (cascade && cascade->mAnonBoxRules.EntryCount()) {
RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>
(PL_DHashTableOperate(&cascade->mAnonBoxRules, aData->mPseudoTag,
PL_DHASH_LOOKUP));
@ -2571,7 +2571,7 @@ nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
{
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
if (cascade && cascade->mXULTreeRules.entryCount) {
if (cascade && cascade->mXULTreeRules.EntryCount()) {
RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>
(PL_DHashTableOperate(&cascade->mXULTreeRules, aData->mPseudoTag,
PL_DHASH_LOOKUP));
@ -3509,7 +3509,7 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
}
// Sort the hash table of per-weight linked lists by weight.
uint32_t weightCount = data.mRulesByWeight.entryCount;
uint32_t weightCount = data.mRulesByWeight.EntryCount();
nsAutoArrayPtr<PerWeightData> weightArray(new PerWeightData[weightCount]);
FillWeightArrayData fwData(weightArray);
PL_DHashTableEnumerate(&data.mRulesByWeight, FillWeightArray, &fwData);

Просмотреть файл

@ -500,12 +500,12 @@ nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes* aMapped)
NS_ASSERTION(mMappedAttrTable.ops, "table uninitialized");
#ifdef DEBUG
uint32_t entryCount = mMappedAttrTable.entryCount - 1;
uint32_t entryCount = mMappedAttrTable.EntryCount() - 1;
#endif
PL_DHashTableOperate(&mMappedAttrTable, aMapped, PL_DHASH_REMOVE);
NS_ASSERTION(entryCount == mMappedAttrTable.entryCount, "not removed");
NS_ASSERTION(entryCount == mMappedAttrTable.EntryCount(), "not removed");
}
nsIStyleRule*

Просмотреть файл

@ -9005,9 +9005,9 @@ nsRuleNode::SweepChildren(nsTArray<nsRuleNode*>& aSweepQueue)
nsRuleNode* survivorsWithChildren = nullptr;
if (ChildrenAreHashed()) {
PLDHashTable* children = ChildrenHash();
uint32_t oldChildCount = children->entryCount;
uint32_t oldChildCount = children->EntryCount();
PL_DHashTableEnumerate(children, SweepHashEntry, &survivorsWithChildren);
childrenDestroyed = oldChildCount - children->entryCount;
childrenDestroyed = oldChildCount - children->EntryCount();
if (childrenDestroyed == oldChildCount) {
PL_DHashTableDestroy(children);
mChildren.asVoid = nullptr;

Просмотреть файл

@ -153,20 +153,20 @@ SpanningCellSorter::GetNext(int32_t *aColSpan)
mEnumerationIndex = 0;
if (mHashTable.ops) {
HashTableEntry **sh =
new HashTableEntry*[mHashTable.entryCount];
new HashTableEntry*[mHashTable.EntryCount()];
if (!sh) {
// give up
mState = DONE;
return nullptr;
}
PL_DHashTableEnumerate(&mHashTable, FillSortedArray, sh);
NS_QuickSort(sh, mHashTable.entryCount, sizeof(sh[0]),
NS_QuickSort(sh, mHashTable.EntryCount(), sizeof(sh[0]),
SortArray, nullptr);
mSortedHashTable = sh;
}
/* fall through */
case ENUMERATING_HASH:
if (mHashTable.ops && mEnumerationIndex < mHashTable.entryCount) {
if (mHashTable.ops && mEnumerationIndex < mHashTable.EntryCount()) {
Item *result = mSortedHashTable[mEnumerationIndex]->mItems;
*aColSpan = mSortedHashTable[mEnumerationIndex]->mColSpan;
NS_ASSERTION(result, "holes in hash table");

Просмотреть файл

@ -745,7 +745,7 @@ Preferences::GetPreference(PrefSetting* aPref)
void
Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
{
aPrefs->SetCapacity(PL_DHASH_TABLE_CAPACITY(&gHashTable));
aPrefs->SetCapacity(gHashTable.Capacity());
PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
}
@ -971,8 +971,8 @@ Preferences::WritePrefFile(nsIFile* aFile)
if (NS_FAILED(rv))
return rv;
nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.entryCount]);
memset(valueArray, 0, gHashTable.entryCount * sizeof(char*));
nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.EntryCount()]);
memset(valueArray, 0, gHashTable.EntryCount() * sizeof(char*));
pref_saveArgs saveArgs;
saveArgs.prefArray = valueArray;
saveArgs.saveTypes = SAVE_ALL;
@ -981,13 +981,13 @@ Preferences::WritePrefFile(nsIFile* aFile)
PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
/* Sort the preferences to make a readable file on disk */
NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, nullptr);
NS_QuickSort(valueArray, gHashTable.EntryCount(), sizeof(char *), pref_CompareStrings, nullptr);
// write out the file header
outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
char** walker = valueArray;
for (uint32_t valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
for (uint32_t valueIdx = 0; valueIdx < gHashTable.EntryCount(); valueIdx++, walker++) {
if (*walker) {
outStream->Write(*walker, strlen(*walker), &writeAmount);
outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);

Просмотреть файл

@ -895,4 +895,4 @@ NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeTo
return NS_OK;
}
#undef ENSURE_MAIN_PROCESS
#undef ENSURE_MAIN_PROCESS

Просмотреть файл

@ -47,7 +47,7 @@ clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
// don't need to free this as it's allocated in memory owned by
// gPrefNameArena
pref->key = nullptr;
memset(entry, 0, table->entrySize);
memset(entry, 0, table->EntrySize());
}
static bool
@ -65,7 +65,7 @@ matchPrefEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
return (strcmp(prefEntry->key, otherKey) == 0);
}
PLDHashTable gHashTable = { nullptr };
PLDHashTable gHashTable;
static PLArenaPool gPrefNameArena;
bool gDirty = false;

Просмотреть файл

@ -230,7 +230,7 @@ nsLoadGroup::Cancel(nsresult status)
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
nsresult rv;
uint32_t count = mRequests.entryCount;
uint32_t count = mRequests.EntryCount();
nsAutoTArray<nsIRequest*, 8> requests;
@ -301,7 +301,7 @@ nsLoadGroup::Cancel(nsresult status)
}
#if defined(DEBUG)
NS_ASSERTION(mRequests.entryCount == 0, "Request list is not empty.");
NS_ASSERTION(mRequests.EntryCount() == 0, "Request list is not empty.");
NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active.");
#endif
@ -316,7 +316,7 @@ NS_IMETHODIMP
nsLoadGroup::Suspend()
{
nsresult rv, firstError;
uint32_t count = mRequests.entryCount;
uint32_t count = mRequests.EntryCount();
nsAutoTArray<nsIRequest*, 8> requests;
@ -368,7 +368,7 @@ NS_IMETHODIMP
nsLoadGroup::Resume()
{
nsresult rv, firstError;
uint32_t count = mRequests.entryCount;
uint32_t count = mRequests.EntryCount();
nsAutoTArray<nsIRequest*, 8> requests;
@ -489,7 +489,7 @@ nsLoadGroup::AddRequest(nsIRequest *request, nsISupports* ctxt)
nsAutoCString nameStr;
request->GetName(nameStr);
LOG(("LOADGROUP [%x]: Adding request %x %s (count=%d).\n",
this, request, nameStr.get(), mRequests.entryCount));
this, request, nameStr.get(), mRequests.EntryCount()));
}
#endif /* PR_LOGGING */
@ -602,7 +602,7 @@ nsLoadGroup::RemoveRequest(nsIRequest *request, nsISupports* ctxt,
nsAutoCString nameStr;
request->GetName(nameStr);
LOG(("LOADGROUP [%x]: Removing request %x %s status %x (count=%d).\n",
this, request, nameStr.get(), aStatus, mRequests.entryCount-1));
this, request, nameStr.get(), aStatus, mRequests.EntryCount() - 1));
}
#endif
@ -664,7 +664,7 @@ nsLoadGroup::RemoveRequest(nsIRequest *request, nsISupports* ctxt,
}
}
if (mRequests.entryCount == 0) {
if (mRequests.EntryCount() == 0) {
TelemetryReport();
}
@ -720,7 +720,7 @@ NS_IMETHODIMP
nsLoadGroup::GetRequests(nsISimpleEnumerator * *aRequests)
{
nsCOMArray<nsIRequest> requests;
requests.SetCapacity(mRequests.entryCount);
requests.SetCapacity(mRequests.EntryCount());
PL_DHashTableEnumerate(&mRequests, AppendRequestsToCOMArray, &requests);

Просмотреть файл

@ -42,7 +42,7 @@ struct HttpHeapAtom {
char value[1];
};
static struct PLDHashTable sAtomTable = {0};
static struct PLDHashTable sAtomTable;
static struct HttpHeapAtom *sHeapAtoms = nullptr;
static Mutex *sLock = nullptr;

Просмотреть файл

@ -73,8 +73,8 @@ static const PLDHashTableOps UnicodeToEntityOps = {
nullptr,
};
static PLDHashTable gEntityToUnicode = { 0 };
static PLDHashTable gUnicodeToEntity = { 0 };
static PLDHashTable gEntityToUnicode;
static PLDHashTable gUnicodeToEntity;
static nsrefcnt gTableRefCnt = 0;
#define HTML_ENTITY(_name, _value) { #_name, _value },

Просмотреть файл

@ -1316,7 +1316,7 @@ InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
}
else {
// If this second-level hash empties out, clean it up.
if (!root->u.hash.mPropertyHash->entryCount) {
if (!root->u.hash.mPropertyHash->EntryCount()) {
root->Release();
SetForwardArcs(aSource, nullptr);
}
@ -1661,7 +1661,7 @@ NS_IMETHODIMP
InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
{
nsCOMArray<nsIRDFNode> nodes;
nodes.SetCapacity(mForwardArcs.entryCount);
nodes.SetCapacity(mForwardArcs.EntryCount());
// Enumerate all of our entries into an nsCOMArray
PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes);
@ -1920,7 +1920,7 @@ InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
SweepForwardArcsEntries, info);
// If the sub-hash is now empty, clean it up.
if (!as->u.hash.mPropertyHash->entryCount) {
if (!as->u.hash.mPropertyHash->EntryCount()) {
as->Release();
result = PL_DHASH_REMOVE;
}

Просмотреть файл

@ -1385,7 +1385,7 @@ RemoveInfoCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number,
void nsDocLoader::ClearRequestInfoHash(void)
{
if (!mRequestInfoHash.ops || !mRequestInfoHash.entryCount) {
if (!mRequestInfoHash.ops || !mRequestInfoHash.EntryCount()) {
// No hash, or the hash is empty, nothing to do here then...
return;

Просмотреть файл

@ -878,7 +878,7 @@ public:
uint32_t MapCount() const
{
return mPtrToNodeMap.entryCount;
return mPtrToNodeMap.EntryCount();
}
void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,

Просмотреть файл

@ -343,13 +343,12 @@ NS_PurgeAtomTable()
if (dumpAtomLeaks && *dumpAtomLeaks) {
uint32_t leaked = 0;
printf("*** %d atoms still exist (including permanent):\n",
gAtomTable.entryCount);
gAtomTable.EntryCount());
PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
printf("*** %u non-permanent atoms leaked\n", leaked);
}
#endif
PL_DHashTableFinish(&gAtomTable);
gAtomTable.entryCount = 0;
gAtomTable.ops = nullptr;
}
}
@ -406,9 +405,9 @@ AtomImpl::~AtomImpl()
if (!IsPermanentInDestructor()) {
AtomTableKey key(mString, mLength, mHash);
PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE);
if (gAtomTable.entryCount == 0) {
if (gAtomTable.ops && gAtomTable.EntryCount() == 0) {
PL_DHashTableFinish(&gAtomTable);
NS_ASSERTION(gAtomTable.entryCount == 0,
NS_ASSERTION(gAtomTable.EntryCount() == 0,
"PL_DHashTableFinish changed the entry count");
}
}
@ -558,7 +557,7 @@ GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t* aHashOut)
AtomTableEntry* e = static_cast<AtomTableEntry*>(
PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
if (!e) {
NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
NS_ABORT_OOM(gAtomTable.EntryCount() * gAtomTable.EntrySize());
}
return e;
}
@ -572,7 +571,7 @@ GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t* aHashOut)
AtomTableEntry* e = static_cast<AtomTableEntry*>(
PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
if (!e) {
NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
NS_ABORT_OOM(gAtomTable.EntryCount() * gAtomTable.EntrySize());
}
return e;
}
@ -719,7 +718,7 @@ NS_NewPermanentAtom(const nsAString& aUTF16String)
nsrefcnt
NS_GetNumberOfAtoms(void)
{
return gAtomTable.entryCount;
return gAtomTable.EntryCount();
}
nsIAtom*

Просмотреть файл

@ -607,11 +607,11 @@ nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult)
nsCOMArray<nsIPropertyElement> props;
// We know the necessary size; we can avoid growing it while adding elements
props.SetCapacity(mTable.entryCount);
props.SetCapacity(mTable.EntryCount());
// Step through hash entries populating a transient array
uint32_t n = PL_DHashTableEnumerate(&mTable, AddElemToArray, (void*)&props);
if (n < mTable.entryCount) {
if (n < mTable.EntryCount()) {
return NS_ERROR_OUT_OF_MEMORY;
}

Просмотреть файл

@ -116,7 +116,7 @@ nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable()
{
if (mNameArray) {
// manually call the destructor on placement-new'ed objects
for (uint32_t index = 0; index < mNameTable.entryCount; index++) {
for (uint32_t index = 0; index < mNameTable.EntryCount(); index++) {
mNameArray[index].~nsDependentCString();
}
nsMemory::Free((void*)mNameArray);
@ -231,7 +231,7 @@ nsStaticCaseInsensitiveNameTable::GetStringValue(int32_t aIndex)
NS_ASSERTION(mNameArray, "not inited");
NS_ASSERTION(mNameTable.ops, "not inited");
if ((NOT_FOUND < aIndex) && ((uint32_t)aIndex < mNameTable.entryCount)) {
if ((NOT_FOUND < aIndex) && ((uint32_t)aIndex < mNameTable.EntryCount())) {
return mNameArray[aIndex];
}
return mNullStr;

Просмотреть файл

@ -124,7 +124,7 @@ public:
void Put(KeyType aKey, const UserDataType& aData)
{
if (!Put(aKey, aData, fallible_t())) {
NS_ABORT_OOM(this->mTable.entrySize * this->mTable.entryCount);
NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
}
}

Просмотреть файл

@ -148,7 +148,7 @@ nsRefPtrHashtable<KeyClass, RefPtr>::Put(KeyType aKey,
already_AddRefed<RefPtr> aData)
{
if (!Put(aKey, mozilla::Move(aData), mozilla::fallible_t())) {
NS_ABORT_OOM(this->mTable.entrySize * this->mTable.entryCount);
NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
}
}

Просмотреть файл

@ -99,7 +99,7 @@ public:
* Return the generation number for the table. This increments whenever
* the table data items are moved.
*/
uint32_t GetGeneration() const { return mTable.generation; }
uint32_t GetGeneration() const { return mTable.Generation(); }
/**
* KeyType is typedef'ed for ease of use.
@ -115,7 +115,7 @@ public:
* Return the number of entries in the table.
* @return number of entries
*/
uint32_t Count() const { return mTable.entryCount; }
uint32_t Count() const { return mTable.EntryCount(); }
/**
* Get the entry associated with a key.
@ -150,7 +150,7 @@ public:
{
EntryType* e = PutEntry(aKey, fallible_t());
if (!e) {
NS_ABORT_OOM(mTable.entrySize * mTable.entryCount);
NS_ABORT_OOM(mTable.EntrySize() * mTable.EntryCount());
}
return e;
}

Просмотреть файл

@ -115,27 +115,46 @@ PL_DHashMatchStringKey(PLDHashTable* aTable,
strcmp((const char*)stub->key, (const char*)aKey) == 0);
}
MOZ_ALWAYS_INLINE void
PLDHashTable::MoveEntryStub(const PLDHashEntryHdr* aFrom,
PLDHashEntryHdr* aTo)
{
memcpy(aTo, aFrom, entrySize);
}
void
PL_DHashMoveEntryStub(PLDHashTable* aTable,
const PLDHashEntryHdr* aFrom,
PLDHashEntryHdr* aTo)
{
memcpy(aTo, aFrom, aTable->entrySize);
aTable->MoveEntryStub(aFrom, aTo);
}
MOZ_ALWAYS_INLINE void
PLDHashTable::ClearEntryStub(PLDHashEntryHdr* aEntry)
{
memset(aEntry, 0, entrySize);
}
void
PL_DHashClearEntryStub(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
{
memset(aEntry, 0, aTable->entrySize);
aTable->ClearEntryStub(aEntry);
}
MOZ_ALWAYS_INLINE void
PLDHashTable::FreeStringKey(PLDHashEntryHdr* aEntry)
{
const PLDHashEntryStub* stub = (const PLDHashEntryStub*)aEntry;
free((void*)stub->key);
memset(aEntry, 0, entrySize);
}
void
PL_DHashFreeStringKey(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
{
const PLDHashEntryStub* stub = (const PLDHashEntryStub*)aEntry;
free((void*)stub->key);
memset(aEntry, 0, aTable->entrySize);
aTable->FreeStringKey(aEntry);
}
void
@ -220,17 +239,16 @@ MinCapacity(uint32_t aLength)
return (aLength * 4 + (3 - 1)) / 3; // == ceil(aLength * 4 / 3)
}
bool
PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
void* aData, uint32_t aEntrySize, const fallible_t&,
uint32_t aLength)
MOZ_ALWAYS_INLINE bool
PLDHashTable::Init(const PLDHashTableOps* aOps, void* aData,
uint32_t aEntrySize, const fallible_t&, uint32_t aLength)
{
#ifdef DEBUG
if (aEntrySize > 16 * sizeof(void*)) {
printf_stderr(
"pldhash: for the aTable at address %p, the given aEntrySize"
"pldhash: for the table at address %p, the given aEntrySize"
" of %lu definitely favors chaining over double hashing.\n",
(void*)aTable,
(void*)this,
(unsigned long) aEntrySize);
}
#endif
@ -239,8 +257,8 @@ PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
return false;
}
aTable->ops = aOps;
aTable->data = aData;
ops = aOps;
data = aData;
// Compute the smallest capacity allowing |aLength| elements to be inserted
// without rehashing.
@ -253,29 +271,37 @@ PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
capacity = 1u << log2;
MOZ_ASSERT(capacity <= PL_DHASH_MAX_CAPACITY);
aTable->hashShift = PL_DHASH_BITS - log2;
aTable->entrySize = aEntrySize;
aTable->entryCount = aTable->removedCount = 0;
aTable->generation = 0;
hashShift = PL_DHASH_BITS - log2;
entrySize = aEntrySize;
entryCount = removedCount = 0;
generation = 0;
uint32_t nbytes;
if (!SizeOfEntryStore(capacity, aEntrySize, &nbytes)) {
return false; // overflowed
}
aTable->entryStore = (char*)aOps->allocTable(aTable, nbytes);
if (!aTable->entryStore) {
entryStore = (char*)aOps->allocTable(this, nbytes);
if (!entryStore) {
return false;
}
memset(aTable->entryStore, 0, nbytes);
METER(memset(&aTable->stats, 0, sizeof(aTable->stats)));
memset(entryStore, 0, nbytes);
METER(memset(&stats, 0, sizeof(stats)));
#ifdef DEBUG
aTable->recursionLevel = 0;
recursionLevel = 0;
#endif
return true;
}
bool
PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
void* aData, uint32_t aEntrySize,
const fallible_t& aFallible, uint32_t aLength)
{
return aTable->Init(aOps, aData, aEntrySize, aFallible, aLength);
}
void
PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
void* aData, uint32_t aEntrySize, uint32_t aLength)
@ -307,16 +333,12 @@ PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
* flag in addition to the removed-entry sentinel value. Multiplicative hash
* uses the high order bits of keyHash, so this least-significant reservation
* should not hurt the hash function's effectiveness much.
*
* If you change any of these magic numbers, also update PL_DHASH_ENTRY_IS_LIVE
* in pldhash.h. It used to be private to pldhash.c, but then became public to
* assist iterator writers who inspect table->entryStore directly.
*/
#define COLLISION_FLAG ((PLDHashNumber) 1)
#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0)
#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1)
#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1)
#define ENTRY_IS_LIVE(entry) PL_DHASH_ENTRY_IS_LIVE(entry)
#define ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0
/* Match an entry's keyHash against an unstored one computed from a key. */
@ -327,63 +349,67 @@ PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
#define ADDRESS_ENTRY(table, index) \
((PLDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize))
void
PL_DHashTableFinish(PLDHashTable* aTable)
MOZ_ALWAYS_INLINE void
PLDHashTable::Finish()
{
INCREMENT_RECURSION_LEVEL(aTable);
INCREMENT_RECURSION_LEVEL(this);
/* Call finalize before clearing entries, so it can enumerate them. */
aTable->ops->finalize(aTable);
ops->finalize(this);
/* Clear any remaining live entries. */
char* entryAddr = aTable->entryStore;
uint32_t entrySize = aTable->entrySize;
char* entryLimit = entryAddr + PL_DHASH_TABLE_CAPACITY(aTable) * entrySize;
char* entryAddr = entryStore;
char* entryLimit = entryAddr + Capacity() * entrySize;
while (entryAddr < entryLimit) {
PLDHashEntryHdr* entry = (PLDHashEntryHdr*)entryAddr;
if (ENTRY_IS_LIVE(entry)) {
METER(aTable->stats.removeEnums++);
aTable->ops->clearEntry(aTable, entry);
METER(stats.removeEnums++);
ops->clearEntry(this, entry);
}
entryAddr += entrySize;
}
DECREMENT_RECURSION_LEVEL(aTable);
MOZ_ASSERT(RECURSION_LEVEL_SAFE_TO_FINISH(aTable));
DECREMENT_RECURSION_LEVEL(this);
MOZ_ASSERT(RECURSION_LEVEL_SAFE_TO_FINISH(this));
/* Free entry storage last. */
aTable->ops->freeTable(aTable, aTable->entryStore);
ops->freeTable(this, entryStore);
}
static PLDHashEntryHdr* PL_DHASH_FASTCALL
SearchTable(PLDHashTable* aTable, const void* aKey, PLDHashNumber aKeyHash,
PLDHashOperator aOp)
void
PL_DHashTableFinish(PLDHashTable* aTable)
{
METER(aTable->stats.searches++);
aTable->Finish();
}
PLDHashEntryHdr* PL_DHASH_FASTCALL
PLDHashTable::SearchTable(const void* aKey, PLDHashNumber aKeyHash,
PLDHashOperator aOp)
{
METER(stats.searches++);
NS_ASSERTION(!(aKeyHash & COLLISION_FLAG),
"!(aKeyHash & COLLISION_FLAG)");
/* Compute the primary hash address. */
int hashShift = aTable->hashShift;
PLDHashNumber hash1 = HASH1(aKeyHash, hashShift);
PLDHashEntryHdr* entry = ADDRESS_ENTRY(aTable, hash1);
PLDHashEntryHdr* entry = ADDRESS_ENTRY(this, hash1);
/* Miss: return space for a new entry. */
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
METER(aTable->stats.misses++);
METER(stats.misses++);
return entry;
}
/* Hit: return entry. */
PLDHashMatchEntry matchEntry = aTable->ops->matchEntry;
PLDHashMatchEntry matchEntry = ops->matchEntry;
if (MATCH_ENTRY_KEYHASH(entry, aKeyHash) &&
matchEntry(aTable, entry, aKey)) {
METER(aTable->stats.hits++);
matchEntry(this, entry, aKey)) {
METER(stats.hits++);
return entry;
}
/* Collision: double hash. */
int sizeLog2 = PL_DHASH_BITS - aTable->hashShift;
int sizeLog2 = PL_DHASH_BITS - hashShift;
PLDHashNumber hash2 = HASH2(aKeyHash, sizeLog2, hashShift);
uint32_t sizeMask = (1u << sizeLog2) - 1;
@ -401,19 +427,19 @@ SearchTable(PLDHashTable* aTable, const void* aKey, PLDHashNumber aKeyHash,
}
}
METER(aTable->stats.steps++);
METER(stats.steps++);
hash1 -= hash2;
hash1 &= sizeMask;
entry = ADDRESS_ENTRY(aTable, hash1);
entry = ADDRESS_ENTRY(this, hash1);
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
METER(aTable->stats.misses++);
METER(stats.misses++);
return (firstRemoved && aOp == PL_DHASH_ADD) ? firstRemoved : entry;
}
if (MATCH_ENTRY_KEYHASH(entry, aKeyHash) &&
matchEntry(aTable, entry, aKey)) {
METER(aTable->stats.hits++);
matchEntry(this, entry, aKey)) {
METER(stats.hits++);
return entry;
}
}
@ -432,26 +458,25 @@ SearchTable(PLDHashTable* aTable, const void* aKey, PLDHashNumber aKeyHash,
* entries to keys, which means callers can use complex key types more
* easily.
*/
static PLDHashEntryHdr* PL_DHASH_FASTCALL
FindFreeEntry(PLDHashTable* aTable, PLDHashNumber aKeyHash)
PLDHashEntryHdr* PL_DHASH_FASTCALL
PLDHashTable::FindFreeEntry(PLDHashNumber aKeyHash)
{
METER(aTable->stats.searches++);
METER(stats.searches++);
NS_ASSERTION(!(aKeyHash & COLLISION_FLAG),
"!(aKeyHash & COLLISION_FLAG)");
/* Compute the primary hash address. */
int hashShift = aTable->hashShift;
PLDHashNumber hash1 = HASH1(aKeyHash, hashShift);
PLDHashEntryHdr* entry = ADDRESS_ENTRY(aTable, hash1);
PLDHashEntryHdr* entry = ADDRESS_ENTRY(this, hash1);
/* Miss: return space for a new entry. */
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
METER(aTable->stats.misses++);
METER(stats.misses++);
return entry;
}
/* Collision: double hash. */
int sizeLog2 = PL_DHASH_BITS - aTable->hashShift;
int sizeLog2 = PL_DHASH_BITS - hashShift;
PLDHashNumber hash2 = HASH2(aKeyHash, sizeLog2, hashShift);
uint32_t sizeMask = (1u << sizeLog2) - 1;
@ -460,13 +485,13 @@ FindFreeEntry(PLDHashTable* aTable, PLDHashNumber aKeyHash)
"!ENTRY_IS_REMOVED(entry)");
entry->keyHash |= COLLISION_FLAG;
METER(aTable->stats.steps++);
METER(stats.steps++);
hash1 -= hash2;
hash1 &= sizeMask;
entry = ADDRESS_ENTRY(aTable, hash1);
entry = ADDRESS_ENTRY(this, hash1);
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
METER(aTable->stats.misses++);
METER(stats.misses++);
return entry;
}
}
@ -475,45 +500,44 @@ FindFreeEntry(PLDHashTable* aTable, PLDHashNumber aKeyHash)
return nullptr;
}
static bool
ChangeTable(PLDHashTable* aTable, int aDeltaLog2)
bool
PLDHashTable::ChangeTable(int aDeltaLog2)
{
/* Look, but don't touch, until we succeed in getting new entry store. */
int oldLog2 = PL_DHASH_BITS - aTable->hashShift;
int oldLog2 = PL_DHASH_BITS - hashShift;
int newLog2 = oldLog2 + aDeltaLog2;
uint32_t newCapacity = 1u << newLog2;
if (newCapacity > PL_DHASH_MAX_CAPACITY) {
return false;
}
uint32_t entrySize = aTable->entrySize;
uint32_t nbytes;
if (!SizeOfEntryStore(newCapacity, entrySize, &nbytes)) {
return false; // overflowed
}
char* newEntryStore = (char*)aTable->ops->allocTable(aTable, nbytes);
char* newEntryStore = (char*)ops->allocTable(this, nbytes);
if (!newEntryStore) {
return false;
}
/* We can't fail from here on, so update table parameters. */
#ifdef DEBUG
uint32_t recursionLevel = aTable->recursionLevel;
uint32_t recursionLevelTmp = recursionLevel;
#endif
aTable->hashShift = PL_DHASH_BITS - newLog2;
aTable->removedCount = 0;
aTable->generation++;
hashShift = PL_DHASH_BITS - newLog2;
removedCount = 0;
generation++;
/* Assign the new entry store to table. */
memset(newEntryStore, 0, nbytes);
char* oldEntryStore;
char* oldEntryAddr;
oldEntryAddr = oldEntryStore = aTable->entryStore;
aTable->entryStore = newEntryStore;
PLDHashMoveEntry moveEntry = aTable->ops->moveEntry;
oldEntryAddr = oldEntryStore = entryStore;
entryStore = newEntryStore;
PLDHashMoveEntry moveEntry = ops->moveEntry;
#ifdef DEBUG
aTable->recursionLevel = recursionLevel;
recursionLevel = recursionLevelTmp;
#endif
/* Copy only live entries, leaving removed ones behind. */
@ -522,28 +546,28 @@ ChangeTable(PLDHashTable* aTable, int aDeltaLog2)
PLDHashEntryHdr* oldEntry = (PLDHashEntryHdr*)oldEntryAddr;
if (ENTRY_IS_LIVE(oldEntry)) {
oldEntry->keyHash &= ~COLLISION_FLAG;
PLDHashEntryHdr* newEntry = FindFreeEntry(aTable, oldEntry->keyHash);
PLDHashEntryHdr* newEntry = FindFreeEntry(oldEntry->keyHash);
NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(newEntry),
"PL_DHASH_ENTRY_IS_FREE(newEntry)");
moveEntry(aTable, oldEntry, newEntry);
moveEntry(this, oldEntry, newEntry);
newEntry->keyHash = oldEntry->keyHash;
}
oldEntryAddr += entrySize;
}
aTable->ops->freeTable(aTable, oldEntryStore);
ops->freeTable(this, oldEntryStore);
return true;
}
PLDHashEntryHdr* PL_DHASH_FASTCALL
PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp)
MOZ_ALWAYS_INLINE PLDHashEntryHdr*
PLDHashTable::Operate(const void* aKey, PLDHashOperator aOp)
{
PLDHashEntryHdr* entry;
MOZ_ASSERT(aOp == PL_DHASH_LOOKUP || aTable->recursionLevel == 0);
INCREMENT_RECURSION_LEVEL(aTable);
MOZ_ASSERT(aOp == PL_DHASH_LOOKUP || recursionLevel == 0);
INCREMENT_RECURSION_LEVEL(this);
PLDHashNumber keyHash = aTable->ops->hashKey(aTable, aKey);
PLDHashNumber keyHash = ops->hashKey(this, aKey);
keyHash *= PL_DHASH_GOLDEN_RATIO;
/* Avoid 0 and 1 hash codes, they indicate free and removed entries. */
@ -552,8 +576,8 @@ PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp
switch (aOp) {
case PL_DHASH_LOOKUP:
METER(aTable->stats.lookups++);
entry = SearchTable(aTable, aKey, keyHash, aOp);
METER(stats.lookups++);
entry = SearchTable(aKey, keyHash, aOp);
break;
case PL_DHASH_ADD: {
@ -562,27 +586,27 @@ PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp
* in the table, we may grow once more than necessary, but only if we
* are on the edge of being overloaded.
*/
uint32_t capacity = PL_DHASH_TABLE_CAPACITY(aTable);
if (aTable->entryCount + aTable->removedCount >= MaxLoad(capacity)) {
uint32_t capacity = Capacity();
if (entryCount + removedCount >= MaxLoad(capacity)) {
/* Compress if a quarter or more of all entries are removed. */
int deltaLog2;
if (aTable->removedCount >= capacity >> 2) {
METER(aTable->stats.compresses++);
if (removedCount >= capacity >> 2) {
METER(stats.compresses++);
deltaLog2 = 0;
} else {
METER(aTable->stats.grows++);
METER(stats.grows++);
deltaLog2 = 1;
}
/*
* Grow or compress aTable. If ChangeTable() fails, allow
* Grow or compress the table. If ChangeTable() fails, allow
* overloading up to the secondary max. Once we hit the secondary
* max, return null.
*/
if (!ChangeTable(aTable, deltaLog2) &&
aTable->entryCount + aTable->removedCount >=
if (!ChangeTable(deltaLog2) &&
entryCount + removedCount >=
MaxLoadOnGrowthFailure(capacity)) {
METER(aTable->stats.addFailures++);
METER(stats.addFailures++);
entry = nullptr;
break;
}
@ -592,48 +616,47 @@ PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp
* 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.
*/
entry = SearchTable(aTable, aKey, keyHash, aOp);
entry = SearchTable(aKey, keyHash, aOp);
if (!ENTRY_IS_LIVE(entry)) {
/* Initialize the entry, indicating that it's no longer free. */
METER(aTable->stats.addMisses++);
METER(stats.addMisses++);
if (ENTRY_IS_REMOVED(entry)) {
METER(aTable->stats.addOverRemoved++);
aTable->removedCount--;
METER(stats.addOverRemoved++);
removedCount--;
keyHash |= COLLISION_FLAG;
}
if (aTable->ops->initEntry &&
!aTable->ops->initEntry(aTable, entry, aKey)) {
if (ops->initEntry && !ops->initEntry(this, entry, aKey)) {
/* We haven't claimed entry yet; fail with null return. */
memset(entry + 1, 0, aTable->entrySize - sizeof(*entry));
memset(entry + 1, 0, entrySize - sizeof(*entry));
entry = nullptr;
break;
}
entry->keyHash = keyHash;
aTable->entryCount++;
entryCount++;
}
METER(else {
aTable->stats.addHits++;
stats.addHits++;
});
break;
}
case PL_DHASH_REMOVE:
entry = SearchTable(aTable, aKey, keyHash, aOp);
entry = SearchTable(aKey, keyHash, aOp);
if (ENTRY_IS_LIVE(entry)) {
/* Clear this entry and mark it as "removed". */
METER(aTable->stats.removeHits++);
PL_DHashTableRawRemove(aTable, entry);
METER(stats.removeHits++);
PL_DHashTableRawRemove(this, entry);
/* Shrink if alpha is <= .25 and aTable isn't too small already. */
uint32_t capacity = PL_DHASH_TABLE_CAPACITY(aTable);
/* Shrink if alpha is <= .25 and the table isn't too small already. */
uint32_t capacity = Capacity();
if (capacity > PL_DHASH_MIN_CAPACITY &&
aTable->entryCount <= MinLoad(capacity)) {
METER(aTable->stats.shrinks++);
(void) ChangeTable(aTable, -1);
entryCount <= MinLoad(capacity)) {
METER(stats.shrinks++);
(void) ChangeTable(-1);
}
}
METER(else {
aTable->stats.removeMisses++;
stats.removeMisses++;
});
entry = nullptr;
break;
@ -643,40 +666,50 @@ PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp
entry = nullptr;
}
DECREMENT_RECURSION_LEVEL(aTable);
DECREMENT_RECURSION_LEVEL(this);
return entry;
}
PLDHashEntryHdr* PL_DHASH_FASTCALL
PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey, PLDHashOperator aOp)
{
return aTable->Operate(aKey, aOp);
}
MOZ_ALWAYS_INLINE void
PLDHashTable::RawRemove(PLDHashEntryHdr* aEntry)
{
MOZ_ASSERT(recursionLevel != IMMUTABLE_RECURSION_LEVEL);
NS_ASSERTION(ENTRY_IS_LIVE(aEntry), "ENTRY_IS_LIVE(aEntry)");
/* Load keyHash first in case clearEntry() goofs it. */
PLDHashNumber keyHash = aEntry->keyHash;
ops->clearEntry(this, aEntry);
if (keyHash & COLLISION_FLAG) {
MARK_ENTRY_REMOVED(aEntry);
removedCount++;
} else {
METER(stats.removeFrees++);
MARK_ENTRY_FREE(aEntry);
}
entryCount--;
}
void
PL_DHashTableRawRemove(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
{
MOZ_ASSERT(aTable->recursionLevel != IMMUTABLE_RECURSION_LEVEL);
NS_ASSERTION(PL_DHASH_ENTRY_IS_LIVE(aEntry),
"PL_DHASH_ENTRY_IS_LIVE(aEntry)");
/* Load keyHash first in case clearEntry() goofs it. */
PLDHashNumber keyHash = aEntry->keyHash;
aTable->ops->clearEntry(aTable, aEntry);
if (keyHash & COLLISION_FLAG) {
MARK_ENTRY_REMOVED(aEntry);
aTable->removedCount++;
} else {
METER(aTable->stats.removeFrees++);
MARK_ENTRY_FREE(aEntry);
}
aTable->entryCount--;
aTable->RawRemove(aEntry);
}
uint32_t
PL_DHashTableEnumerate(PLDHashTable* aTable, PLDHashEnumerator aEtor, void* aArg)
MOZ_ALWAYS_INLINE uint32_t
PLDHashTable::Enumerate(PLDHashEnumerator aEtor, void* aArg)
{
INCREMENT_RECURSION_LEVEL(aTable);
INCREMENT_RECURSION_LEVEL(this);
char* entryAddr = aTable->entryStore;
uint32_t entrySize = aTable->entrySize;
uint32_t capacity = PL_DHASH_TABLE_CAPACITY(aTable);
char* entryAddr = entryStore;
uint32_t capacity = Capacity();
uint32_t tableSize = capacity * entrySize;
char* entryLimit = entryAddr + tableSize;
uint32_t i = 0;
@ -695,10 +728,10 @@ PL_DHashTableEnumerate(PLDHashTable* aTable, PLDHashEnumerator aEtor, void* aArg
for (uint32_t e = 0; e < capacity; ++e) {
PLDHashEntryHdr* entry = (PLDHashEntryHdr*)entryAddr;
if (ENTRY_IS_LIVE(entry)) {
PLDHashOperator op = aEtor(aTable, entry, i++, aArg);
PLDHashOperator op = aEtor(this, entry, i++, aArg);
if (op & PL_DHASH_REMOVE) {
METER(aTable->stats.removeEnums++);
PL_DHashTableRawRemove(aTable, entry);
METER(stats.removeEnums++);
PL_DHashTableRawRemove(this, entry);
didRemove = true;
}
if (op & PL_DHASH_STOP) {
@ -711,37 +744,44 @@ PL_DHashTableEnumerate(PLDHashTable* aTable, PLDHashEnumerator aEtor, void* aArg
}
}
MOZ_ASSERT(!didRemove || aTable->recursionLevel == 1);
MOZ_ASSERT(!didRemove || recursionLevel == 1);
/*
* Shrink or compress if a quarter or more of all entries are removed, or
* if the table is underloaded according to the minimum alpha, and is not
* minimal-size already. Do this only if we removed above, so non-removing
* enumerations can count on stable aTable->entryStore until the next
* enumerations can count on stable |entryStore| until the next
* non-lookup-Operate or removing-Enumerate.
*/
if (didRemove &&
(aTable->removedCount >= capacity >> 2 ||
(removedCount >= capacity >> 2 ||
(capacity > PL_DHASH_MIN_CAPACITY &&
aTable->entryCount <= MinLoad(capacity)))) {
METER(aTable->stats.enumShrinks++);
capacity = aTable->entryCount;
entryCount <= MinLoad(capacity)))) {
METER(stats.enumShrinks++);
capacity = entryCount;
capacity += capacity >> 1;
if (capacity < PL_DHASH_MIN_CAPACITY) {
capacity = PL_DHASH_MIN_CAPACITY;
}
uint32_t ceiling = CeilingLog2(capacity);
ceiling -= PL_DHASH_BITS - aTable->hashShift;
ceiling -= PL_DHASH_BITS - hashShift;
(void) ChangeTable(aTable, ceiling);
(void) ChangeTable(ceiling);
}
DECREMENT_RECURSION_LEVEL(aTable);
DECREMENT_RECURSION_LEVEL(this);
return i;
}
uint32_t
PL_DHashTableEnumerate(PLDHashTable* aTable, PLDHashEnumerator aEtor,
void* aArg)
{
return aTable->Enumerate(aEtor, aArg);
}
struct SizeOfEntryExcludingThisArg
{
size_t total;
@ -759,23 +799,41 @@ SizeOfEntryExcludingThisEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
return PL_DHASH_NEXT;
}
MOZ_ALWAYS_INLINE size_t
PLDHashTable::SizeOfExcludingThis(
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
MallocSizeOf aMallocSizeOf, void* aArg /* = nullptr */) const
{
size_t n = 0;
n += aMallocSizeOf(entryStore);
if (aSizeOfEntryExcludingThis) {
SizeOfEntryExcludingThisArg arg2 = {
0, aSizeOfEntryExcludingThis, aMallocSizeOf, aArg
};
PL_DHashTableEnumerate(const_cast<PLDHashTable*>(this),
SizeOfEntryExcludingThisEnumerator, &arg2);
n += arg2.total;
}
return n;
}
MOZ_ALWAYS_INLINE size_t
PLDHashTable::SizeOfIncludingThis(
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
MallocSizeOf aMallocSizeOf, void* aArg /* = nullptr */) const
{
return aMallocSizeOf(this) +
SizeOfExcludingThis(aSizeOfEntryExcludingThis, aMallocSizeOf, aArg);
}
size_t
PL_DHashTableSizeOfExcludingThis(
const PLDHashTable* aTable,
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
MallocSizeOf aMallocSizeOf, void* aArg /* = nullptr */)
{
size_t n = 0;
n += aMallocSizeOf(aTable->entryStore);
if (aSizeOfEntryExcludingThis) {
SizeOfEntryExcludingThisArg arg2 = {
0, aSizeOfEntryExcludingThis, aMallocSizeOf, aArg
};
PL_DHashTableEnumerate(const_cast<PLDHashTable*>(aTable),
SizeOfEntryExcludingThisEnumerator, &arg2);
n += arg2.total;
}
return n;
return aTable->SizeOfExcludingThis(aSizeOfEntryExcludingThis,
aMallocSizeOf, aArg);
}
size_t
@ -784,16 +842,21 @@ PL_DHashTableSizeOfIncludingThis(
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
MallocSizeOf aMallocSizeOf, void* aArg /* = nullptr */)
{
return aMallocSizeOf(aTable) +
PL_DHashTableSizeOfExcludingThis(aTable, aSizeOfEntryExcludingThis,
aMallocSizeOf, aArg);
return aTable->SizeOfIncludingThis(aSizeOfEntryExcludingThis,
aMallocSizeOf, aArg);
}
#ifdef DEBUG
MOZ_ALWAYS_INLINE void
PLDHashTable::MarkImmutable()
{
recursionLevel = IMMUTABLE_RECURSION_LEVEL;
}
void
PL_DHashMarkTableImmutable(PLDHashTable* aTable)
{
aTable->recursionLevel = IMMUTABLE_RECURSION_LEVEL;
aTable->MarkImmutable();
}
#endif
@ -801,17 +864,15 @@ PL_DHashMarkTableImmutable(PLDHashTable* aTable)
#include <math.h>
void
PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
PLDHashTable::DumpMeter(PLDHashEnumerator aDump, FILE* aFp)
{
PLDHashNumber hash1, hash2, maxChainHash1, maxChainHash2;
double sqsum, mean, variance, sigma;
PLDHashEntryHdr* entry;
char* entryAddr = aTable->entryStore;
uint32_t entrySize = aTable->entrySize;
int hashShift = aTable->hashShift;
char* entryAddr = entryStore;
int sizeLog2 = PL_DHASH_BITS - hashShift;
uint32_t capacity = PL_DHASH_TABLE_CAPACITY(aTable);
uint32_t capacity = Capacity();
uint32_t sizeMask = (1u << sizeLog2) - 1;
uint32_t chainCount = 0, maxChainLen = 0;
hash2 = 0;
@ -825,7 +886,7 @@ PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
}
hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift);
PLDHashNumber saveHash1 = hash1;
PLDHashEntryHdr* probe = ADDRESS_ENTRY(aTable, hash1);
PLDHashEntryHdr* probe = ADDRESS_ENTRY(this, hash1);
uint32_t chainLen = 1;
if (probe == entry) {
/* Start of a (possibly unit-length) chain. */
@ -837,7 +898,7 @@ PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
chainLen++;
hash1 -= hash2;
hash1 &= sizeMask;
probe = ADDRESS_ENTRY(aTable, hash1);
probe = ADDRESS_ENTRY(this, hash1);
} while (probe != entry);
}
sqsum += chainLen * chainLen;
@ -848,7 +909,6 @@ PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
}
}
uint32_t entryCount = aTable->entryCount;
if (entryCount && chainCount) {
mean = (double)entryCount / chainCount;
variance = chainCount * sqsum - entryCount * entryCount;
@ -864,45 +924,50 @@ PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
fprintf(aFp, "Double hashing statistics:\n");
fprintf(aFp, " table size (in entries): %u\n", tableSize);
fprintf(aFp, " number of entries: %u\n", aTable->entryCount);
fprintf(aFp, " number of removed entries: %u\n", aTable->removedCount);
fprintf(aFp, " number of searches: %u\n", aTable->stats.searches);
fprintf(aFp, " number of hits: %u\n", aTable->stats.hits);
fprintf(aFp, " number of misses: %u\n", aTable->stats.misses);
fprintf(aFp, " number of entries: %u\n", entryCount);
fprintf(aFp, " number of removed entries: %u\n", removedCount);
fprintf(aFp, " number of searches: %u\n", stats.searches);
fprintf(aFp, " number of hits: %u\n", stats.hits);
fprintf(aFp, " number of misses: %u\n", stats.misses);
fprintf(aFp, " mean steps per search: %g\n",
aTable->stats.searches ?
(double)aTable->stats.steps / aTable->stats.searches : 0.);
stats.searches ? (double)stats.steps / stats.searches : 0.);
fprintf(aFp, " mean hash chain length: %g\n", mean);
fprintf(aFp, " standard deviation: %g\n", sigma);
fprintf(aFp, " maximum hash chain length: %u\n", maxChainLen);
fprintf(aFp, " number of lookups: %u\n", aTable->stats.lookups);
fprintf(aFp, " adds that made a new entry: %u\n", aTable->stats.addMisses);
fprintf(aFp, "adds that recycled removeds: %u\n", aTable->stats.addOverRemoved);
fprintf(aFp, " adds that found an entry: %u\n", aTable->stats.addHits);
fprintf(aFp, " add failures: %u\n", aTable->stats.addFailures);
fprintf(aFp, " useful removes: %u\n", aTable->stats.removeHits);
fprintf(aFp, " useless removes: %u\n", aTable->stats.removeMisses);
fprintf(aFp, "removes that freed an entry: %u\n", aTable->stats.removeFrees);
fprintf(aFp, " removes while enumerating: %u\n", aTable->stats.removeEnums);
fprintf(aFp, " number of grows: %u\n", aTable->stats.grows);
fprintf(aFp, " number of shrinks: %u\n", aTable->stats.shrinks);
fprintf(aFp, " number of compresses: %u\n", aTable->stats.compresses);
fprintf(aFp, "number of enumerate shrinks: %u\n", aTable->stats.enumShrinks);
fprintf(aFp, " number of lookups: %u\n", stats.lookups);
fprintf(aFp, " adds that made a new entry: %u\n", stats.addMisses);
fprintf(aFp, "adds that recycled removeds: %u\n", stats.addOverRemoved);
fprintf(aFp, " adds that found an entry: %u\n", stats.addHits);
fprintf(aFp, " add failures: %u\n", stats.addFailures);
fprintf(aFp, " useful removes: %u\n", stats.removeHits);
fprintf(aFp, " useless removes: %u\n", stats.removeMisses);
fprintf(aFp, "removes that freed an entry: %u\n", stats.removeFrees);
fprintf(aFp, " removes while enumerating: %u\n", stats.removeEnums);
fprintf(aFp, " number of grows: %u\n", stats.grows);
fprintf(aFp, " number of shrinks: %u\n", stats.shrinks);
fprintf(aFp, " number of compresses: %u\n", stats.compresses);
fprintf(aFp, "number of enumerate shrinks: %u\n", stats.enumShrinks);
if (aDump && maxChainLen && hash2) {
fputs("Maximum hash chain:\n", aFp);
hash1 = maxChainHash1;
hash2 = maxChainHash2;
entry = ADDRESS_ENTRY(aTable, hash1);
entry = ADDRESS_ENTRY(this, hash1);
uint32_t i = 0;
do {
if (aDump(aTable, entry, i++, aFp) != PL_DHASH_NEXT) {
if (aDump(this, entry, i++, aFp) != PL_DHASH_NEXT) {
break;
}
hash1 -= hash2;
hash1 &= sizeMask;
entry = ADDRESS_ENTRY(aTable, hash1);
entry = ADDRESS_ENTRY(this, hash1);
} while (PL_DHASH_ENTRY_IS_BUSY(entry));
}
}
void
PL_DHashTableDumpMeter(PLDHashTable* aTable, PLDHashEnumerator aDump, FILE* aFp)
{
aTable->DumpMeter(aDump, aFp);
}
#endif /* PL_DHASHMETER */

Просмотреть файл

@ -75,11 +75,6 @@ typedef struct PLDHashTableOps PLDHashTableOps;
* maintained automatically by PL_DHashTableOperate -- users should never set
* it, and its only uses should be via the entry macros below.
*
* The PL_DHASH_ENTRY_IS_LIVE function tests whether entry is neither free nor
* removed. An entry may be either busy or free; if busy, it may be live or
* removed. Consumers of this API should not access members of entries that
* are not live.
*
* However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries
* returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a
* non-live, busy (i.e., removed) entry pointer to its caller. See below for
@ -102,11 +97,66 @@ PL_DHASH_ENTRY_IS_BUSY(PLDHashEntryHdr* aEntry)
return !PL_DHASH_ENTRY_IS_FREE(aEntry);
}
MOZ_ALWAYS_INLINE bool
PL_DHASH_ENTRY_IS_LIVE(PLDHashEntryHdr* aEntry)
/*
* To consolidate keyHash computation and table grow/shrink code, we use a
* single entry point for lookup, add, and remove operations. The operation
* codes are declared here, along with codes returned by PLDHashEnumerator
* functions, which control PL_DHashTableEnumerate's behavior.
*/
typedef enum PLDHashOperator
{
return aEntry->keyHash >= 2;
}
PL_DHASH_LOOKUP = 0, /* lookup entry */
PL_DHASH_ADD = 1, /* add entry */
PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */
PL_DHASH_NEXT = 0, /* enumerator says continue */
PL_DHASH_STOP = 1 /* enumerator says stop */
} PLDHashOperator;
/*
* Enumerate entries in table using etor:
*
* count = PL_DHashTableEnumerate(table, etor, arg);
*
* PL_DHashTableEnumerate calls etor like so:
*
* op = etor(table, entry, number, arg);
*
* where number is a zero-based ordinal assigned to live entries according to
* their order in aTable->entryStore.
*
* The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT,
* then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via
* aTable->ops->clearEntry) and free entry. Then we check whether op contains
* PL_DHASH_STOP; if so, stop enumerating and return the number of live entries
* that were enumerated so far. Return the total number of live entries when
* enumeration completes normally.
*
* If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it
* must return PL_DHASH_STOP; otherwise undefined behavior results.
*
* If any enumerator returns PL_DHASH_REMOVE, aTable->entryStore may be shrunk
* or compressed after enumeration, but before PL_DHashTableEnumerate returns.
* Such an enumerator therefore can't safely set aside entry pointers, but an
* enumerator that never returns PL_DHASH_REMOVE can set pointers to entries
* aside, e.g., to avoid copying live entries into an array of the entry type.
* Copying entry pointers is cheaper, and safe so long as the caller of such a
* "stable" Enumerate doesn't use the set-aside pointers after any call either
* to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might
* grow or shrink entryStore.
*
* If your enumerator wants to remove certain entries, but set aside pointers
* to other entries that it retains, it can use PL_DHashTableRawRemove on the
* entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if
* you want to remove entries, but for some reason you do not want entryStore
* to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on
* the entry being enumerated, rather than returning PL_DHASH_REMOVE.
*/
typedef PLDHashOperator (*PLDHashEnumerator)(PLDHashTable* aTable,
PLDHashEntryHdr* aHdr,
uint32_t aNumber, void* aArg);
typedef size_t (*PLDHashSizeOfEntryExcludingThisFun)(
PLDHashEntryHdr* aHdr, mozilla::MallocSizeOf aMallocSizeOf, void* aArg);
/*
* A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead)
@ -182,8 +232,15 @@ PL_DHASH_ENTRY_IS_LIVE(PLDHashEntryHdr* aEntry)
*/
struct PLDHashTable
{
const PLDHashTableOps* ops; /* virtual operations, see below */
/*
* Virtual operations; see below. This field is public because it's commonly
* zeroed to indicate that a table is no longer live.
*/
const PLDHashTableOps* ops;
void* data; /* ops- and instance-specific data */
private:
int16_t hashShift; /* multiplicative hash shift */
/*
* |recursionLevel| is only used in debug builds, but is present in opt
@ -197,6 +254,7 @@ struct PLDHashTable
uint32_t removedCount; /* removed entry sentinels in table */
uint32_t generation; /* entry storage generation number */
char* entryStore; /* entry storage */
#ifdef PL_DHASHMETER
struct PLDHashStats
{
@ -219,15 +277,63 @@ struct PLDHashTable
uint32_t enumShrinks; /* contractions after Enumerate */
} stats;
#endif
};
/*
* Size in entries (gross, not net of free and removed sentinels) for table.
* We store hashShift rather than sizeLog2 to optimize the collision-free case
* in SearchTable.
*/
#define PL_DHASH_TABLE_CAPACITY(table) \
((uint32_t)1 << (PL_DHASH_BITS - (table)->hashShift))
public:
/*
* Size in entries (gross, not net of free and removed sentinels) for table.
* We store hashShift rather than sizeLog2 to optimize the collision-free case
* in SearchTable.
*/
uint32_t Capacity() const
{
return ((uint32_t)1 << (PL_DHASH_BITS - hashShift));
}
uint32_t EntrySize() const { return entrySize; }
uint32_t EntryCount() const { return entryCount; }
uint32_t Generation() const { return generation; }
bool Init(const PLDHashTableOps* aOps, void* aData, uint32_t aEntrySize,
const mozilla::fallible_t&, uint32_t aLength);
void Finish();
PLDHashEntryHdr* Operate(const void* aKey, PLDHashOperator aOp);
void RawRemove(PLDHashEntryHdr* aEntry);
uint32_t Enumerate(PLDHashEnumerator aEtor, void* aArg);
size_t SizeOfIncludingThis(
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
mozilla::MallocSizeOf aMallocSizeOf, void* aArg = nullptr) const;
size_t SizeOfExcludingThis(
PLDHashSizeOfEntryExcludingThisFun aSizeOfEntryExcludingThis,
mozilla::MallocSizeOf aMallocSizeOf, void* aArg = nullptr) const;
#ifdef DEBUG
void MarkImmutable();
#endif
void MoveEntryStub(const PLDHashEntryHdr* aFrom, PLDHashEntryHdr* aTo);
void ClearEntryStub(PLDHashEntryHdr* aEntry);
void FreeStringKey(PLDHashEntryHdr* aEntry);
#ifdef PL_DHASHMETER
void DumpMeter(PLDHashEnumerator aDump, FILE* aFp);
#endif
private:
PLDHashEntryHdr* PL_DHASH_FASTCALL
SearchTable(const void* aKey, PLDHashNumber aKeyHash, PLDHashOperator aOp);
PLDHashEntryHdr* PL_DHASH_FASTCALL FindFreeEntry(PLDHashNumber aKeyHash);
bool ChangeTable(int aDeltaLog2);
};
/*
* Table space at entryStore is allocated and freed using these callbacks.
@ -424,21 +530,6 @@ MOZ_WARN_UNUSED_RESULT NS_COM_GLUE bool PL_DHashTableInit(
*/
NS_COM_GLUE void PL_DHashTableFinish(PLDHashTable* aTable);
/*
* To consolidate keyHash computation and table grow/shrink code, we use a
* single entry point for lookup, add, and remove operations. The operation
* codes are declared here, along with codes returned by PLDHashEnumerator
* functions, which control PL_DHashTableEnumerate's behavior.
*/
typedef enum PLDHashOperator
{
PL_DHASH_LOOKUP = 0, /* lookup entry */
PL_DHASH_ADD = 1, /* add entry */
PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */
PL_DHASH_NEXT = 0, /* enumerator says continue */
PL_DHASH_STOP = 1 /* enumerator says stop */
} PLDHashOperator;
/*
* To lookup a key in table, call:
*
@ -485,56 +576,10 @@ PL_DHashTableOperate(PLDHashTable* aTable, const void* aKey,
NS_COM_GLUE void PL_DHashTableRawRemove(PLDHashTable* aTable,
PLDHashEntryHdr* aEntry);
/*
* Enumerate entries in table using etor:
*
* count = PL_DHashTableEnumerate(table, etor, arg);
*
* PL_DHashTableEnumerate calls etor like so:
*
* op = etor(table, entry, number, arg);
*
* where number is a zero-based ordinal assigned to live entries according to
* their order in aTable->entryStore.
*
* The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT,
* then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via
* aTable->ops->clearEntry) and free entry. Then we check whether op contains
* PL_DHASH_STOP; if so, stop enumerating and return the number of live entries
* that were enumerated so far. Return the total number of live entries when
* enumeration completes normally.
*
* If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it
* must return PL_DHASH_STOP; otherwise undefined behavior results.
*
* If any enumerator returns PL_DHASH_REMOVE, aTable->entryStore may be shrunk
* or compressed after enumeration, but before PL_DHashTableEnumerate returns.
* Such an enumerator therefore can't safely set aside entry pointers, but an
* enumerator that never returns PL_DHASH_REMOVE can set pointers to entries
* aside, e.g., to avoid copying live entries into an array of the entry type.
* Copying entry pointers is cheaper, and safe so long as the caller of such a
* "stable" Enumerate doesn't use the set-aside pointers after any call either
* to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might
* grow or shrink entryStore.
*
* If your enumerator wants to remove certain entries, but set aside pointers
* to other entries that it retains, it can use PL_DHashTableRawRemove on the
* entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if
* you want to remove entries, but for some reason you do not want entryStore
* to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on
* the entry being enumerated, rather than returning PL_DHASH_REMOVE.
*/
typedef PLDHashOperator (*PLDHashEnumerator)(PLDHashTable* aTable,
PLDHashEntryHdr* aHdr,
uint32_t aNumber, void* aArg);
NS_COM_GLUE uint32_t
PL_DHashTableEnumerate(PLDHashTable* aTable, PLDHashEnumerator aEtor,
void* aArg);
typedef size_t (*PLDHashSizeOfEntryExcludingThisFun)(
PLDHashEntryHdr* aHdr, mozilla::MallocSizeOf aMallocSizeOf, void* aArg);
/**
* Measure the size of the table's entry storage, and if
* |aSizeOfEntryExcludingThis| is non-nullptr, measure the size of things