Title: [272942] branches/safari-611-branch/Source/WebCore
Revision
272942
Author
repst...@apple.com
Date
2021-02-16 17:15:19 -0800 (Tue, 16 Feb 2021)

Log Message

Cherry-pick r272394. rdar://problem/74409285

    Avoid creating JS wrapper on a removed node when the subtree is not observable
    https://bugs.webkit.org/show_bug.cgi?id=221243
    <rdar://problem/73719386>

    Reviewed by Geoffrey Garen.

    Prior to this patch, WebKit forced the creation the JS wrapper on the root DOM node of a removed subtree
    to avoid script observable deletion of nodes. This is necessary because DOM nodes are reference counted
    in the C++ side, and while a DOM node keeps its child nodes alive, it won't keep its parent node alive
    to avoid reference cycles (leaks). If we didn't force the creation of the JS wrapper and the root node
    of the removed subtree didn't have any external reference to it in C++ side, we would happily delete it
    and all its descendant nodes above any subtree with a JS wrapper or an external C++ reference.

    While this turned out to be an effective strategy for implementing DOM nodes' GC semantics correctly,
    it has a significant runtime and memory cost - the latter is because we don't collect the JS wrappers
    of DOM nodes once they're created until they're ready to be destructed.

    This patch introduces a new optimization to avoid creating these JS wrappers when the removed subtree
    won't be observable by scripts in the future. The current heuristic is to check if the removed node
    has any external reference to it (i.e. refCount() > 0 excluding any reference counting that happens within
    our algorithm). This is sufficient because a given node should not be observable at a later time unless
    it has an external reference to it. This is ~0.5% progression on Speedometer-2.0 on MacBookAir7,2.

    To do this, we take advantage of the fact notifyChildNodeRemoved already traverses each removed subtree,
    and check if any of them has a reference count greater than 1 (greater than 1 because notifyChildNodeRemoved
    itself increments node's reference count before calling itself on child nodes). Note that we exclude the
    root node of the removed subtree as these JS wrapper creation is only needed to keep the root node alive.
    If the root node is already kept alive by some external reference to it, there is no need to keep it alive
    again by creating a JS wrapper on it.

    No new tests since existing tests such as fast/dom/gc-3.html covers it.

    * dom/ContainerNode.cpp:
    (WebCore::ContainerNode::removeAllChildrenWithScriptAssertion): Call willCreatePossiblyOrphanedTreeByRemoval
    if the removed subtree contains an observable node.
    (WebCore::ContainerNode::removeNodeWithScriptAssertion): Ditto.
    (WebCore::ContainerNode::removeSelfOrChildNodesForInsertion): Renamed from collectChildrenAndRemoveFromOldParent.
    Avoid collecting the removed nodes in this function in addition to removeAllChildrenWithScriptAssertion.
    (WebCore::ContainerNode::insertBefore):
    (WebCore::ContainerNode::replaceChild):
    (WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck):
    (WebCore::dispatchChildRemovalEvents): Don't call willCreatePossiblyOrphanedTreeByRemoval here.
    * dom/ContainerNode.h:
    * dom/ContainerNodeAlgorithms.cpp:
    (WebCore::observabilityOfRemovedNode): Added. Checks the observability of a node excluding the root node of
    the removed subtree since it needs a special case in removeAllChildrenWithScriptAssertion.
    As notifyNodeRemovedFromDocument and notifyNodeRemovedFromTree ref's each child node before recursing on itself,
    we check refCount() > 1 here.
    (WebCore::updateObservability): Added. A helper function to update RemovedSubtreeObservability.
    (WebCore::notifyNodeRemovedFromDocument): Now returns RemovedSubtreeObservability,
    (WebCore::notifyNodeRemovedFromTree): Ditto.
    (WebCore::notifyChildNodeRemoved): Ditto.
    * dom/ContainerNodeAlgorithms.h:

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@272394 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Diff

Modified: branches/safari-611-branch/Source/WebCore/ChangeLog (272941 => 272942)


--- branches/safari-611-branch/Source/WebCore/ChangeLog	2021-02-17 01:15:05 UTC (rev 272941)
+++ branches/safari-611-branch/Source/WebCore/ChangeLog	2021-02-17 01:15:19 UTC (rev 272942)
@@ -1,5 +1,122 @@
 2021-02-16  Ruben Turcios  <rubent...@apple.com>
 
+        Cherry-pick r272394. rdar://problem/74409285
+
+    Avoid creating JS wrapper on a removed node when the subtree is not observable
+    https://bugs.webkit.org/show_bug.cgi?id=221243
+    <rdar://problem/73719386>
+    
+    Reviewed by Geoffrey Garen.
+    
+    Prior to this patch, WebKit forced the creation the JS wrapper on the root DOM node of a removed subtree
+    to avoid script observable deletion of nodes. This is necessary because DOM nodes are reference counted
+    in the C++ side, and while a DOM node keeps its child nodes alive, it won't keep its parent node alive
+    to avoid reference cycles (leaks). If we didn't force the creation of the JS wrapper and the root node
+    of the removed subtree didn't have any external reference to it in C++ side, we would happily delete it
+    and all its descendant nodes above any subtree with a JS wrapper or an external C++ reference.
+    
+    While this turned out to be an effective strategy for implementing DOM nodes' GC semantics correctly,
+    it has a significant runtime and memory cost - the latter is because we don't collect the JS wrappers
+    of DOM nodes once they're created until they're ready to be destructed.
+    
+    This patch introduces a new optimization to avoid creating these JS wrappers when the removed subtree
+    won't be observable by scripts in the future. The current heuristic is to check if the removed node
+    has any external reference to it (i.e. refCount() > 0 excluding any reference counting that happens within
+    our algorithm). This is sufficient because a given node should not be observable at a later time unless
+    it has an external reference to it. This is ~0.5% progression on Speedometer-2.0 on MacBookAir7,2.
+    
+    To do this, we take advantage of the fact notifyChildNodeRemoved already traverses each removed subtree,
+    and check if any of them has a reference count greater than 1 (greater than 1 because notifyChildNodeRemoved
+    itself increments node's reference count before calling itself on child nodes). Note that we exclude the
+    root node of the removed subtree as these JS wrapper creation is only needed to keep the root node alive.
+    If the root node is already kept alive by some external reference to it, there is no need to keep it alive
+    again by creating a JS wrapper on it.
+    
+    No new tests since existing tests such as fast/dom/gc-3.html covers it.
+    
+    * dom/ContainerNode.cpp:
+    (WebCore::ContainerNode::removeAllChildrenWithScriptAssertion): Call willCreatePossiblyOrphanedTreeByRemoval
+    if the removed subtree contains an observable node.
+    (WebCore::ContainerNode::removeNodeWithScriptAssertion): Ditto.
+    (WebCore::ContainerNode::removeSelfOrChildNodesForInsertion): Renamed from collectChildrenAndRemoveFromOldParent.
+    Avoid collecting the removed nodes in this function in addition to removeAllChildrenWithScriptAssertion.
+    (WebCore::ContainerNode::insertBefore):
+    (WebCore::ContainerNode::replaceChild):
+    (WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck):
+    (WebCore::dispatchChildRemovalEvents): Don't call willCreatePossiblyOrphanedTreeByRemoval here.
+    * dom/ContainerNode.h:
+    * dom/ContainerNodeAlgorithms.cpp:
+    (WebCore::observabilityOfRemovedNode): Added. Checks the observability of a node excluding the root node of
+    the removed subtree since it needs a special case in removeAllChildrenWithScriptAssertion.
+    As notifyNodeRemovedFromDocument and notifyNodeRemovedFromTree ref's each child node before recursing on itself,
+    we check refCount() > 1 here.
+    (WebCore::updateObservability): Added. A helper function to update RemovedSubtreeObservability.
+    (WebCore::notifyNodeRemovedFromDocument): Now returns RemovedSubtreeObservability,
+    (WebCore::notifyNodeRemovedFromTree): Ditto.
+    (WebCore::notifyChildNodeRemoved): Ditto.
+    * dom/ContainerNodeAlgorithms.h:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@272394 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-02-04  Ryosuke Niwa  <rn...@webkit.org>
+
+            Avoid creating JS wrapper on a removed node when the subtree is not observable
+            https://bugs.webkit.org/show_bug.cgi?id=221243
+            <rdar://problem/73719386>
+
+            Reviewed by Geoffrey Garen.
+
+            Prior to this patch, WebKit forced the creation the JS wrapper on the root DOM node of a removed subtree
+            to avoid script observable deletion of nodes. This is necessary because DOM nodes are reference counted
+            in the C++ side, and while a DOM node keeps its child nodes alive, it won't keep its parent node alive
+            to avoid reference cycles (leaks). If we didn't force the creation of the JS wrapper and the root node
+            of the removed subtree didn't have any external reference to it in C++ side, we would happily delete it
+            and all its descendant nodes above any subtree with a JS wrapper or an external C++ reference.
+
+            While this turned out to be an effective strategy for implementing DOM nodes' GC semantics correctly,
+            it has a significant runtime and memory cost - the latter is because we don't collect the JS wrappers
+            of DOM nodes once they're created until they're ready to be destructed.
+
+            This patch introduces a new optimization to avoid creating these JS wrappers when the removed subtree
+            won't be observable by scripts in the future. The current heuristic is to check if the removed node
+            has any external reference to it (i.e. refCount() > 0 excluding any reference counting that happens within
+            our algorithm). This is sufficient because a given node should not be observable at a later time unless
+            it has an external reference to it. This is ~0.5% progression on Speedometer-2.0 on MacBookAir7,2.
+
+            To do this, we take advantage of the fact notifyChildNodeRemoved already traverses each removed subtree,
+            and check if any of them has a reference count greater than 1 (greater than 1 because notifyChildNodeRemoved
+            itself increments node's reference count before calling itself on child nodes). Note that we exclude the
+            root node of the removed subtree as these JS wrapper creation is only needed to keep the root node alive.
+            If the root node is already kept alive by some external reference to it, there is no need to keep it alive
+            again by creating a JS wrapper on it.
+
+            No new tests since existing tests such as fast/dom/gc-3.html covers it.
+
+            * dom/ContainerNode.cpp:
+            (WebCore::ContainerNode::removeAllChildrenWithScriptAssertion): Call willCreatePossiblyOrphanedTreeByRemoval
+            if the removed subtree contains an observable node.
+            (WebCore::ContainerNode::removeNodeWithScriptAssertion): Ditto.
+            (WebCore::ContainerNode::removeSelfOrChildNodesForInsertion): Renamed from collectChildrenAndRemoveFromOldParent.
+            Avoid collecting the removed nodes in this function in addition to removeAllChildrenWithScriptAssertion.
+            (WebCore::ContainerNode::insertBefore):
+            (WebCore::ContainerNode::replaceChild):
+            (WebCore::ContainerNode::appendChildWithoutPreInsertionValidityCheck):
+            (WebCore::dispatchChildRemovalEvents): Don't call willCreatePossiblyOrphanedTreeByRemoval here.
+            * dom/ContainerNode.h:
+            * dom/ContainerNodeAlgorithms.cpp:
+            (WebCore::observabilityOfRemovedNode): Added. Checks the observability of a node excluding the root node of
+            the removed subtree since it needs a special case in removeAllChildrenWithScriptAssertion.
+            As notifyNodeRemovedFromDocument and notifyNodeRemovedFromTree ref's each child node before recursing on itself,
+            we check refCount() > 1 here.
+            (WebCore::updateObservability): Added. A helper function to update RemovedSubtreeObservability.
+            (WebCore::notifyNodeRemovedFromDocument): Now returns RemovedSubtreeObservability,
+            (WebCore::notifyNodeRemovedFromTree): Ditto.
+            (WebCore::notifyChildNodeRemoved): Ditto.
+            * dom/ContainerNodeAlgorithms.h:
+
+2021-02-16  Ruben Turcios  <rubent...@apple.com>
+
         Cherry-pick r272390. rdar://problem/74409535
 
     AX: expose focusable elements even if element or ancestor has aria-hidden=true

Modified: branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp (272941 => 272942)


--- branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp	2021-02-17 01:15:05 UTC (rev 272941)
+++ branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp	2021-02-17 01:15:19 UTC (rev 272942)
@@ -111,7 +111,9 @@
 
     while (RefPtr<Node> child = m_firstChild) {
         removeBetween(nullptr, child->nextSibling(), *child);
-        notifyChildNodeRemoved(*this, *child);
+        auto subtreeObservability = notifyChildNodeRemoved(*this, *child);
+        if (source == ChildChange::Source::API && subtreeObservability == RemovedSubtreeObservability::MaybeObservableByRefPtr)
+            willCreatePossiblyOrphanedTreeByRemoval(child.get());
     }
 
     if (deferChildrenChanged == DeferChildrenChanged::No)
@@ -149,6 +151,7 @@
         return false;
 
     ChildChange change;
+    RemovedSubtreeObservability subtreeObservability;
     {
         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
         ScriptDisallowedScope::InMainThread scriptDisallowedScope;
@@ -164,7 +167,7 @@
         RefPtr<Node> previousSibling = childToRemove.previousSibling();
         RefPtr<Node> nextSibling = childToRemove.nextSibling();
         removeBetween(previousSibling.get(), nextSibling.get(), childToRemove);
-        notifyChildNodeRemoved(*this, childToRemove);
+        subtreeObservability = notifyChildNodeRemoved(*this, childToRemove);
 
         change.type = is<Element>(childToRemove) ?
             ChildChange::Type::ElementRemoved :
@@ -176,6 +179,9 @@
         change.source = source;
     }
 
+    if (source == ChildChange::Source::API && subtreeObservability == RemovedSubtreeObservability::MaybeObservableByRefPtr)
+        willCreatePossiblyOrphanedTreeByRemoval(&childToRemove);
+
     // FIXME: Move childrenChanged into ScriptDisallowedScope block.
     childrenChanged(change);
 
@@ -224,18 +230,26 @@
         dispatchChildInsertionEvents(child);
 }
 
-static ExceptionOr<void> collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes)
+ExceptionOr<void> ContainerNode::removeSelfOrChildNodesForInsertion(Node& child, NodeVector& nodesForInsertion)
 {
-    if (!is<DocumentFragment>(node)) {
-        nodes.append(node);
-        auto* oldParent = node.parentNode();
+    if (!is<DocumentFragment>(child)) {
+        nodesForInsertion.append(child);
+        auto oldParent = makeRefPtr(child.parentNode());
         if (!oldParent)
             return { };
-        return oldParent->removeChild(node);
+        return oldParent->removeChild(child);
     }
 
-    nodes = collectChildNodes(node);
-    downcast<DocumentFragment>(node).removeChildren();
+    auto& fragment = downcast<DocumentFragment>(child);
+    if (!fragment.hasChildNodes())
+        return { };
+
+    auto removedChildNodes = fragment.removeAllChildrenWithScriptAssertion(ContainerNode::ChildChange::Source::API);
+    nodesForInsertion.swap(removedChildNodes);
+
+    fragment.rebuildSVGExtensionsElementsIfNecessary();
+    fragment.dispatchSubtreeModifiedEvent();
+
     return { };
 }
 
@@ -393,13 +407,13 @@
     Ref<Node> next(*refChild);
 
     NodeVector targets;
-    auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
+    auto removeResult = removeSelfOrChildNodesForInsertion(newChild, targets);
     if (removeResult.hasException())
         return removeResult.releaseException();
     if (targets.isEmpty())
         return { };
 
-    // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
+    // We need this extra check because removeSelfOrChildNodesForInsertion() can fire mutation events.
     for (auto& child : targets) {
         auto checkAcceptResult = checkAcceptChildGuaranteedNodeTypes(*this, child);
         if (checkAcceptResult.hasException())
@@ -508,12 +522,12 @@
     NodeVector targets;
     {
         ChildListMutationScope mutation(*this);
-        auto collectResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
+        auto collectResult = removeSelfOrChildNodesForInsertion(newChild, targets);
         if (collectResult.hasException())
             return collectResult.releaseException();
     }
 
-    // Do this one more time because collectChildrenAndRemoveFromOldParent() fires a MutationEvent.
+    // Do this one more time because removeSelfOrChildNodesForInsertion() fires a MutationEvent.
     for (auto& child : targets) {
         validityResult = checkPreReplacementValidity(*this, child, oldChild, ShouldValidateChildParent::No);
         if (validityResult.hasException())
@@ -707,7 +721,7 @@
     Ref<ContainerNode> protectedThis(*this);
 
     NodeVector targets;
-    auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets);
+    auto removeResult = removeSelfOrChildNodesForInsertion(newChild, targets);
     if (removeResult.hasException())
         return removeResult.releaseException();
 
@@ -714,7 +728,7 @@
     if (targets.isEmpty())
         return { };
 
-    // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events.
+    // We need this extra check because removeSelfOrChildNodesForInsertion() can fire mutation events.
     for (auto& child : targets) {
         auto nodeTypeResult = checkAcceptChildGuaranteedNodeTypes(*this, child);
         if (nodeTypeResult.hasException())
@@ -857,10 +871,6 @@
     if (child->isInShadowTree())
         return;
 
-    // FIXME: This doesn't belong in dispatchChildRemovalEvents.
-    // FIXME: Nodes removed from a shadow tree should also be kept alive.
-    willCreatePossiblyOrphanedTreeByRemoval(child.ptr());
-
     Ref<Document> document = child->document();
 
     // dispatch pre-removal mutation events

Modified: branches/safari-611-branch/Source/WebCore/dom/ContainerNode.h (272941 => 272942)


--- branches/safari-611-branch/Source/WebCore/dom/ContainerNode.h	2021-02-17 01:15:05 UTC (rev 272941)
+++ branches/safari-611-branch/Source/WebCore/dom/ContainerNode.h	2021-02-17 01:15:19 UTC (rev 272942)
@@ -150,6 +150,7 @@
     enum class DeferChildrenChanged { Yes, No };
     NodeVector removeAllChildrenWithScriptAssertion(ChildChange::Source, DeferChildrenChanged = DeferChildrenChanged::No);
     bool removeNodeWithScriptAssertion(Node&, ChildChange::Source);
+    ExceptionOr<void> removeSelfOrChildNodesForInsertion(Node&, NodeVector&);
 
     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
     ExceptionOr<void> appendChildWithoutPreInsertionValidityCheck(Node&);

Modified: branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.cpp (272941 => 272942)


--- branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.cpp	2021-02-17 01:15:05 UTC (rev 272941)
+++ branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.cpp	2021-02-17 01:15:19 UTC (rev 272942)
@@ -107,49 +107,66 @@
     return postInsertionNotificationTargets;
 }
 
-static void notifyNodeRemovedFromDocument(ContainerNode& oldParentOfRemovedTree, TreeScopeChange treeScopeChange, Node& node)
+inline RemovedSubtreeObservability observabilityOfRemovedNode(Node& node)
 {
+    bool isRootOfRemovedTree = !node.parentNode();
+    return node.refCount() > 1 && !isRootOfRemovedTree ? RemovedSubtreeObservability::MaybeObservableByRefPtr : RemovedSubtreeObservability::NotObservable;
+}
+
+inline void updateObservability(RemovedSubtreeObservability& currentObservability, RemovedSubtreeObservability newStatus)
+{
+    if (newStatus == RemovedSubtreeObservability::MaybeObservableByRefPtr)
+        currentObservability = newStatus;
+}
+
+static RemovedSubtreeObservability notifyNodeRemovedFromDocument(ContainerNode& oldParentOfRemovedTree, TreeScopeChange treeScopeChange, Node& node)
+{
     ASSERT(oldParentOfRemovedTree.isConnected());
     ASSERT(node.isConnected());
     node.removedFromAncestor(Node::RemovalType { /* disconnectedFromDocument */ true, treeScopeChange == TreeScopeChange::Changed }, oldParentOfRemovedTree);
 
+    auto observability = observabilityOfRemovedNode(node);
     if (!is<ContainerNode>(node))
-        return;
+        return observability;
 
     for (RefPtr<Node> child = downcast<ContainerNode>(node).firstChild(); child; child = child->nextSibling()) {
         RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!node.isConnected() && child->parentNode() == &node);
-        notifyNodeRemovedFromDocument(oldParentOfRemovedTree, treeScopeChange, *child.get());
+        updateObservability(observability, notifyNodeRemovedFromDocument(oldParentOfRemovedTree, treeScopeChange, *child.get()));
     }
 
     if (!is<Element>(node))
-        return;
+        return observability;
 
     if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot()) {
         RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!node.isConnected() && root->host() == &node);
-        notifyNodeRemovedFromDocument(oldParentOfRemovedTree, TreeScopeChange::DidNotChange, *root.get());
+        updateObservability(observability, notifyNodeRemovedFromDocument(oldParentOfRemovedTree, TreeScopeChange::DidNotChange, *root.get()));
     }
+    return observability;
 }
 
