diff options
author | Moonchild <git-repo@palemoon.org> | 2020-02-26 02:38:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-26 02:38:18 +0100 |
commit | cce2bc96771613f51659e9209181e0d54a3fee96 (patch) | |
tree | cbeec2384bd44bab37cd787215ec830fa8b356cd /js/src/gc/Tracer.cpp | |
parent | 35c26c6c19e66fabcb230fb074e76e243df04d2b (diff) | |
parent | ecdeefc4dd5624e824e696ac1c492c0b103f4acd (diff) | |
download | UXP-cce2bc96771613f51659e9209181e0d54a3fee96.tar UXP-cce2bc96771613f51659e9209181e0d54a3fee96.tar.gz UXP-cce2bc96771613f51659e9209181e0d54a3fee96.tar.lz UXP-cce2bc96771613f51659e9209181e0d54a3fee96.tar.xz UXP-cce2bc96771613f51659e9209181e0d54a3fee96.zip |
Merge pull request #1461 from MoonchildProductions/ubbo
Back out unboxed array/object removals
Diffstat (limited to 'js/src/gc/Tracer.cpp')
-rw-r--r-- | js/src/gc/Tracer.cpp | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index 3416464dd..63cd9b08a 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -201,15 +201,80 @@ gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, Shape* shape) } while (shape); } +// Object groups can point to other object groups via an UnboxedLayout or the +// the original unboxed group link. There can potentially be deep or cyclic +// chains of such groups to trace through without going through a thing that +// participates in cycle collection. These need to be handled iteratively to +// avoid blowing the stack when running the cycle collector's callback tracer. +struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer +{ + explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer) + : JS::CallbackTracer(innerTracer->runtime(), DoNotTraceWeakMaps), + innerTracer(innerTracer) + {} + + void onChild(const JS::GCCellPtr& thing) override; + + JS::CallbackTracer* innerTracer; + Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist; +}; + +void +ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing) +{ + if (thing.is<BaseShape>()) { + // The CC does not care about BaseShapes, and no additional GC things + // will be reached by following this edge. + return; + } + + if (thing.is<JSObject>() || thing.is<JSScript>()) { + // Invoke the inner cycle collector callback on this child. It will not + // recurse back into TraceChildren. + innerTracer->onChild(thing); + return; + } + + if (thing.is<ObjectGroup>()) { + // If this group is required to be in an ObjectGroup chain, trace it + // via the provided worklist rather than continuing to recurse. + ObjectGroup& group = thing.as<ObjectGroup>(); + if (group.maybeUnboxedLayout()) { + for (size_t i = 0; i < seen.length(); i++) { + if (seen[i] == &group) + return; + } + if (seen.append(&group) && worklist.append(&group)) { + return; + } else { + // If append fails, keep tracing normally. The worst that will + // happen is we end up overrecursing. + } + } + } + + TraceChildren(this, thing.asCell(), thing.kind()); +} + void gc::TraceCycleCollectorChildren(JS::CallbackTracer* trc, ObjectGroup* group) { MOZ_ASSERT(trc->isCallbackTracer()); - group->traceChildren(trc); -} + // Early return if this group is not required to be in an ObjectGroup chain. + if (!group->maybeUnboxedLayout()) + return group->traceChildren(trc); + + ObjectGroupCycleCollectorTracer groupTracer(trc->asCallbackTracer()); + group->traceChildren(&groupTracer); + while (!groupTracer.worklist.empty()) { + ObjectGroup* innerGroup = groupTracer.worklist.popCopy(); + innerGroup->traceChildren(&groupTracer); + } +} + /*** Traced Edge Printer *************************************************************************/ static size_t |