зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1577146 - Consider debugger weak maps when calculating which compartments we think are live r=sfink
Differential Revision: https://phabricator.services.mozilla.com/D44399 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
61645c287f
Коммит
bdab0a4eea
|
@ -68,6 +68,10 @@ enum class ResumeMode {
|
|||
class DebugScript;
|
||||
class DebuggerVector;
|
||||
|
||||
using CompartmentSet =
|
||||
HashSet<JS::Compartment*, DefaultHasher<JS::Compartment*>,
|
||||
SystemAllocPolicy>;
|
||||
|
||||
class DebugAPI {
|
||||
public:
|
||||
friend class Debugger;
|
||||
|
@ -103,6 +107,11 @@ class DebugAPI {
|
|||
// Add sweep group edges due to the presence of any debuggers.
|
||||
static MOZ_MUST_USE bool findSweepGroupEdges(JSRuntime* rt);
|
||||
|
||||
// Find the target compartments of cross compartment edges.
|
||||
static bool findCrossCompartmentTargets(JSRuntime* rt,
|
||||
JS::Compartment* source,
|
||||
CompartmentSet& targets);
|
||||
|
||||
// Sweep breakpoints in a script associated with any debugger.
|
||||
static inline void sweepBreakpoints(JSFreeOp* fop, JSScript* script);
|
||||
|
||||
|
|
|
@ -3565,6 +3565,59 @@ void DebugAPI::traceCrossCompartmentEdges(JSTracer* trc) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Before performing a collection, the GC tries to find whether any collected
|
||||
* compartments are expected to die. To do this is needs to know about any cross
|
||||
* compartment pointers the debugger has that may keep compartments alive. This
|
||||
* is done by calling findCrossCompartmentTargets for compartments it suspects
|
||||
* are live.
|
||||
*/
|
||||
|
||||
bool DebugAPI::findCrossCompartmentTargets(JSRuntime* rt,
|
||||
JS::Compartment* source,
|
||||
CompartmentSet& targets) {
|
||||
for (Debugger* dbg : rt->debuggerList()) {
|
||||
if (dbg->compartment() == source) {
|
||||
if (!dbg->findCrossCompartmentTargets(targets)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::findCrossCompartmentTargets(CompartmentSet& targets) {
|
||||
for (WeakGlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
|
||||
Compartment* comp = e.front().unbarrieredGet()->compartment();
|
||||
if (!targets.put(comp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
forEachWeakMap([&](auto& weakMap) {
|
||||
if (ok && !weakMap.findCrossCompartmentTargets(targets)) {
|
||||
ok = false;
|
||||
}
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <class Referent, class Wrapper, bool InvisibleKeysOk>
|
||||
bool DebuggerWeakMap<Referent, Wrapper, InvisibleKeysOk>::
|
||||
findCrossCompartmentTargets(CompartmentSet& targets) {
|
||||
for (Enum e(*this); !e.empty(); e.popFront()) {
|
||||
Key key = e.front().key();
|
||||
JS::Compartment* comp = key->compartment();
|
||||
if (!targets.put(comp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
static bool RuntimeHasDebugger(JSRuntime* rt, Debugger* dbg) {
|
||||
|
|
|
@ -310,10 +310,6 @@ class DebuggerWeakMap : private WeakMap<HeapPtr<Referent*>, HeapPtr<Wrapper*>> {
|
|||
typedef HeapPtr<Referent*> Key;
|
||||
typedef HeapPtr<Wrapper*> Value;
|
||||
|
||||
typedef HashMap<JS::Zone*, uintptr_t, DefaultHasher<JS::Zone*>,
|
||||
ZoneAllocPolicy>
|
||||
CountMap;
|
||||
|
||||
JS::Compartment* compartment;
|
||||
|
||||
public:
|
||||
|
@ -375,6 +371,7 @@ class DebuggerWeakMap : private WeakMap<HeapPtr<Referent*>, HeapPtr<Wrapper*>> {
|
|||
}
|
||||
}
|
||||
|
||||
bool findCrossCompartmentTargets(CompartmentSet& targets);
|
||||
bool findSweepGroupEdges(JS::Zone* debuggerZone);
|
||||
|
||||
private:
|
||||
|
@ -832,6 +829,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
|
|||
void traceForMovingGC(JSTracer* trc);
|
||||
void traceCrossCompartmentEdges(JSTracer* tracer);
|
||||
|
||||
bool findCrossCompartmentTargets(CompartmentSet& targets);
|
||||
|
||||
static const JSClassOps classOps_;
|
||||
|
||||
public:
|
||||
|
@ -1051,6 +1050,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
|
|||
static Debugger* fromChildJSObject(JSObject* obj);
|
||||
|
||||
Zone* zone() const { return toJSObject()->zone(); }
|
||||
JS::Compartment* compartment() const { return toJSObject()->compartment(); }
|
||||
|
||||
bool hasMemory() const;
|
||||
DebuggerMemory& memory() const;
|
||||
|
|
|
@ -4028,7 +4028,7 @@ bool GCRuntime::beginMarkPhase(JS::GCReason reason, AutoGCSession& session) {
|
|||
}
|
||||
|
||||
if (isIncremental) {
|
||||
markCompartments();
|
||||
findDeadCompartments();
|
||||
}
|
||||
|
||||
updateMemoryCountersOnGCStart();
|
||||
|
@ -4046,7 +4046,7 @@ bool GCRuntime::beginMarkPhase(JS::GCReason reason, AutoGCSession& session) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void GCRuntime::markCompartments() {
|
||||
void GCRuntime::findDeadCompartments() {
|
||||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::MARK_ROOTS);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::MARK_COMPARTMENTS);
|
||||
|
||||
|
@ -4056,8 +4056,8 @@ void GCRuntime::markCompartments() {
|
|||
* flag is false. The maybeAlive flag is set if:
|
||||
*
|
||||
* (1) the compartment has been entered (set in beginMarkPhase() above)
|
||||
* (2) the compartment is not being collected (set in beginMarkPhase()
|
||||
* above)
|
||||
* (2) the compartment's zone is not being collected (set in
|
||||
* beginMarkPhase() above)
|
||||
* (3) an object in the compartment was marked during root marking, either
|
||||
* as a black root or a gray root (set in RootMarking.cpp), or
|
||||
* (4) the compartment has incoming cross-compartment edges from another
|
||||
|
@ -4080,7 +4080,7 @@ void GCRuntime::markCompartments() {
|
|||
* allocation and read barriers during JS_TransplantObject and the like.
|
||||
*/
|
||||
|
||||
/* Propagate the maybeAlive flag via cross-compartment edges. */
|
||||
// Propagate the maybeAlive flag via cross-compartment edges.
|
||||
|
||||
Vector<Compartment*, 0, js::SystemAllocPolicy> workList;
|
||||
|
||||
|
@ -4094,6 +4094,8 @@ void GCRuntime::markCompartments() {
|
|||
|
||||
while (!workList.empty()) {
|
||||
Compartment* comp = workList.popCopy();
|
||||
|
||||
// Check the cross compartment map.
|
||||
for (Compartment::WrappedObjectCompartmentEnum e(comp); !e.empty();
|
||||
e.popFront()) {
|
||||
Compartment* dest = e.front();
|
||||
|
@ -4104,9 +4106,24 @@ void GCRuntime::markCompartments() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check debugger cross compartment edges.
|
||||
CompartmentSet debuggerTargets;
|
||||
if (!DebugAPI::findCrossCompartmentTargets(rt, comp, debuggerTargets)) {
|
||||
return;
|
||||
}
|
||||
for (auto e = debuggerTargets.all(); !e.empty(); e.popFront()) {
|
||||
Compartment* dest = e.front();
|
||||
if (!dest->gcState.maybeAlive) {
|
||||
dest->gcState.maybeAlive = true;
|
||||
if (!workList.append(dest)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set scheduleForDestruction based on maybeAlive. */
|
||||
// Set scheduledForDestruction based on maybeAlive.
|
||||
|
||||
for (GCCompartmentsIter comp(rt); !comp.done(); comp.next()) {
|
||||
MOZ_ASSERT(!comp->gcState.scheduledForDestruction);
|
||||
|
|
|
@ -620,7 +620,7 @@ class GCRuntime {
|
|||
void traceEmbeddingGrayRoots(JSTracer* trc);
|
||||
void checkNoRuntimeRoots(AutoGCSession& session);
|
||||
void maybeDoCycleCollection();
|
||||
void markCompartments();
|
||||
void findDeadCompartments();
|
||||
IncrementalProgress markUntilBudgetExhausted(SliceBudget& sliceBudget,
|
||||
gcstats::PhaseKind phase);
|
||||
void drainMarkStack();
|
||||
|
|
Загрузка…
Ссылка в новой задаче