-static void notifyNodeRemovedFromTree(ContainerNode& oldParentOfRemovedTree, TreeScopeChange treeScopeChange, Node& node)
+static RemovedSubtreeObservability notifyNodeRemovedFromTree(ContainerNode& oldParentOfRemovedTree, TreeScopeChange treeScopeChange, Node& node)
 {
     ASSERT(!oldParentOfRemovedTree.isConnected());
 
     node.removedFromAncestor(Node::RemovalType { /* disconnectedFromDocument */ false, treeScopeChange == TreeScopeChange::Changed }, oldParentOfRemovedTree);
 
+    auto observability = observabilityOfRemovedNode(node);
     if (!is<ContainerNode>(node))
-        return;
+        return observability;
 
     for (RefPtr<Node> child = downcast<ContainerNode>(node).firstChild(); child; child = child->nextSibling())
-        notifyNodeRemovedFromTree(oldParentOfRemovedTree, treeScopeChange, *child);
+        updateObservability(observability, notifyNodeRemovedFromTree(oldParentOfRemovedTree, treeScopeChange, *child));
 
     if (!is<Element>(node))
-        return;
+        return observability;
 
     if (RefPtr<ShadowRoot> root = downcast<Element>(node).shadowRoot())
-        notifyNodeRemovedFromTree(oldParentOfRemovedTree, TreeScopeChange::DidNotChange, *root);
+        updateObservability(observability, notifyNodeRemovedFromTree(oldParentOfRemovedTree, TreeScopeChange::DidNotChange, *root));
+
+    return observability;
 }
 
