зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1570590 : trace weak references in tracing. r=jonco
Introduces SweepingTracer and TraceWeakEdge to trace weak references in AtomsTable::sweep and AtomsTable::sweepIncrementally while sweeping. Also rename those two functions to traceWeak and traceWeakIncrementally. Differential Revision: https://phabricator.services.mozilla.com/D40939 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
2747e35c51
Коммит
a29edd5706
|
@ -252,7 +252,8 @@ class JS_PUBLIC_API CallbackTracer : public JSTracer {
|
|||
GrayBuffering,
|
||||
VerifyTraceProtoAndIface,
|
||||
ClearEdges,
|
||||
UnmarkGray
|
||||
UnmarkGray,
|
||||
Sweeping
|
||||
};
|
||||
virtual TracerKind getTracerKind() const { return TracerKind::Unspecified; }
|
||||
#endif
|
||||
|
|
|
@ -6180,7 +6180,8 @@ void GCRuntime::startSweepingAtomsTable() {
|
|||
// Create secondary tables to hold new atoms added while we're sweeping the
|
||||
// main tables incrementally.
|
||||
if (!atomsTable->startIncrementalSweep()) {
|
||||
atomsTable->sweepAll(rt);
|
||||
SweepingTracer trc(rt);
|
||||
atomsTable->traceWeak(&trc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6201,7 +6202,9 @@ IncrementalProgress GCRuntime::sweepAtomsTable(FreeOp* fop,
|
|||
return Finished;
|
||||
}
|
||||
|
||||
if (!rt->atomsForSweeping()->sweepIncrementally(maybeAtoms.ref(), budget)) {
|
||||
SweepingTracer trc(rt);
|
||||
if (!rt->atomsForSweeping()->traceWeakIncrementally(&trc, maybeAtoms.ref(),
|
||||
budget)) {
|
||||
return NotFinished;
|
||||
}
|
||||
|
||||
|
@ -6367,9 +6370,8 @@ IncrementalProgress GCRuntime::sweepShapeTree(FreeOp* fop,
|
|||
return NotFinished;
|
||||
}
|
||||
|
||||
if (!SweepArenaList<AccessorShape>(fop,
|
||||
&al.gcAccessorShapeArenasToUpdate.ref(),
|
||||
budget)) {
|
||||
if (!SweepArenaList<AccessorShape>(
|
||||
fop, &al.gcAccessorShapeArenasToUpdate.ref(), budget)) {
|
||||
return NotFinished;
|
||||
}
|
||||
|
||||
|
|
|
@ -176,6 +176,33 @@ struct MovingTracer final : public JS::CallbackTracer {
|
|||
bool updateEdge(T** thingp);
|
||||
};
|
||||
|
||||
struct SweepingTracer final : public JS::CallbackTracer {
|
||||
explicit SweepingTracer(JSRuntime* rt)
|
||||
: CallbackTracer(rt, TraceWeakMapKeysValues) {}
|
||||
|
||||
bool onObjectEdge(JSObject** objp) override;
|
||||
bool onShapeEdge(Shape** shapep) override;
|
||||
bool onStringEdge(JSString** stringp) override;
|
||||
bool onScriptEdge(JSScript** scriptp) override;
|
||||
bool onLazyScriptEdge(LazyScript** lazyp) override;
|
||||
bool onBaseShapeEdge(BaseShape** basep) override;
|
||||
bool onScopeEdge(Scope** scopep) override;
|
||||
bool onRegExpSharedEdge(RegExpShared** sharedp) override;
|
||||
bool onBigIntEdge(BigInt** bip) override;
|
||||
bool onChild(const JS::GCCellPtr& thing) override {
|
||||
MOZ_CRASH("unexpected edge.");
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
TracerKind getTracerKind() const override { return TracerKind::Sweeping; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
bool sweepEdge(T** thingp);
|
||||
};
|
||||
|
||||
// Structure for counting how many times objects in a particular group have
|
||||
// been tenured during a minor collection.
|
||||
struct TenureCount {
|
||||
|
|
|
@ -246,7 +246,8 @@ void js::CheckTracedThing(JSTracer* trc, T* thing) {
|
|||
isGcMarkingTracer ||
|
||||
IsTracerKind(trc, JS::CallbackTracer::TracerKind::GrayBuffering) ||
|
||||
IsTracerKind(trc, JS::CallbackTracer::TracerKind::UnmarkGray) ||
|
||||
IsTracerKind(trc, JS::CallbackTracer::TracerKind::ClearEdges));
|
||||
IsTracerKind(trc, JS::CallbackTracer::TracerKind::ClearEdges) ||
|
||||
IsTracerKind(trc, JS::CallbackTracer::TracerKind::Sweeping));
|
||||
|
||||
if (isGcMarkingTracer) {
|
||||
GCMarker* gcMarker = GCMarker::fromTracer(trc);
|
||||
|
@ -3434,6 +3435,47 @@ bool js::gc::IsAboutToBeFinalizedInternal(T* thingp) {
|
|||
return dying;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool SweepingTracer::sweepEdge(T** thingp) {
|
||||
CheckIsMarkedThing(thingp);
|
||||
T* thing = *thingp;
|
||||
JSRuntime* rt = thing->runtimeFromAnyThread();
|
||||
|
||||
if (ThingIsPermanentAtomOrWellKnownSymbol(thing) && runtime() != rt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TenuredCell& tenured = thing->asTenured();
|
||||
MOZ_ASSERT(tenured.zoneFromAnyThread()->isGCSweeping(),
|
||||
"Should be called during Sweeping.");
|
||||
if (!tenured.isMarkedAny()) {
|
||||
*thingp = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SweepingTracer::onObjectEdge(JSObject** objp) { return sweepEdge(objp); }
|
||||
bool SweepingTracer::onShapeEdge(Shape** shapep) { return sweepEdge(shapep); }
|
||||
bool SweepingTracer::onStringEdge(JSString** stringp) {
|
||||
return sweepEdge(stringp);
|
||||
}
|
||||
bool SweepingTracer::onScriptEdge(JSScript** scriptp) {
|
||||
return sweepEdge(scriptp);
|
||||
}
|
||||
bool SweepingTracer::onLazyScriptEdge(LazyScript** lazyp) {
|
||||
return sweepEdge(lazyp);
|
||||
}
|
||||
bool SweepingTracer::onBaseShapeEdge(BaseShape** basep) {
|
||||
return sweepEdge(basep);
|
||||
}
|
||||
bool SweepingTracer::onScopeEdge(Scope** scopep) { return sweepEdge(scopep); }
|
||||
bool SweepingTracer::onRegExpSharedEdge(RegExpShared** sharedp) {
|
||||
return sweepEdge(sharedp);
|
||||
}
|
||||
bool SweepingTracer::onBigIntEdge(BigInt** bip) { return sweepEdge(bip); }
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ inline void AssertRootMarkingPhase(JSTracer* trc) {}
|
|||
// Note that weak edges are handled separately. GC things with weak edges must
|
||||
// not trace those edges during marking tracing (which would keep the referent
|
||||
// alive) but instead arrange for the edge to be swept by calling
|
||||
// js::gc::IsAboutToBeFinalized during sweeping. For example, see the treatment
|
||||
// of the script_ edge in LazyScript::traceChildren and
|
||||
// js::gc::IsAboutToBeFinalized or TraceWeakEdge during sweeping. For example,
|
||||
// see the treatment of the script_ edge in LazyScript::traceChildren and
|
||||
// js::gc::SweepLazyScripts.
|
||||
//
|
||||
// GC things that are weakly held in containers can use WeakMap or a container
|
||||
|
@ -191,6 +191,14 @@ inline void TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp,
|
|||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
// Trace through a weak edge. If *thingp is not marked at the end of marking,
|
||||
// it is replaced by nullptr, and this method will return false to indicate that
|
||||
// the edge no longer exists.
|
||||
template <typename T>
|
||||
inline bool TraceWeakEdge(JSTracer* trc, T* thingp, const char* name) {
|
||||
return gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
// Trace all edges contained in the given array.
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -188,12 +188,13 @@ class AtomsTable {
|
|||
void tracePinnedAtoms(JSTracer* trc, const AutoAccessAtomsZone& access);
|
||||
|
||||
// Sweep all atoms non-incrementally.
|
||||
void sweepAll(JSRuntime* rt);
|
||||
void traceWeak(JSTracer* trc);
|
||||
|
||||
bool startIncrementalSweep();
|
||||
|
||||
// Sweep some atoms incrementally and return whether we finished.
|
||||
bool sweepIncrementally(SweepIterator& atomsToSweep, SliceBudget& budget);
|
||||
bool traceWeakIncrementally(JSTracer* trc, SweepIterator& atomsToSweep,
|
||||
SliceBudget& budget);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mainThreadHasAllLocks() const { return allPartitionsLocked; }
|
||||
|
|
|
@ -476,15 +476,15 @@ void js::TraceWellKnownSymbols(JSTracer* trc) {
|
|||
}
|
||||
}
|
||||
|
||||
void AtomsTable::sweepAll(JSRuntime* rt) {
|
||||
void AtomsTable::traceWeak(JSTracer* trc) {
|
||||
JSRuntime* rt = trc->runtime();
|
||||
for (size_t i = 0; i < PartitionCount; i++) {
|
||||
AutoLock lock(rt, partitions[i]->lock);
|
||||
AtomSet& atoms = partitions[i]->atoms;
|
||||
for (AtomSet::Enum e(atoms); !e.empty(); e.popFront()) {
|
||||
JSAtom* atom = e.front().asPtrUnbarriered();
|
||||
MOZ_DIAGNOSTIC_ASSERT(atom);
|
||||
if (IsAboutToBeFinalizedUnbarriered(&atom)) {
|
||||
MOZ_ASSERT(!atom->isPinned());
|
||||
if (!TraceWeakEdge(trc, &atom, "AtomsTable::partitions::atoms")) {
|
||||
e.removeFront();
|
||||
} else {
|
||||
MOZ_ASSERT(atom == e.front().asPtrUnbarriered());
|
||||
|
@ -589,8 +589,8 @@ void AtomsTable::mergeAtomsAddedWhileSweeping(Partition& part) {
|
|||
js_delete(newAtoms);
|
||||
}
|
||||
|
||||
bool AtomsTable::sweepIncrementally(SweepIterator& atomsToSweep,
|
||||
SliceBudget& budget) {
|
||||
bool AtomsTable::traceWeakIncrementally(JSTracer* trc, SweepIterator& atomsToSweep,
|
||||
SliceBudget& budget) {
|
||||
// Sweep the table incrementally until we run out of work or budget.
|
||||
while (!atomsToSweep.empty()) {
|
||||
budget.step();
|
||||
|
@ -600,8 +600,7 @@ bool AtomsTable::sweepIncrementally(SweepIterator& atomsToSweep,
|
|||
|
||||
JSAtom* atom = atomsToSweep.front();
|
||||
MOZ_DIAGNOSTIC_ASSERT(atom);
|
||||
if (IsAboutToBeFinalizedUnbarriered(&atom)) {
|
||||
MOZ_ASSERT(!atom->isPinned());
|
||||
if (!TraceWeakEdge(trc, &atom, "maybeAtomsToSweep")) {
|
||||
atomsToSweep.removeFront();
|
||||
} else {
|
||||
MOZ_ASSERT(atom == atomsToSweep.front());
|
||||
|
|
Загрузка…
Ссылка в новой задаче