AbortSignal: Model dependent signals as Member instead of root
The root in AbortSignal was creating the following cycle with unified
heap:
Request -> AbortSignal -> AbortSignal (root) -> ExecutionContext -> Request
Bug: 928781,843903
Change-Id: Iefad41f37fe3ccb3960a7c3d9e1b963730aab7ec
Reviewed-on: https://chromium-review.googlesource.com/c/1477241
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#633714}diff --git a/third_party/blink/renderer/core/dom/abort_signal.cc b/third_party/blink/renderer/core/dom/abort_signal.cc
index b1774cba..64cafa08 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.cc
+++ b/third_party/blink/renderer/core/dom/abort_signal.cc
@@ -36,6 +36,24 @@
abort_algorithms_.push_back(std::move(algorithm));
}
+void AbortSignal::AddSignalAbortAlgorithm(AbortSignal* dependent_signal) {
+ if (aborted_flag_)
+ return;
+
+ // The signal should be kept alive as long as parentSignal is allow chained
+ // requests like the following:
+ // controller -owns-> signal1 -owns-> signal2 -owns-> signal3 <-owns- request
+ //
+ // Due to lack to traced closures we pass a weak persistent but also add
+ // |dependent_signal| as a dependency that is traced. We do not use
+ // WrapPersistent here as this would create a root for Oilpan and unified heap
+ // that leaks the |execution_context_| as there is no explicit event removing
+ // the root anymore.
+ abort_algorithms_.emplace_back(WTF::Bind(
+ &AbortSignal::SignalAbort, WrapWeakPersistent(dependent_signal)));
+ dependent_signals_.push_back(dependent_signal);
+}
+
void AbortSignal::SignalAbort() {
if (aborted_flag_)
return;
@@ -44,6 +62,7 @@
std::move(closure).Run();
}
abort_algorithms_.clear();
+ dependent_signals_.clear();
DispatchEvent(*Event::Create(event_type_names::kAbort));
}
@@ -53,24 +72,12 @@
if (parentSignal->aborted_flag_)
SignalAbort();
- // Unlike the usual practice for AddAlgorithm(), we don't use a weak pointer
- // here. To see why, consider the following object graph:
- //
- // controller --owns--> signal1 -?-> signal2 -?-> signal3 <--owns-- request
- //
- // It's easy to create chained signals like this using the Request
- // constructor. If the -?-> pointers were weak, then |signal2| could be
- // collected even though |controller| and |request| were still
- // referenced. This would prevent controller.abort() from working. So the
- // pointers need to be strong. This won't artificially extend the lifetime of
- // |request|, because the pointer to it in the closure held by |signal3| is
- // still weak.
- parentSignal->AddAlgorithm(
- WTF::Bind(&AbortSignal::SignalAbort, WrapPersistent(this)));
+ parentSignal->AddSignalAbortAlgorithm(this);
}
void AbortSignal::Trace(Visitor* visitor) {
visitor->Trace(execution_context_);
+ visitor->Trace(dependent_signals_);
EventTargetWithInlineData::Trace(visitor);
}
diff --git a/third_party/blink/renderer/core/dom/abort_signal.h b/third_party/blink/renderer/core/dom/abort_signal.h
index b6abfc3e..96dcea1 100644
--- a/third_party/blink/renderer/core/dom/abort_signal.h
+++ b/third_party/blink/renderer/core/dom/abort_signal.h
@@ -62,8 +62,11 @@
void Trace(Visitor*) override;
private:
+ void AddSignalAbortAlgorithm(AbortSignal*);
+
bool aborted_flag_ = false;
Vector<base::OnceClosure> abort_algorithms_;
+ HeapVector<Member<AbortSignal>> dependent_signals_;
Member<ExecutionContext> execution_context_;
};