-void notifyChildNodeRemoved(ContainerNode& oldParentOfRemovedTree, Node& child)
+RemovedSubtreeObservability notifyChildNodeRemoved(ContainerNode& oldParentOfRemovedTree, Node& child)
 {
     // Assert that the caller of this function has an instance of ScriptDisallowedScope.
     ASSERT(!isMainThread() || ScriptDisallowedScope::InMainThread::hasDisallowedScope());
@@ -158,9 +175,8 @@
     // Tree scope has changed if the container node from which "node" is removed is in a document or a shadow root.
     auto treeScopeChange = oldParentOfRemovedTree.isInTreeScope() ? TreeScopeChange::Changed : TreeScopeChange::DidNotChange;
     if (child.isConnected())
-        notifyNodeRemovedFromDocument(oldParentOfRemovedTree, treeScopeChange, child);
-    else
-        notifyNodeRemovedFromTree(oldParentOfRemovedTree, treeScopeChange, child);
+        return notifyNodeRemovedFromDocument(oldParentOfRemovedTree, treeScopeChange, child);
+    return notifyNodeRemovedFromTree(oldParentOfRemovedTree, treeScopeChange, child);
 }
 
 void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode& container)

Modified: branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.h (272941 => 272942)


--- branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.h	2021-02-17 01:15:05 UTC (rev 272941)
+++ branches/safari-611-branch/Source/WebCore/dom/ContainerNodeAlgorithms.h	2021-02-17 01:15:19 UTC (rev 272942)
@@ -62,7 +62,11 @@
 #endif // not ASSERT_ENABLED
 
 NodeVector notifyChildNodeInserted(ContainerNode& parentOfInsertedTree, Node&);
-void notifyChildNodeRemoved(ContainerNode& oldParentOfRemovedTree, Node&);
+enum class RemovedSubtreeObservability {
+    NotObservable,
+    MaybeObservableByRefPtr,
+};
+RemovedSubtreeObservability notifyChildNodeRemoved(ContainerNode& oldParentOfRemovedTree, Node&);
 void removeDetachedChildrenInContainer(ContainerNode&);
 
 enum SubframeDisconnectPolicy {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to