mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1196847 - Part 2: Implement a cell hasher that uses unique id based hashes; r=jonco
--HG-- extra : rebase_source : aec278105f1cb4303eff593edef244f10ebd2a0e
This commit is contained in:
parent
954ca0c585
commit
5e9eddeee5
@ -653,8 +653,6 @@ class HashMapEntry
|
||||
template <class> friend class detail::HashTableEntry;
|
||||
template <class, class, class, class> friend class HashMap;
|
||||
|
||||
Key & mutableKey() { return key_; }
|
||||
|
||||
public:
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
HashMapEntry(KeyInput&& k, ValueInput&& v)
|
||||
@ -670,9 +668,10 @@ class HashMapEntry
|
||||
typedef Key KeyType;
|
||||
typedef Value ValueType;
|
||||
|
||||
const Key & key() const { return key_; }
|
||||
const Value & value() const { return value_; }
|
||||
Value & value() { return value_; }
|
||||
const Key& key() const { return key_; }
|
||||
Key& mutableKey() { return key_; }
|
||||
const Value& value() const { return value_; }
|
||||
Value& value() { return value_; }
|
||||
|
||||
private:
|
||||
HashMapEntry(const HashMapEntry&) = delete;
|
||||
@ -741,6 +740,7 @@ class HashTableEntry
|
||||
}
|
||||
|
||||
T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); }
|
||||
NonConstT& getMutable() { MOZ_ASSERT(isLive()); return *mem.addr(); }
|
||||
|
||||
bool isFree() const { return keyHash == sFreeKey; }
|
||||
void clearLive() { MOZ_ASSERT(isLive()); keyHash = sFreeKey; mem.addr()->~T(); }
|
||||
@ -980,6 +980,16 @@ class HashTable : private AllocPolicy
|
||||
#endif
|
||||
}
|
||||
|
||||
NonConstT& mutableFront() {
|
||||
MOZ_ASSERT(!this->empty());
|
||||
#ifdef JS_DEBUG
|
||||
MOZ_ASSERT(this->validEntry);
|
||||
MOZ_ASSERT(this->generation == this->Range::table_->generation());
|
||||
MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount);
|
||||
#endif
|
||||
return this->cur->getMutable();
|
||||
}
|
||||
|
||||
// Removes the |front()| element and re-inserts it into the table with
|
||||
// a new key at the new Lookup position. |front()| is invalid after
|
||||
// this operation until the next call to |popFront()|.
|
||||
|
@ -102,3 +102,56 @@ JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next
|
||||
MOZ_ASSERT(valuep);
|
||||
js::InternalGCMethods<JS::Value>::postBarrier(valuep, prev, next);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
/* static */ HashNumber
|
||||
js::MovableCellHasher<T>::hash(const Lookup& l)
|
||||
{
|
||||
if (!l)
|
||||
return 0;
|
||||
|
||||
// We have to access the zone from-any-thread here: a worker thread may be
|
||||
// cloning a self-hosted object from the main-thread-runtime-owned self-
|
||||
// hosting zone into the off-main-thread runtime. The zone's uid lock will
|
||||
// protect against multiple workers doing this simultaneously.
|
||||
MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
|
||||
l->zoneFromAnyThread()->isSelfHostingZone());
|
||||
|
||||
HashNumber hn;
|
||||
if (!l->zoneFromAnyThread()->getHashCode(l, &hn))
|
||||
js::CrashAtUnhandlableOOM("failed to get a stable hash code");
|
||||
return hn;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
/* static */ bool
|
||||
js::MovableCellHasher<T>::match(const Key& k, const Lookup& l)
|
||||
{
|
||||
// Return true if both are null or false if only one is null.
|
||||
if (!k)
|
||||
return !l;
|
||||
if (!l)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(k);
|
||||
MOZ_ASSERT(l);
|
||||
MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
|
||||
l->zoneFromAnyThread()->isSelfHostingZone());
|
||||
|
||||
Zone* zone = k->zoneFromAnyThread();
|
||||
if (zone != l->zoneFromAnyThread())
|
||||
return false;
|
||||
MOZ_ASSERT(zone->hasUniqueId(k));
|
||||
MOZ_ASSERT(zone->hasUniqueId(l));
|
||||
|
||||
// Since both already have a uid (from hash), the get is infallible.
|
||||
uint64_t uidK, uidL;
|
||||
MOZ_ALWAYS_TRUE(zone->getUniqueId(k, &uidK));
|
||||
MOZ_ALWAYS_TRUE(zone->getUniqueId(l, &uidL));
|
||||
return uidK == uidL;
|
||||
}
|
||||
|
||||
template struct js::MovableCellHasher<JSObject*>;
|
||||
template struct js::MovableCellHasher<js::GlobalObject*>;
|
||||
template struct js::MovableCellHasher<js::SavedFrame*>;
|
||||
template struct js::MovableCellHasher<js::ScopeObject*>;
|
||||
|
@ -545,6 +545,31 @@ BarrieredSetPair(Zone* zone,
|
||||
v2.postBarrieredSet(val2);
|
||||
}
|
||||
|
||||
// Provide hash codes for Cell kinds that may be relocated and, thus, not have
|
||||
// a stable address to use as the base for a hash code. Instead of the address,
|
||||
// this hasher uses Cell::getUniqueId to provide exact matches and as a base
|
||||
// for generating hash codes.
|
||||
//
|
||||
// Note: this hasher, like PointerHasher can "hash" a nullptr. While a nullptr
|
||||
// would not likely be a useful key, there are some cases where being able to
|
||||
// hash a nullptr is useful, either on purpose or because of bugs:
|
||||
// (1) existence checks where the key may happen to be null and (2) some
|
||||
// aggregate Lookup kinds embed a JSObject* that is frequently null and do not
|
||||
// null test before dispatching to the hasher.
|
||||
template <typename T>
|
||||
struct MovableCellHasher
|
||||
{
|
||||
static_assert(mozilla::IsBaseOf<JSObject, typename mozilla::RemovePointer<T>::Type>::value,
|
||||
"MovableCellHasher's T must be a Cell type that may move");
|
||||
|
||||
using Key = T;
|
||||
using Lookup = T;
|
||||
|
||||
static HashNumber hash(const Lookup& l);
|
||||
static bool match(const Key& k, const Lookup& l);
|
||||
static void rekey(Key& k, const Key& newKey) { k = newKey; }
|
||||
};
|
||||
|
||||
/* Useful for hashtables with a HeapPtr as key. */
|
||||
template <class T>
|
||||
struct HeapPtrHasher
|
||||
|
Loading…
Reference in New Issue
Block a user