зеркало из https://github.com/mozilla/pjs.git
Reduce allocation overhead in ConflictSet; lazily create hashtable in MatchSet. NOT YET IN THE BUILD.
This commit is contained in:
Родитель
30f12a7c0a
Коммит
18579e1b8c
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
TO DO
|
TO DO
|
||||||
|
|
||||||
|
. fix ContentTagTest's location in the network contruction
|
||||||
. use arenas
|
. use arenas
|
||||||
. extended template syntax
|
. extended template syntax
|
||||||
|
|
||||||
|
@ -406,6 +407,8 @@ protected:
|
||||||
const Match* right = NS_STATIC_CAST(const Match*, aRight);
|
const Match* right = NS_STATIC_CAST(const Match*, aRight);
|
||||||
return *left == *right; }
|
return *left == *right; }
|
||||||
|
|
||||||
|
enum { kHashTableThreshold = 8 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Iterator;
|
class Iterator;
|
||||||
|
|
||||||
|
@ -522,16 +525,7 @@ MatchSet::MatchSet()
|
||||||
: mMatches(nsnull), mCount(0)
|
: mMatches(nsnull), mCount(0)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(MatchSet);
|
MOZ_COUNT_CTOR(MatchSet);
|
||||||
|
|
||||||
mHead.mNext = mHead.mPrev = &mHead;
|
mHead.mNext = mHead.mPrev = &mHead;
|
||||||
|
|
||||||
// XXXwaterson create this lazily if we exceed a threshold?
|
|
||||||
mMatches = PL_NewHashTable(16,
|
|
||||||
HashMatch,
|
|
||||||
CompareMatches,
|
|
||||||
PL_CompareValues,
|
|
||||||
nsnull /* XXXwaterson use an arena */,
|
|
||||||
nsnull);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
||||||
|
@ -541,13 +535,12 @@ void MatchSet::operator=(const MatchSet& aMatchSet) {}
|
||||||
|
|
||||||
MatchSet::~MatchSet()
|
MatchSet::~MatchSet()
|
||||||
{
|
{
|
||||||
// XXXwaterson if it's worth it, do a hand rolled cleanup routine
|
if (mMatches) {
|
||||||
// that avoids de-hashing n' stuff.
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
if (mMatches)
|
|
||||||
PL_HashTableDestroy(mMatches);
|
PL_HashTableDestroy(mMatches);
|
||||||
|
mMatches = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clear();
|
||||||
MOZ_COUNT_DTOR(MatchSet);
|
MOZ_COUNT_DTOR(MatchSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +548,20 @@ MatchSet::~MatchSet()
|
||||||
MatchSet::Iterator
|
MatchSet::Iterator
|
||||||
MatchSet::Insert(Iterator aIterator, const Match& aMatch)
|
MatchSet::Insert(Iterator aIterator, const Match& aMatch)
|
||||||
{
|
{
|
||||||
|
if (++mCount > kHashTableThreshold && !mMatches) {
|
||||||
|
// If we've exceeded a high-water mark, then hash everything.
|
||||||
|
mMatches = PL_NewHashTable(2 * kHashTableThreshold,
|
||||||
|
HashMatch,
|
||||||
|
CompareMatches,
|
||||||
|
PL_CompareValues,
|
||||||
|
nsnull /* XXXwaterson use an arena */,
|
||||||
|
nsnull);
|
||||||
|
|
||||||
|
Iterator last = Last();
|
||||||
|
for (Iterator match = First(); match != last; ++match)
|
||||||
|
PL_HashTableAdd(mMatches, &*match, &*match);
|
||||||
|
}
|
||||||
|
|
||||||
MatchList* newelement = new MatchList();
|
MatchList* newelement = new MatchList();
|
||||||
if (newelement) {
|
if (newelement) {
|
||||||
newelement->mMatch = aMatch;
|
newelement->mMatch = aMatch;
|
||||||
|
@ -585,7 +592,18 @@ PRBool
|
||||||
MatchSet::Contains(const Rule* aRule, const Instantiation& aInstantiation) const
|
MatchSet::Contains(const Rule* aRule, const Instantiation& aInstantiation) const
|
||||||
{
|
{
|
||||||
Match match(aRule, aInstantiation);
|
Match match(aRule, aInstantiation);
|
||||||
return PL_HashTableLookup(mMatches, &match) != nsnull;
|
if (mMatches) {
|
||||||
|
return PL_HashTableLookup(mMatches, &match) != nsnull;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ConstIterator last = Last();
|
||||||
|
for (ConstIterator i = First(); i != last; ++i) {
|
||||||
|
if (*i == match)
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -611,6 +629,8 @@ MatchSet::Erase(Iterator aIterator)
|
||||||
{
|
{
|
||||||
Iterator result = aIterator;
|
Iterator result = aIterator;
|
||||||
|
|
||||||
|
--mCount;
|
||||||
|
|
||||||
if (mMatches)
|
if (mMatches)
|
||||||
PL_HashTableRemove(mMatches, &*aIterator);
|
PL_HashTableRemove(mMatches, &*aIterator);
|
||||||
|
|
||||||
|
@ -902,40 +922,167 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
nsresult Init();
|
||||||
|
nsresult Destroy();
|
||||||
|
|
||||||
// "Clusters" of matched rules for the same <content, member> pair
|
// "Clusters" of matched rules for the same <content, member> pair
|
||||||
PLHashTable* mMatches;
|
PLHashTable* mMatches;
|
||||||
|
|
||||||
static PRIntn RemoveMatch(PLHashEntry* he, PRIntn i, void* arg);
|
class MatchEntry {
|
||||||
|
public:
|
||||||
|
MatchEntry() { MOZ_COUNT_CTOR(ConflictSet::MatchEntry); }
|
||||||
|
~MatchEntry() { MOZ_COUNT_DTOR(ConflictSet::MatchEntry); }
|
||||||
|
|
||||||
|
struct PLHashEntry mHashEntry;
|
||||||
|
Key mKey;
|
||||||
|
MatchSet mMatchSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PLHashAllocOps gMatchAllocOps;
|
||||||
|
static void* PR_CALLBACK AllocMatchTable(void* aPool, PRSize aSize);
|
||||||
|
static void PR_CALLBACK FreeMatchTable(void* aPool, void* aItem);
|
||||||
|
static PLHashEntry* PR_CALLBACK AllocMatchEntry(void* aPool, const void* aKey);
|
||||||
|
static void PR_CALLBACK FreeMatchEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag);
|
||||||
|
|
||||||
// Maps an Instantiation::Binding to a MatchSet
|
// Maps an Instantiation::Binding to a MatchSet
|
||||||
PLHashTable* mBindings;
|
PLHashTable* mBindings;
|
||||||
|
|
||||||
|
class BindingEntry {
|
||||||
|
public:
|
||||||
|
BindingEntry() : mElement(nsnull)
|
||||||
|
{ MOZ_COUNT_CTOR(ConflictSet::BindingEntry); }
|
||||||
|
|
||||||
|
~BindingEntry() {
|
||||||
|
delete mElement;
|
||||||
|
MOZ_COUNT_DTOR(ConflictSet::BindingEntry); }
|
||||||
|
|
||||||
|
struct PLHashEntry mHashEntry;
|
||||||
|
MemoryElement* mElement;
|
||||||
|
MatchSet mMatchSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PLHashAllocOps gBindingAllocOps;
|
||||||
|
static void* PR_CALLBACK AllocBindingTable(void* aPool, PRSize aSize);
|
||||||
|
static void PR_CALLBACK FreeBindingTable(void* aPool, void* aItem);
|
||||||
|
static PLHashEntry* PR_CALLBACK AllocBindingEntry(void* aPool, const void* aKey);
|
||||||
|
static void PR_CALLBACK FreeBindingEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag);
|
||||||
|
|
||||||
static PLHashNumber HashMemoryElement(const void* aBinding);
|
static PLHashNumber HashMemoryElement(const void* aBinding);
|
||||||
static PRIntn CompareMemoryElements(const void* aLeft, const void* aRight);
|
static PRIntn CompareMemoryElements(const void* aLeft, const void* aRight);
|
||||||
static PRIntn RemoveMemoryElement(PLHashEntry* he, PRIntn i, void* arg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allocation operations for the match table
|
||||||
|
PLHashAllocOps ConflictSet::gMatchAllocOps = {
|
||||||
|
AllocMatchTable, FreeMatchTable, AllocMatchEntry, FreeMatchEntry };
|
||||||
|
|
||||||
|
|
||||||
|
void* PR_CALLBACK
|
||||||
|
ConflictSet::AllocMatchTable(void* aPool, PRSize aSize)
|
||||||
|
{
|
||||||
|
return new char[aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeMatchTable(void* aPool, void* aItem)
|
||||||
|
{
|
||||||
|
delete[] NS_STATIC_CAST(char*, aItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLHashEntry* PR_CALLBACK
|
||||||
|
ConflictSet::AllocMatchEntry(void* aPool, const void* aKey)
|
||||||
|
{
|
||||||
|
MatchEntry* entry = new MatchEntry();
|
||||||
|
if (! entry)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
entry->mKey = *NS_STATIC_CAST(const Key*, aKey);
|
||||||
|
return NS_REINTERPRET_CAST(PLHashEntry*, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeMatchEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag)
|
||||||
|
{
|
||||||
|
MatchEntry* entry = NS_REINTERPRET_CAST(MatchEntry*, aHashEntry);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocation operations for the bindings table
|
||||||
|
PLHashAllocOps ConflictSet::gBindingAllocOps = {
|
||||||
|
AllocBindingTable, FreeBindingTable, AllocBindingEntry, FreeBindingEntry };
|
||||||
|
|
||||||
|
|
||||||
|
void* PR_CALLBACK
|
||||||
|
ConflictSet::AllocBindingTable(void* aPool, PRSize aSize)
|
||||||
|
{
|
||||||
|
return new char[aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeBindingTable(void* aPool, void* aItem)
|
||||||
|
{
|
||||||
|
delete[] NS_STATIC_CAST(char*, aItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLHashEntry* PR_CALLBACK
|
||||||
|
ConflictSet::AllocBindingEntry(void* aPool, const void* aKey)
|
||||||
|
{
|
||||||
|
BindingEntry* entry = new BindingEntry();
|
||||||
|
if (! entry)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
const MemoryElement* element = NS_STATIC_CAST(const MemoryElement*, aKey);
|
||||||
|
entry->mElement = element->Clone();
|
||||||
|
|
||||||
|
return NS_REINTERPRET_CAST(PLHashEntry*, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeBindingEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag)
|
||||||
|
{
|
||||||
|
BindingEntry* entry = NS_REINTERPRET_CAST(BindingEntry*, aHashEntry);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ConflictSet::ConflictSet()
|
ConflictSet::ConflictSet()
|
||||||
: mMatches(nsnull), mBindings(nsnull)
|
: mMatches(nsnull), mBindings(nsnull)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConflictSet::~ConflictSet()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
ConflictSet::Init()
|
||||||
{
|
{
|
||||||
mMatches = PL_NewHashTable(16 /* XXXwaterson we need a way to give a hint? */,
|
mMatches = PL_NewHashTable(16 /* XXXwaterson we need a way to give a hint? */,
|
||||||
Key::Hash,
|
Key::Hash,
|
||||||
Key::Compare,
|
Key::Compare,
|
||||||
PL_CompareValues,
|
PL_CompareValues,
|
||||||
nsnull /* XXXwaterson use an arena */,
|
&gMatchAllocOps,
|
||||||
nsnull);
|
nsnull /* XXXwaterson use an arena */);
|
||||||
|
|
||||||
mBindings = PL_NewHashTable(16, /* XXXwaterson need hint */
|
mBindings = PL_NewHashTable(16, /* XXXwaterson need hint */
|
||||||
HashMemoryElement,
|
HashMemoryElement,
|
||||||
CompareMemoryElements,
|
CompareMemoryElements,
|
||||||
PL_CompareValues,
|
PL_CompareValues,
|
||||||
nsnull /* XXXwaterson use an arena */,
|
&gBindingAllocOps,
|
||||||
nsnull);
|
nsnull /* XXXwaterson use an arena */);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConflictSet::~ConflictSet()
|
|
||||||
|
nsresult
|
||||||
|
ConflictSet::Destroy()
|
||||||
{
|
{
|
||||||
Clear();
|
PL_HashTableDestroy(mBindings);
|
||||||
|
PL_HashTableDestroy(mMatches);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -954,15 +1101,20 @@ ConflictSet::Add(const Instantiation& aInstantiation, const Rule* aRule)
|
||||||
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Key* newkey = new Key(key);
|
PLHashEntry* he = PL_HashTableRawAdd(mMatches, hep, hash, &key, nsnull);
|
||||||
if (! newkey)
|
if (! he)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
set = new MatchSet();
|
MatchEntry* entry = NS_REINTERPRET_CAST(MatchEntry*, he);
|
||||||
if (! set)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
PL_HashTableRawAdd(mMatches, hep, hash, newkey, set);
|
// Fixup the key in the hashentry to point to the value
|
||||||
|
// that the specially-allocated entry contains (rather
|
||||||
|
// than the value on the stack). Do the same for its
|
||||||
|
// value.
|
||||||
|
entry->mHashEntry.key = &entry->mKey;
|
||||||
|
entry->mHashEntry.value = &entry->mMatchSet;
|
||||||
|
|
||||||
|
set = &entry->mMatchSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! set->Contains(aRule, aInstantiation)) {
|
if (! set->Contains(aRule, aInstantiation)) {
|
||||||
|
@ -984,15 +1136,17 @@ ConflictSet::Add(const Instantiation& aInstantiation, const Rule* aRule)
|
||||||
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MemoryElement* keyelement = element->Clone();
|
PLHashEntry* he = PL_HashTableRawAdd(mBindings, hep, hash, &*element, nsnull);
|
||||||
if (! keyelement)
|
|
||||||
|
BindingEntry* entry = NS_REINTERPRET_CAST(BindingEntry*, he);
|
||||||
|
if (! entry)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
set = new MatchSet();
|
// Fixup the key and value.
|
||||||
if (! set)
|
entry->mHashEntry.key = entry->mElement;
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
entry->mHashEntry.value = &entry->mMatchSet;
|
||||||
|
|
||||||
PL_HashTableRawAdd(mBindings, hep, hash, keyelement, set);
|
set = &entry->mMatchSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! set->Contains(aRule, aInstantiation)) {
|
if (! set->Contains(aRule, aInstantiation)) {
|
||||||
|
@ -1047,13 +1201,6 @@ ConflictSet::Remove(const MemoryElement& aMemoryElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll eagerly remove it from the table.
|
// We'll eagerly remove it from the table.
|
||||||
MemoryElement* key =
|
|
||||||
NS_STATIC_CAST(MemoryElement*,
|
|
||||||
NS_CONST_CAST(void*, (*hep)->key));
|
|
||||||
|
|
||||||
delete key;
|
|
||||||
delete set;
|
|
||||||
|
|
||||||
PL_HashTableRawRemove(mBindings, hep, *hep);
|
PL_HashTableRawRemove(mBindings, hep, *hep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,53 +1235,17 @@ ConflictSet::Remove(const MemoryElement& aMemoryElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set->Empty()) {
|
if (set->Empty()) {
|
||||||
Key* hashkey = NS_STATIC_CAST(Key*, NS_CONST_CAST(void*, (*hep)->key));
|
|
||||||
delete hashkey;
|
|
||||||
delete set;
|
|
||||||
|
|
||||||
PL_HashTableRawRemove(mMatches, hep, *hep);
|
PL_HashTableRawRemove(mMatches, hep, *hep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PRIntn
|
|
||||||
ConflictSet::RemoveMemoryElement(PLHashEntry* he, PRIntn, void*)
|
|
||||||
{
|
|
||||||
MemoryElement* element =
|
|
||||||
NS_STATIC_CAST(MemoryElement*, NS_CONST_CAST(void*, he->key));
|
|
||||||
|
|
||||||
delete element;
|
|
||||||
|
|
||||||
MatchSet* matches =
|
|
||||||
NS_STATIC_CAST(MatchSet*, he->value);
|
|
||||||
|
|
||||||
delete matches;
|
|
||||||
|
|
||||||
return HT_ENUMERATE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PRIntn
|
|
||||||
ConflictSet::RemoveMatch(PLHashEntry* he, PRIntn, void*)
|
|
||||||
{
|
|
||||||
Key* key = NS_STATIC_CAST(Key*, NS_CONST_CAST(void*, he->key));
|
|
||||||
|
|
||||||
delete key;
|
|
||||||
|
|
||||||
MatchSet* matches =
|
|
||||||
NS_STATIC_CAST(MatchSet*, he->value);
|
|
||||||
|
|
||||||
delete matches;
|
|
||||||
|
|
||||||
return HT_ENUMERATE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ConflictSet::Clear()
|
ConflictSet::Clear()
|
||||||
{
|
{
|
||||||
PL_HashTableEnumerateEntries(mBindings, RemoveMemoryElement, nsnull);
|
Destroy();
|
||||||
PL_HashTableEnumerateEntries(mMatches, RemoveMatch, nsnull);
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
PLHashNumber
|
PLHashNumber
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
TO DO
|
TO DO
|
||||||
|
|
||||||
|
. fix ContentTagTest's location in the network contruction
|
||||||
. use arenas
|
. use arenas
|
||||||
. extended template syntax
|
. extended template syntax
|
||||||
|
|
||||||
|
@ -406,6 +407,8 @@ protected:
|
||||||
const Match* right = NS_STATIC_CAST(const Match*, aRight);
|
const Match* right = NS_STATIC_CAST(const Match*, aRight);
|
||||||
return *left == *right; }
|
return *left == *right; }
|
||||||
|
|
||||||
|
enum { kHashTableThreshold = 8 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Iterator;
|
class Iterator;
|
||||||
|
|
||||||
|
@ -522,16 +525,7 @@ MatchSet::MatchSet()
|
||||||
: mMatches(nsnull), mCount(0)
|
: mMatches(nsnull), mCount(0)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(MatchSet);
|
MOZ_COUNT_CTOR(MatchSet);
|
||||||
|
|
||||||
mHead.mNext = mHead.mPrev = &mHead;
|
mHead.mNext = mHead.mPrev = &mHead;
|
||||||
|
|
||||||
// XXXwaterson create this lazily if we exceed a threshold?
|
|
||||||
mMatches = PL_NewHashTable(16,
|
|
||||||
HashMatch,
|
|
||||||
CompareMatches,
|
|
||||||
PL_CompareValues,
|
|
||||||
nsnull /* XXXwaterson use an arena */,
|
|
||||||
nsnull);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
||||||
|
@ -541,13 +535,12 @@ void MatchSet::operator=(const MatchSet& aMatchSet) {}
|
||||||
|
|
||||||
MatchSet::~MatchSet()
|
MatchSet::~MatchSet()
|
||||||
{
|
{
|
||||||
// XXXwaterson if it's worth it, do a hand rolled cleanup routine
|
if (mMatches) {
|
||||||
// that avoids de-hashing n' stuff.
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
if (mMatches)
|
|
||||||
PL_HashTableDestroy(mMatches);
|
PL_HashTableDestroy(mMatches);
|
||||||
|
mMatches = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clear();
|
||||||
MOZ_COUNT_DTOR(MatchSet);
|
MOZ_COUNT_DTOR(MatchSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,6 +548,20 @@ MatchSet::~MatchSet()
|
||||||
MatchSet::Iterator
|
MatchSet::Iterator
|
||||||
MatchSet::Insert(Iterator aIterator, const Match& aMatch)
|
MatchSet::Insert(Iterator aIterator, const Match& aMatch)
|
||||||
{
|
{
|
||||||
|
if (++mCount > kHashTableThreshold && !mMatches) {
|
||||||
|
// If we've exceeded a high-water mark, then hash everything.
|
||||||
|
mMatches = PL_NewHashTable(2 * kHashTableThreshold,
|
||||||
|
HashMatch,
|
||||||
|
CompareMatches,
|
||||||
|
PL_CompareValues,
|
||||||
|
nsnull /* XXXwaterson use an arena */,
|
||||||
|
nsnull);
|
||||||
|
|
||||||
|
Iterator last = Last();
|
||||||
|
for (Iterator match = First(); match != last; ++match)
|
||||||
|
PL_HashTableAdd(mMatches, &*match, &*match);
|
||||||
|
}
|
||||||
|
|
||||||
MatchList* newelement = new MatchList();
|
MatchList* newelement = new MatchList();
|
||||||
if (newelement) {
|
if (newelement) {
|
||||||
newelement->mMatch = aMatch;
|
newelement->mMatch = aMatch;
|
||||||
|
@ -585,7 +592,18 @@ PRBool
|
||||||
MatchSet::Contains(const Rule* aRule, const Instantiation& aInstantiation) const
|
MatchSet::Contains(const Rule* aRule, const Instantiation& aInstantiation) const
|
||||||
{
|
{
|
||||||
Match match(aRule, aInstantiation);
|
Match match(aRule, aInstantiation);
|
||||||
return PL_HashTableLookup(mMatches, &match) != nsnull;
|
if (mMatches) {
|
||||||
|
return PL_HashTableLookup(mMatches, &match) != nsnull;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ConstIterator last = Last();
|
||||||
|
for (ConstIterator i = First(); i != last; ++i) {
|
||||||
|
if (*i == match)
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -611,6 +629,8 @@ MatchSet::Erase(Iterator aIterator)
|
||||||
{
|
{
|
||||||
Iterator result = aIterator;
|
Iterator result = aIterator;
|
||||||
|
|
||||||
|
--mCount;
|
||||||
|
|
||||||
if (mMatches)
|
if (mMatches)
|
||||||
PL_HashTableRemove(mMatches, &*aIterator);
|
PL_HashTableRemove(mMatches, &*aIterator);
|
||||||
|
|
||||||
|
@ -902,40 +922,167 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
nsresult Init();
|
||||||
|
nsresult Destroy();
|
||||||
|
|
||||||
// "Clusters" of matched rules for the same <content, member> pair
|
// "Clusters" of matched rules for the same <content, member> pair
|
||||||
PLHashTable* mMatches;
|
PLHashTable* mMatches;
|
||||||
|
|
||||||
static PRIntn RemoveMatch(PLHashEntry* he, PRIntn i, void* arg);
|
class MatchEntry {
|
||||||
|
public:
|
||||||
|
MatchEntry() { MOZ_COUNT_CTOR(ConflictSet::MatchEntry); }
|
||||||
|
~MatchEntry() { MOZ_COUNT_DTOR(ConflictSet::MatchEntry); }
|
||||||
|
|
||||||
|
struct PLHashEntry mHashEntry;
|
||||||
|
Key mKey;
|
||||||
|
MatchSet mMatchSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PLHashAllocOps gMatchAllocOps;
|
||||||
|
static void* PR_CALLBACK AllocMatchTable(void* aPool, PRSize aSize);
|
||||||
|
static void PR_CALLBACK FreeMatchTable(void* aPool, void* aItem);
|
||||||
|
static PLHashEntry* PR_CALLBACK AllocMatchEntry(void* aPool, const void* aKey);
|
||||||
|
static void PR_CALLBACK FreeMatchEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag);
|
||||||
|
|
||||||
// Maps an Instantiation::Binding to a MatchSet
|
// Maps an Instantiation::Binding to a MatchSet
|
||||||
PLHashTable* mBindings;
|
PLHashTable* mBindings;
|
||||||
|
|
||||||
|
class BindingEntry {
|
||||||
|
public:
|
||||||
|
BindingEntry() : mElement(nsnull)
|
||||||
|
{ MOZ_COUNT_CTOR(ConflictSet::BindingEntry); }
|
||||||
|
|
||||||
|
~BindingEntry() {
|
||||||
|
delete mElement;
|
||||||
|
MOZ_COUNT_DTOR(ConflictSet::BindingEntry); }
|
||||||
|
|
||||||
|
struct PLHashEntry mHashEntry;
|
||||||
|
MemoryElement* mElement;
|
||||||
|
MatchSet mMatchSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PLHashAllocOps gBindingAllocOps;
|
||||||
|
static void* PR_CALLBACK AllocBindingTable(void* aPool, PRSize aSize);
|
||||||
|
static void PR_CALLBACK FreeBindingTable(void* aPool, void* aItem);
|
||||||
|
static PLHashEntry* PR_CALLBACK AllocBindingEntry(void* aPool, const void* aKey);
|
||||||
|
static void PR_CALLBACK FreeBindingEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag);
|
||||||
|
|
||||||
static PLHashNumber HashMemoryElement(const void* aBinding);
|
static PLHashNumber HashMemoryElement(const void* aBinding);
|
||||||
static PRIntn CompareMemoryElements(const void* aLeft, const void* aRight);
|
static PRIntn CompareMemoryElements(const void* aLeft, const void* aRight);
|
||||||
static PRIntn RemoveMemoryElement(PLHashEntry* he, PRIntn i, void* arg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allocation operations for the match table
|
||||||
|
PLHashAllocOps ConflictSet::gMatchAllocOps = {
|
||||||
|
AllocMatchTable, FreeMatchTable, AllocMatchEntry, FreeMatchEntry };
|
||||||
|
|
||||||
|
|
||||||
|
void* PR_CALLBACK
|
||||||
|
ConflictSet::AllocMatchTable(void* aPool, PRSize aSize)
|
||||||
|
{
|
||||||
|
return new char[aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeMatchTable(void* aPool, void* aItem)
|
||||||
|
{
|
||||||
|
delete[] NS_STATIC_CAST(char*, aItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLHashEntry* PR_CALLBACK
|
||||||
|
ConflictSet::AllocMatchEntry(void* aPool, const void* aKey)
|
||||||
|
{
|
||||||
|
MatchEntry* entry = new MatchEntry();
|
||||||
|
if (! entry)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
entry->mKey = *NS_STATIC_CAST(const Key*, aKey);
|
||||||
|
return NS_REINTERPRET_CAST(PLHashEntry*, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeMatchEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag)
|
||||||
|
{
|
||||||
|
MatchEntry* entry = NS_REINTERPRET_CAST(MatchEntry*, aHashEntry);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocation operations for the bindings table
|
||||||
|
PLHashAllocOps ConflictSet::gBindingAllocOps = {
|
||||||
|
AllocBindingTable, FreeBindingTable, AllocBindingEntry, FreeBindingEntry };
|
||||||
|
|
||||||
|
|
||||||
|
void* PR_CALLBACK
|
||||||
|
ConflictSet::AllocBindingTable(void* aPool, PRSize aSize)
|
||||||
|
{
|
||||||
|
return new char[aSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeBindingTable(void* aPool, void* aItem)
|
||||||
|
{
|
||||||
|
delete[] NS_STATIC_CAST(char*, aItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLHashEntry* PR_CALLBACK
|
||||||
|
ConflictSet::AllocBindingEntry(void* aPool, const void* aKey)
|
||||||
|
{
|
||||||
|
BindingEntry* entry = new BindingEntry();
|
||||||
|
if (! entry)
|
||||||
|
return nsnull;
|
||||||
|
|
||||||
|
const MemoryElement* element = NS_STATIC_CAST(const MemoryElement*, aKey);
|
||||||
|
entry->mElement = element->Clone();
|
||||||
|
|
||||||
|
return NS_REINTERPRET_CAST(PLHashEntry*, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_CALLBACK
|
||||||
|
ConflictSet::FreeBindingEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag)
|
||||||
|
{
|
||||||
|
BindingEntry* entry = NS_REINTERPRET_CAST(BindingEntry*, aHashEntry);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ConflictSet::ConflictSet()
|
ConflictSet::ConflictSet()
|
||||||
: mMatches(nsnull), mBindings(nsnull)
|
: mMatches(nsnull), mBindings(nsnull)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConflictSet::~ConflictSet()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
ConflictSet::Init()
|
||||||
{
|
{
|
||||||
mMatches = PL_NewHashTable(16 /* XXXwaterson we need a way to give a hint? */,
|
mMatches = PL_NewHashTable(16 /* XXXwaterson we need a way to give a hint? */,
|
||||||
Key::Hash,
|
Key::Hash,
|
||||||
Key::Compare,
|
Key::Compare,
|
||||||
PL_CompareValues,
|
PL_CompareValues,
|
||||||
nsnull /* XXXwaterson use an arena */,
|
&gMatchAllocOps,
|
||||||
nsnull);
|
nsnull /* XXXwaterson use an arena */);
|
||||||
|
|
||||||
mBindings = PL_NewHashTable(16, /* XXXwaterson need hint */
|
mBindings = PL_NewHashTable(16, /* XXXwaterson need hint */
|
||||||
HashMemoryElement,
|
HashMemoryElement,
|
||||||
CompareMemoryElements,
|
CompareMemoryElements,
|
||||||
PL_CompareValues,
|
PL_CompareValues,
|
||||||
nsnull /* XXXwaterson use an arena */,
|
&gBindingAllocOps,
|
||||||
nsnull);
|
nsnull /* XXXwaterson use an arena */);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConflictSet::~ConflictSet()
|
|
||||||
|
nsresult
|
||||||
|
ConflictSet::Destroy()
|
||||||
{
|
{
|
||||||
Clear();
|
PL_HashTableDestroy(mBindings);
|
||||||
|
PL_HashTableDestroy(mMatches);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -954,15 +1101,20 @@ ConflictSet::Add(const Instantiation& aInstantiation, const Rule* aRule)
|
||||||
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Key* newkey = new Key(key);
|
PLHashEntry* he = PL_HashTableRawAdd(mMatches, hep, hash, &key, nsnull);
|
||||||
if (! newkey)
|
if (! he)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
set = new MatchSet();
|
MatchEntry* entry = NS_REINTERPRET_CAST(MatchEntry*, he);
|
||||||
if (! set)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
PL_HashTableRawAdd(mMatches, hep, hash, newkey, set);
|
// Fixup the key in the hashentry to point to the value
|
||||||
|
// that the specially-allocated entry contains (rather
|
||||||
|
// than the value on the stack). Do the same for its
|
||||||
|
// value.
|
||||||
|
entry->mHashEntry.key = &entry->mKey;
|
||||||
|
entry->mHashEntry.value = &entry->mMatchSet;
|
||||||
|
|
||||||
|
set = &entry->mMatchSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! set->Contains(aRule, aInstantiation)) {
|
if (! set->Contains(aRule, aInstantiation)) {
|
||||||
|
@ -984,15 +1136,17 @@ ConflictSet::Add(const Instantiation& aInstantiation, const Rule* aRule)
|
||||||
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
set = NS_STATIC_CAST(MatchSet*, (*hep)->value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MemoryElement* keyelement = element->Clone();
|
PLHashEntry* he = PL_HashTableRawAdd(mBindings, hep, hash, &*element, nsnull);
|
||||||
if (! keyelement)
|
|
||||||
|
BindingEntry* entry = NS_REINTERPRET_CAST(BindingEntry*, he);
|
||||||
|
if (! entry)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
set = new MatchSet();
|
// Fixup the key and value.
|
||||||
if (! set)
|
entry->mHashEntry.key = entry->mElement;
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
entry->mHashEntry.value = &entry->mMatchSet;
|
||||||
|
|
||||||
PL_HashTableRawAdd(mBindings, hep, hash, keyelement, set);
|
set = &entry->mMatchSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! set->Contains(aRule, aInstantiation)) {
|
if (! set->Contains(aRule, aInstantiation)) {
|
||||||
|
@ -1047,13 +1201,6 @@ ConflictSet::Remove(const MemoryElement& aMemoryElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll eagerly remove it from the table.
|
// We'll eagerly remove it from the table.
|
||||||
MemoryElement* key =
|
|
||||||
NS_STATIC_CAST(MemoryElement*,
|
|
||||||
NS_CONST_CAST(void*, (*hep)->key));
|
|
||||||
|
|
||||||
delete key;
|
|
||||||
delete set;
|
|
||||||
|
|
||||||
PL_HashTableRawRemove(mBindings, hep, *hep);
|
PL_HashTableRawRemove(mBindings, hep, *hep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,53 +1235,17 @@ ConflictSet::Remove(const MemoryElement& aMemoryElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set->Empty()) {
|
if (set->Empty()) {
|
||||||
Key* hashkey = NS_STATIC_CAST(Key*, NS_CONST_CAST(void*, (*hep)->key));
|
|
||||||
delete hashkey;
|
|
||||||
delete set;
|
|
||||||
|
|
||||||
PL_HashTableRawRemove(mMatches, hep, *hep);
|
PL_HashTableRawRemove(mMatches, hep, *hep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PRIntn
|
|
||||||
ConflictSet::RemoveMemoryElement(PLHashEntry* he, PRIntn, void*)
|
|
||||||
{
|
|
||||||
MemoryElement* element =
|
|
||||||
NS_STATIC_CAST(MemoryElement*, NS_CONST_CAST(void*, he->key));
|
|
||||||
|
|
||||||
delete element;
|
|
||||||
|
|
||||||
MatchSet* matches =
|
|
||||||
NS_STATIC_CAST(MatchSet*, he->value);
|
|
||||||
|
|
||||||
delete matches;
|
|
||||||
|
|
||||||
return HT_ENUMERATE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PRIntn
|
|
||||||
ConflictSet::RemoveMatch(PLHashEntry* he, PRIntn, void*)
|
|
||||||
{
|
|
||||||
Key* key = NS_STATIC_CAST(Key*, NS_CONST_CAST(void*, he->key));
|
|
||||||
|
|
||||||
delete key;
|
|
||||||
|
|
||||||
MatchSet* matches =
|
|
||||||
NS_STATIC_CAST(MatchSet*, he->value);
|
|
||||||
|
|
||||||
delete matches;
|
|
||||||
|
|
||||||
return HT_ENUMERATE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ConflictSet::Clear()
|
ConflictSet::Clear()
|
||||||
{
|
{
|
||||||
PL_HashTableEnumerateEntries(mBindings, RemoveMemoryElement, nsnull);
|
Destroy();
|
||||||
PL_HashTableEnumerateEntries(mMatches, RemoveMatch, nsnull);
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
PLHashNumber
|
PLHashNumber
|
||||||
|
|
Загрузка…
Ссылка в новой задаче