Bug 1438732 - Use nsClassHashtable for prefs hashtable. r=njn

--HG--
extra : rebase_source : a17b9490b6d52d2ed4e510f27a2410f56724f861
This commit is contained in:
Eric Rahm 2018-02-15 16:43:32 -08:00
parent 1b9bcc15aa
commit cbfd16320a

View File

@ -326,9 +326,8 @@ static ArenaAllocator<8192, 1> gPrefNameArena;
class Pref
{
public:
explicit Pref(const char* aName)
: mName(ArenaStrdup(aName, gPrefNameArena))
, mType(static_cast<uint32_t>(PrefType::None))
explicit Pref()
: mType(static_cast<uint32_t>(PrefType::None))
, mIsSticky(false)
, mIsLocked(false)
, mHasDefaultValue(false)
@ -341,15 +340,10 @@ public:
~Pref()
{
// There's no need to free mName because it's allocated in memory owned by
// gPrefNameArena.
mDefaultValue.Clear(Type());
mUserValue.Clear(Type());
}
const char* Name() { return mName; }
// Types.
PrefType Type() const { return static_cast<PrefType>(mType); }
@ -401,15 +395,6 @@ public:
// Other operations.
bool MatchEntry(const char* aPrefName)
{
if (!mName || !aPrefName) {
return false;
}
return strcmp(mName, aPrefName) == 0;
}
nsresult GetBoolValue(PrefValueKind aKind, bool* aResult)
{
if (!IsTypeBool()) {
@ -469,11 +454,16 @@ public:
return NS_OK;
}
void ToDomPref(dom::Pref* aDomPref)
// Fills out a dom pref with the values from this pref.
// @param aDomPref The pref to update.
// @param aName Optional. Override the dom pref's name with aName.
void ToDomPref(dom::Pref* aDomPref, const char* aName = nullptr)
{
MOZ_ASSERT(XRE_IsParentProcess());
aDomPref->name() = mName;
if (aName) {
aDomPref->name() = aName;
}
aDomPref->isLocked() = mIsLocked;
@ -502,7 +492,6 @@ public:
void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged)
{
MOZ_ASSERT(!XRE_IsParentProcess());
MOZ_ASSERT(strcmp(mName, aDomPref.name().get()) == 0);
mIsLocked = aDomPref.isLocked();
@ -688,7 +677,6 @@ public:
void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
{
// Note: mName is allocated in gPrefNameArena, measured elsewhere.
aSizes.mPrefValues += aMallocSizeOf(this);
if (IsTypeString()) {
if (mHasDefaultValue) {
@ -701,8 +689,6 @@ public:
}
private:
const char* mName; // allocated in gPrefNameArena
uint32_t mType : 2;
uint32_t mIsSticky : 1;
uint32_t mIsLocked : 1;
@ -714,36 +700,6 @@ private:
PrefValue mUserValue;
};
class PrefEntry : public PLDHashEntryHdr
{
public:
Pref* mPref; // Note: this is never null in a live entry.
static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey)
{
auto entry = static_cast<const PrefEntry*>(aEntry);
auto prefName = static_cast<const char*>(aKey);
return entry->mPref->MatchEntry(prefName);
}
static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
{
auto entry = static_cast<PrefEntry*>(aEntry);
auto prefName = static_cast<const char*>(aKey);
entry->mPref = new Pref(prefName);
}
static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
{
auto entry = static_cast<PrefEntry*>(aEntry);
delete entry->mPref;
entry->mPref = nullptr;
}
};
struct CallbackNode
{
CallbackNode(const char* aDomain,
@ -769,7 +725,21 @@ struct CallbackNode
CallbackNode* mNext;
};
static PLDHashTable* gHashTable;
// Hash key that allocates its string from the `gPrefNameArena`. The base class
// `nsDepCharHashKey` does not own the string data and no copies are made.
class StringArenaHashKey : public nsDepCharHashKey
{
public:
explicit StringArenaHashKey(const char* aKey)
: nsDepCharHashKey(ArenaStrdup(aKey, gPrefNameArena))
{
}
};
// Hashtable used to map names to pref objects. StringArenaHashKey is used to
// allocate the strings out of an arena.
using PrefsTable = nsClassHashtable<StringArenaHashKey, Pref>;
static PrefsTable* gHashTable;
// The callback list contains all the priority callbacks followed by the
// non-priority callbacks. gLastPriorityNode records where the first part ends.
@ -782,14 +752,6 @@ static bool gIsAnyPrefLocked = false;
static bool gCallbacksInProgress = false;
static bool gShouldCleanupDeadNodes = false;
static PLDHashTableOps pref_HashTableOps = {
PLDHashTable::HashStringKey,
PrefEntry::MatchEntry,
PLDHashTable::MoveEntryStub,
PrefEntry::ClearEntry,
PrefEntry::InitEntry,
};
static Pref*
pref_HashTableLookup(const char* aPrefName);
@ -803,10 +765,10 @@ pref_savePrefs()
{
MOZ_ASSERT(NS_IsMainThread());
PrefSaveData savedPrefs(gHashTable->EntryCount());
PrefSaveData savedPrefs(gHashTable->Count());
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
Pref* pref = iter.Data();
nsAutoCString prefValueStr;
if (!pref->UserValueToStringForSaving(prefValueStr)) {
@ -814,7 +776,7 @@ pref_savePrefs()
}
nsAutoCString prefNameStr;
StrEscape(pref->Name(), prefNameStr);
StrEscape(iter.Key(), prefNameStr);
nsPrintfCString str(
"user_pref(%s, %s);", prefNameStr.get(), prefValueStr.get());
@ -865,7 +827,7 @@ IsEarlyPref(const char* aPrefName)
#endif // DEBUG
static PrefEntry*
static PrefsTable::LookupResult
pref_HashTableLookupInner(const char* aPrefName)
{
MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
@ -888,14 +850,14 @@ pref_HashTableLookupInner(const char* aPrefName)
}
#endif
return static_cast<PrefEntry*>(gHashTable->Search(aPrefName));
return gHashTable->Lookup(aPrefName);
}
static Pref*
pref_HashTableLookup(const char* aPrefName)
{
PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
return entry ? entry->mPref : nullptr;
PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
return entry ? static_cast<Pref*>(entry.Data()) : nullptr;
}
static nsresult
@ -912,12 +874,7 @@ pref_SetPref(const char* aPrefName,
return NS_ERROR_OUT_OF_MEMORY;
}
auto entry = static_cast<PrefEntry*>(gHashTable->Add(aPrefName, fallible));
if (!entry) {
return NS_ERROR_OUT_OF_MEMORY;
}
Pref* pref = entry->mPref;
Pref* pref = gHashTable->LookupOrAdd(aPrefName);
if (pref->IsTypeNone()) {
// New entry. Set the type.
pref->SetType(aType);
@ -2030,13 +1987,11 @@ nsPrefBranch::DeleteBranch(const char* aStartingAt)
Substring(branchName, 0, branchName.Length() - 1);
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
// The first disjunct matches branches: e.g. a branch name "foo.bar."
// matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz").
// The second disjunct matches leaf nodes: e.g. a branch name "foo.bar."
// matches a name "foo.bar" (by ignoring the trailing '.').
nsDependentCString name(pref->Name());
nsDependentCString name(iter.Key());
if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) {
iter.Remove();
}
@ -2071,9 +2026,8 @@ nsPrefBranch::GetChildList(const char* aStartingAt,
const PrefName& parent = GetPrefName(aStartingAt);
size_t parentLen = parent.Length();
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
if (strncmp(pref->Name(), parent.get(), parentLen) == 0) {
prefArray.AppendElement(pref->Name());
if (strncmp(iter.Key(), parent.get(), parentLen) == 0) {
prefArray.AppendElement(iter.Key());
}
}
@ -2685,7 +2639,7 @@ PreferenceServiceReporter::CollectReports(
if (gHashTable) {
sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf);
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
Pref* pref = iter.Data();
pref->AddSizeOfIncludingThis(mallocSizeOf, sizes);
}
}
@ -2878,8 +2832,7 @@ Preferences::GetInstanceForService()
sPreferences = new Preferences();
MOZ_ASSERT(!gHashTable);
gHashTable = new PLDHashTable(
&pref_HashTableOps, sizeof(PrefEntry), PREF_HASHTABLE_INITIAL_LENGTH);
gHashTable = new PrefsTable(PREF_HASHTABLE_INITIAL_LENGTH);
gTelemetryLoadData =
new nsDataHashtable<nsCStringHashKey, TelemetryLoadData>();
@ -3134,7 +3087,7 @@ Preferences::ResetPrefs()
{
ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs");
gHashTable->ClearAndPrepareForLength(PREF_HASHTABLE_INITIAL_LENGTH);
gHashTable->Clear();
gPrefNameArena.Clear();
return InitInitialObjects().isOk() ? NS_OK : NS_ERROR_FAILURE;
@ -3149,10 +3102,10 @@ Preferences::ResetUserPrefs()
Vector<const char*> prefNames;
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
Pref* pref = iter.Data();
if (pref->HasUserValue()) {
if (!prefNames.append(pref->Name())) {
if (!prefNames.append(iter.Key())) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -3226,12 +3179,7 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
const char* prefName = aDomPref.name().get();
auto entry = static_cast<PrefEntry*>(gHashTable->Add(prefName, fallible));
if (!entry) {
return;
}
Pref* pref = entry->mPref;
Pref* pref = gHashTable->LookupOrAdd(prefName);
bool valueChanged = false;
pref->FromDomPref(aDomPref, &valueChanged);
@ -3247,7 +3195,7 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
// needlessly, but that's ok because this case is rare.
//
if (!pref->HasDefaultValue() && !pref->HasUserValue()) {
gHashTable->RemoveEntry(entry);
gHashTable->Remove(prefName);
}
// Note: we don't have to worry about HandleDirty() because we are setting
@ -3275,9 +3223,9 @@ Preferences::GetPreferences(InfallibleTArray<dom::Pref>* aDomPrefs)
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
aDomPrefs->SetCapacity(gHashTable->EntryCount());
aDomPrefs->SetCapacity(gHashTable->Count());
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
Pref* pref = iter.Data();
if (!pref->MustSendToContentProcesses()) {
// The pref value hasn't changed since it was initialized at startup.
@ -3288,7 +3236,7 @@ Preferences::GetPreferences(InfallibleTArray<dom::Pref>* aDomPrefs)
if (pref->HasAdvisablySizedValues()) {
dom::Pref* setting = aDomPrefs->AppendElement();
pref->ToDomPref(setting);
pref->ToDomPref(setting, iter.Key());
}
}
}
@ -4184,13 +4132,13 @@ Preferences::ClearUserInAnyProcess(const char* aPrefName)
{
NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
PrefsTable::LookupResult entry = pref_HashTableLookupInner(aPrefName);
Pref* pref;
if (entry && (pref = entry->mPref) && pref->HasUserValue()) {
if (entry && (pref = entry.Data()) && pref->HasUserValue()) {
pref->ClearUserValue();
if (!pref->HasDefaultValue()) {
gHashTable->RemoveEntry(entry);
entry.Remove();
}
NotifyCallbacks(aPrefName);