These changes were necessary for me to build successfully with this in my
mozconfig:
ac_add_options --enable-debug
ac_add_options --disable-unified-build
ac_add_options --enable-profiling
While I'm here, I removed a duplicate include in InputTaskManager.h, and made
nsThreadPool.cpp include its own header first, to match Gecko common practice.
Differential Revision: https://phabricator.services.mozilla.com/D127503
xpcom/ds/nsProperties.cpp:56:3: error: use of undeclared identifier 'AppendToArray'; did you mean 'mozilla::AppendToArray'?
xpcom/ds/PLDHashTable.cpp:324:3: error: use of undeclared identifier 'NS_ASSERTION'
xpcom/ds/PLDHashTable.cpp:395:3: error: use of undeclared identifier 'NS_ASSERTION'
xpcom/ds/PLDHashTable.cpp:679:7: error: use of undeclared identifier 'NS_ABORT_OOM'
xpcom/ds/PLDHashTable.cpp:685:7: error: use of undeclared identifier 'NS_ABORT_OOM'
Differential Revision: https://phabricator.services.mozilla.com/D127039
nsBaseHashtable now supports non-default-constructible DataType and
UserDataType, however not all methods can be instantiated. All methods which
can't be instantiated with non-default-constructible DataType or UserDataType
are now described as such in method definitions.
The public API of PLDHashTable and nsBaseHashtable/nsDataHashtable was changed:
- A new method PLDHashTable::WithEntryHandle has been added. It allows to use a
custom function for entry initialization (instead of the global hook).
- A new method nsBaseHashtable::MaybeGet has been added.
- A new overload nsBaseHashtable::Remove has been added.
- The nsDataHashtable::GetAndRemove method has been pulled up to
nsBaseHashtable.
In addition, the following implementation details have changed:
PLDHashTable:
- The code from the Add method has been split into MakeEntryHandle and a helper
object called EntryHandle. The Add method is now implemented on top of that.
nsTHashtable:
- A new (non-public) API for WithEntryHandle has been added.
- The InitEntry hook is no longer used. Instead of using the hook, PutEntry
methods now use nsTHashtable::WithEntryHandle instead of PLDHashTable::Add.
This change allows to do custom initialization in derived classes.
nsBaseHashtable:
- A new (non-public) API for WithEntryHandle has been added.
- Put methods no longer use nsTHashtable::PutEntry, they now use the new method
nsBaseHashtable::WithEntryHandle.
Differential Revision: https://phabricator.services.mozilla.com/D99428
nsBaseHashtable now supports non-default-constructible DataType and
UserDataType, however not all methods can be instantiated. All methods which
can't be instantiated with non-default-constructible DataType or UserDataType
are now described as such in method definitions.
The public API of PLDHashTable and nsBaseHashtable/nsDataHashtable was changed:
- A new method PLDHashTable::WithEntryHandle has been added. It allows to use a
custom function for entry initialization (instead of the global hook).
- A new method nsBaseHashtable::MaybeGet has been added.
- A new overload nsBaseHashtable::Remove has been added.
- The nsDataHashtable::GetAndRemove method has been pulled up to
nsBaseHashtable.
In addition, the following implementation details have changed:
PLDHashTable:
- The code from the Add method has been split into MakeEntryHandle and a helper
object called EntryHandle. The Add method is now implemented on top of that.
nsTHashtable:
- A new (non-public) API for WithEntryHandle has been added.
- The InitEntry hook is no longer used. Instead of using the hook, PutEntry
methods now use nsTHashtable::WithEntryHandle instead of PLDHashTable::Add.
This change allows to do custom initialization in derived classes.
nsBaseHashtable:
- A new (non-public) API for WithEntryHandle has been added.
- Put methods no longer use nsTHashtable::PutEntry, they now use the new method
nsBaseHashtable::WithEntryHandle.
Differential Revision: https://phabricator.services.mozilla.com/D99428
Put them behind a MOZ_HASH_TABLE_CHECKS_ENABLED define, which right now is only
defined in DEBUG builds, preserving behavior.
MakeImmutable becomes an empty inline function when disabled, which should be
zero-cost.
Differential Revision: https://phabricator.services.mozilla.com/D50493
The core loop of Iterator::Next() requires multiple branches, one to
check for entry liveness and one to check for wraparound. We can
rewrite this to use masking instead, as well as iterating only over the
hashes, and reconstructing the entry pointer when we know we've reached
a live entry. This change cuts the time taken on the collections
benchmark by the iteration portion in half.
As discussed in the previous commit message, PLDHashTable's storage
wastes space for common entry types. This commit reorganizes the
storage to store all the hashes packed together, followed by all the
entries, which eliminates said waste.
PLDHashTable requires that all items stored therein inherit from
PLDHashEntryHdr:
struct PLDHashEntryHdr {
// PLDHashNumber is a uint32_t.
PLDHashNumber mKeyHash; // Cached hash key for object.
};
class MyType : public PLDHashEntryHdr {
// Data members, etc.
};
PLDHashEntryHdr::mKeyHash is used to cache the computed hash value of
the entry, so we aren't rehashing entries on every lookup/add/etc.
Because of structure layout requirements on 64-bit platforms, the data
members of MyType will typically start at offset 8:
MyType, offset 0: mKeyHash
MyType, offset 4: padding required by alignment
MyType, offset 8: first data member of MyType
MyType, offset N: ...
The padding at offset 4 is dead, unused space.
We'd like to change this state of affairs by having PLDHashTable manage
the cached hash key itself, which would eliminate the dead space in the
object and would enable packing the table storage more tightly. But
PLDHashTable pervasively assumes that its internal storage is an array
of PLDHashEntryHdrs (with an associated object size to account for
subclassing).
As a first step to laying out the hash table storage differently, we
have to make the internals of PLDHashTable not access PLDHashEntryHdr
items directly, but layer an abstraction on top. We call this
abstraction "slots": a slot represents storage for the cached hash key
and the associated entry, and can produce a PLDHashEntryHdr* on demand.
The only place where this is used where the const-ness matters is in
AddressEntry, and that use const_cast's away the const-ness. So let's
just ditch the method that attempts to return const pointers.
This change is satisfying insofar as it removes a load from every
iteration step over the hashtable, but it doesn't seem to affect
our collection benchmarks in any way. The change does not make
iterators any larger, as there is padding at the end of the iterator
structure on both 32- and 64-bit platforms.
We only use its value in one place, and said value is easily computable
from readily available information. This change makes iterators
slightly smaller.
Currently we have three ways of representing hash values.
- uint32_t: used in HashFunctions.h.
- PLDHashNumber: defined in PLDHashTable.{h,cpp}.
- js::HashNumber: defined in js/public/Utility.h.
Functions that create hash values with functions from HashFunctions.h use a mix
of these three types. It's a bit of a mess.
This patch introduces mozilla::HashNumber, and redefines PLDHashNumber and
js::HashNumber as synonyms. It also changes HashFunctions.h to use
mozilla::HashNumber throughout instead of uint32_t.
This leaves plenty of places that still use uint32_t that should use
mozilla::HashNumber or one of its synonyms, but I didn't want to tackle that
now.
The patch also:
- Does similar things for the constants defining the number of bits in each
hash number type.
- Moves js::HashNumber from Utility.h to HashTable.h, which is a better spot
for it. (This required changing the signature of ScrambleHashCode(); that's
ok, it'll get moved by the next patch anyway.)
MozReview-Commit-ID: EdoWlCm7OUC
This speeds up BenchCollections.PLDHash as follows:
> succ_lookups fail_lookups insert_remove iterate
> 42.8 ms 51.6 ms 21.0 ms 34.9 ms
> 41.8 ms 51.9 ms 20.0 ms 34.6 ms
> 41.6 ms 51.3 ms 19.3 ms 34.5 ms
> 41.6 ms 51.3 ms 19.8 ms 35.0 ms
> 41.7 ms 50.8 ms 20.5 ms 35.2 ms
After:
> succ_lookups fail_lookups insert_remove iterate
> 37.7 ms 33.1 ms 19.7 ms 35.0 ms
> 37.0 ms 32.5 ms 19.1 ms 35.4 ms
> 37.6 ms 33.6 ms 19.2 ms 36.2 ms
> 36.7 ms 33.3 ms 19.1 ms 35.3 ms
> 37.1 ms 33.1 ms 19.1 ms 35.0 ms
Successful lookups are about 1.13x faster, failing lookups are about 1.54x
faster, and insertions/removals are about 1.05x faster.
On Linux64, this increases the size of libxul (as measured by `size`) by a mere
16 bytes.
The current code for resizing PLDHashTable modifies the cached hash for
all entries in the old hash table. This is unnecessary, because we're
going to throw away the old hash table shortly, and inefficient, because
writing to memory we're never going to use again just wastes time and
memory bandwidth. Instead, let's avoid the write by pulling out the
cached key and doing the necessary manipulation on local variables,
which is probably slightly faster.
PLDHashTable::Search() does not modify any members. So, this method and
methods called by it should be marked as const.
MozReview-Commit-ID: 6g4jrYK1j9E
This was done automatically replacing:
s/mozilla::Move/std::move/
s/ Move(/ std::move(/
s/(Move(/(std::move(/
Removing the 'using mozilla::Move;' lines.
And then with a few manual fixups, see the bug for the split series..
MozReview-Commit-ID: Jxze3adipUh
This patch reduces sizeof(PLDHashTable) as follows.
- 64-bit: from 40 bytes to 32
- 32-bit: from 28 bytes to 20
It does this by doing the following.
- It moves mGeneration from EntryStore to PLDHashTable, to avoid unnecessary
padding on 64-bit. This requires tweaking EntryStore::Set() as explained in a
comment.
- It also shrinks mGeneration from uint32_t to uint16_t, saving 2 bytes of
data.
- It shrinks mEntrySize from uint32_t to uint8_t, to cut 3 bytes of data.
- It shrinks mHashShift from int16_t to uint8_t, trimming another byte of data,
and moves it, saving another 2 bytes of padding.
And it reorders the fields so the word-sized ones are at the start, which makes
it easier to imagine the memory layout.
The patch also adds a test, and fixes some misordered function arguments in
existing tests.
The current code replaces one PLDHashTable's mGeneration with another. If the
two generation values happen to be equal, it will look as though the storage
hasn't changed when really it has.
The fix is to use EntryStore::Set() to update mEntryStore, which increments
mGeneration appropriately.
The simplistic shift-based hashing function creates a lot of collisions
for pointers pointing to arrays as it doesn't do a great job at distributing
the data randomly based on the input bytes.