Bug 1196847 - Part 2: Implement a cell hasher that uses unique id based hashes; r=jonco

--HG--
extra : rebase_source : 4d33add708a491e27492f9cdb63d98e76a7af94e
This commit is contained in:
Terrence Cole 2015-08-26 14:51:35 -07:00
Родитель 01fd1cc898
Коммит a6855649ac
3 изменённых файлов: 91 добавлений и 0 удалений

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

@ -740,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(); }
@ -979,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()|.

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

@ -10,7 +10,9 @@
#include "jsobj.h"
#include "gc/Zone.h"
#include "js/HashTable.h"
#include "js/Value.h"
#include "vm/ScopeObject.h"
#include "vm/Symbol.h"
#ifdef DEBUG
@ -102,3 +104,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 */ js::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());
js::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*>;

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

@ -693,6 +693,31 @@ class ImmutableTenuredPtr
const T* address() { return &value; }
};
// 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