diff options
Diffstat (limited to 'js/src/gc/Marking-inl.h')
-rw-r--r-- | js/src/gc/Marking-inl.h | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/js/src/gc/Marking-inl.h b/js/src/gc/Marking-inl.h index 4afc9f7c8c..90f6337657 100644 --- a/js/src/gc/Marking-inl.h +++ b/js/src/gc/Marking-inl.h @@ -188,9 +188,40 @@ inline void PreWriteBarrierDuringFlattening(JSString* str) { #ifdef JSGC_HASH_TABLE_CHECKS +// Moving GC things whose pointers are used in hash table keys has the potential +// to break hash tables in subtle and terrifying ways. For example, a key might +// be reported as not present but iterating the table could still return it. +// +// Check that a table is correct following a moving GC, ensuring that nothing is +// present in the table that points into the nursery or that has not been moved, +// and that the hash table entries are discoverable. +// +// |checkEntryAndGetLookup| should check any GC thing pointers in the entry are +// valid and return the lookup required to get this entry from the table. + +template <typename Table, typename Range, typename Lookup> +void CheckTableEntryAfterMovingGC(const Table& table, const Range& r, + const Lookup& lookup) { + auto ptr = table.lookup(lookup); + MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front()); +} + +template <typename Table, typename F> +void CheckTableAfterMovingGC(const Table& table, F&& checkEntryAndGetLookup) { + for (auto r = table.all(); !r.empty(); r.popFront()) { + auto lookup = checkEntryAndGetLookup(r.front()); + CheckTableEntryAfterMovingGC(table, r, lookup); + } +} + template <typename T> inline bool IsGCThingValidAfterMovingGC(T* t) { - return !IsInsideNursery(t) && !t->isForwarded(); + if (!t->isTenured()) { + return false; + } + + TenuredCell* cell = &t->asTenured(); + return cell->arena()->allocated() && !cell->isForwarded(); } template <typename T> @@ -201,8 +232,24 @@ inline void CheckGCThingAfterMovingGC(T* t) { } template <typename T> -inline void CheckGCThingAfterMovingGC(const WeakHeapPtr<T*>& t) { - CheckGCThingAfterMovingGC(t.unbarrieredGet()); +inline void CheckGCThingAfterMovingGC(T* t, JS::Zone* expectedZone) { + if (t) { + MOZ_RELEASE_ASSERT(IsGCThingValidAfterMovingGC(t)); + JS::Zone* zone = t->zoneFromAnyThread(); + MOZ_RELEASE_ASSERT(zone == expectedZone || zone->isAtomsZone()); + } +} + +template <typename T> +inline void CheckGCThingAfterMovingGC(const WeakHeapPtr<T*>& t, + JS::Zone* expectedZone) { + CheckGCThingAfterMovingGC(t.unbarrieredGet(), expectedZone); +} + +inline void CheckProtoAfterMovingGC(const TaggedProto& proto, JS::Zone* zone) { + if (proto.isObject()) { + CheckGCThingAfterMovingGC(proto.toObject(), zone); + } } #endif // JSGC_HASH_TABLE_CHECKS |