Title: [135228] trunk
Revision
135228
Author
ad...@chromium.org
Date
2012-11-19 18:16:33 -0800 (Mon, 19 Nov 2012)

Log Message

MutationObserver wrapper should not be collected while still observing
https://bugs.webkit.org/show_bug.cgi?id=102328

Reviewed by Adam Barth.

Source/WebCore:

Use the new opaqueRootForGC helper in V8GCController to put each
MutationObserver wrapper in the same object group as the nodes it's
observing.

Only includes V8 impl for now, JSC impl coming soon.

Tests: fast/mutation/observer-wrapper-dropoff-transient.html
       fast/mutation/observer-wrapper-dropoff.html

* bindings/v8/V8GCController.cpp: Add custom code for MutationObserver
with a FIXME to move this out once we update the opaque roots API.
* dom/MutationObserver.cpp:
(WebCore::MutationObserver::getObservedNodes): Plumbing to expose the observed nodes
to the GC controller.
(WebCore):
* dom/MutationObserver.h:
* dom/MutationObserverRegistration.cpp:
(WebCore::MutationObserverRegistration::addRegistrationNodesToSet): More plumbing.
(WebCore):
* dom/MutationObserverRegistration.h:
(MutationObserverRegistration):

LayoutTests:

Tests showing that observers are kept alive, both in the simple case
and in the transient registered observer case (where the original
registration node is GCed but the transient observation node is still
alive).

* fast/mutation/observer-wrapper-dropoff-expected.txt: Added.
* fast/mutation/observer-wrapper-dropoff-transient-expected.txt: Added.
* fast/mutation/observer-wrapper-dropoff-transient.html: Added.
* fast/mutation/observer-wrapper-dropoff.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (135227 => 135228)


--- trunk/LayoutTests/ChangeLog	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/ChangeLog	2012-11-20 02:16:33 UTC (rev 135228)
@@ -1,3 +1,20 @@
+2012-11-19  Adam Klein  <ad...@chromium.org>
+
+        MutationObserver wrapper should not be collected while still observing
+        https://bugs.webkit.org/show_bug.cgi?id=102328
+
+        Reviewed by Adam Barth.
+
+        Tests showing that observers are kept alive, both in the simple case
+        and in the transient registered observer case (where the original
+        registration node is GCed but the transient observation node is still
+        alive).
+
+        * fast/mutation/observer-wrapper-dropoff-expected.txt: Added.
+        * fast/mutation/observer-wrapper-dropoff-transient-expected.txt: Added.
+        * fast/mutation/observer-wrapper-dropoff-transient.html: Added.
+        * fast/mutation/observer-wrapper-dropoff.html: Added.
+
 2012-11-19  Tony Chang  <t...@chromium.org>
 
         Move more non-settings out of InternalSettings

Added: trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-expected.txt (0 => 135228)


--- trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-expected.txt	2012-11-20 02:16:33 UTC (rev 135228)
@@ -0,0 +1,10 @@
+MutationObserver wrappers should survive GC for passing into the callback even if JS has lost references.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS observer.testProperty is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient-expected.txt (0 => 135228)


--- trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient-expected.txt	2012-11-20 02:16:33 UTC (rev 135228)
@@ -0,0 +1,10 @@
+MutationObserver wrappers should survive GC for passing into the callback even if JS has lost references and the only remaining observations are transient.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS observer.testProperty is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient.html (0 => 135228)


--- trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff-transient.html	2012-11-20 02:16:33 UTC (rev 135228)
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+
+<script src=""
+
+<script>
+description('MutationObserver wrappers should survive GC for passing into the callback even if JS has lost references and the only remaining observations are transient.');
+
+jsTestIsAsync = true;
+
+function addObserver(node, fn) {
+    var observer = new WebKitMutationObserver(fn);
+    observer.testProperty = true;
+    observer.observe(node, {attributes:true, subtree: true});
+}
+
+_onload_ = function() {
+    var root = document.createElement('div');
+    var child = root.appendChild(document.createElement('span'));
+    addObserver(root, function(records, observer) {
+        window.observer = observer;
+        shouldBe('observer.testProperty', 'true');
+        finishJSTest();
+    });
+
+    root.removeChild(child);
+    child.setAttribute('foo', 'bar');
+    root = null;
+
+    gc();
+};
+</script>
+
+<script src=""

Added: trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff.html (0 => 135228)


--- trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mutation/observer-wrapper-dropoff.html	2012-11-20 02:16:33 UTC (rev 135228)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+
+<script src=""
+
+<script>
+description('MutationObserver wrappers should survive GC for passing into the callback even if JS has lost references.');
+
+jsTestIsAsync = true;
+
+function addObserver(node, fn) {
+    var observer = new WebKitMutationObserver(fn);
+    observer.testProperty = true;
+    observer.observe(node, {attributes:true});
+}
+
+_onload_ = function() {
+    addObserver(document.body, function(records, observer) {
+        window.observer = observer;
+        shouldBe('observer.testProperty', 'true');
+        finishJSTest();
+    });
+
+    gc();
+
+    document.body.setAttribute('touch', 'the node');
+};
+</script>
+
+<script src=""

Modified: trunk/LayoutTests/platform/efl/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/efl/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/efl/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -1713,3 +1713,6 @@
 webkit.org/b/102367 fast/forms/zoomed-controls.html [ ImageOnlyFailure Missing ]
 
 webkit.org/b/102493 fast/events/mouse-cursor.html [ Failure ]
+
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -1387,6 +1387,9 @@
 
 webkit.org/b/102586 media/video-src-blob.html [ Failure ]
 
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]
+
 #////////////////////////////////////////////////////////////////////////////////////////
 # End of Tests failing
 #////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/LayoutTests/platform/mac/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/mac/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -1193,3 +1193,6 @@
 
 # Hangs safari apparently due to an issue with weird multi-frame CUR image files
 webkit.org/b/101811 fast/events/mouse-cursor-multiframecur.html [ Skip ]
+
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]

Modified: trunk/LayoutTests/platform/qt/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/qt/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/qt/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -2386,3 +2386,6 @@
 
 # [Qt] fast/block/float/overhanging-tall-block.html asserts after r135025
 webkit.org/b/102675 [ Debug ] fast/block/float/overhanging-tall-block.html
+
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]

Modified: trunk/LayoutTests/platform/win/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/win/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/win/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -2430,3 +2430,6 @@
 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited.html
 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last.html
 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line.html
+
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]

Modified: trunk/LayoutTests/platform/wincairo/TestExpectations (135227 => 135228)


--- trunk/LayoutTests/platform/wincairo/TestExpectations	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/LayoutTests/platform/wincairo/TestExpectations	2012-11-20 02:16:33 UTC (rev 135228)
@@ -2961,3 +2961,6 @@
 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited.html
 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last.html
 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line.html
+
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff.html [ Skip ]
+webkit.org/b/102744 fast/mutation/observer-wrapper-dropoff-transient.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (135227 => 135228)


--- trunk/Source/WebCore/ChangeLog	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/ChangeLog	2012-11-20 02:16:33 UTC (rev 135228)
@@ -1,3 +1,32 @@
+2012-11-19  Adam Klein  <ad...@chromium.org>
+
+        MutationObserver wrapper should not be collected while still observing
+        https://bugs.webkit.org/show_bug.cgi?id=102328
+
+        Reviewed by Adam Barth.
+
+        Use the new opaqueRootForGC helper in V8GCController to put each
+        MutationObserver wrapper in the same object group as the nodes it's
+        observing.
+
+        Only includes V8 impl for now, JSC impl coming soon.
+
+        Tests: fast/mutation/observer-wrapper-dropoff-transient.html
+               fast/mutation/observer-wrapper-dropoff.html
+
+        * bindings/v8/V8GCController.cpp: Add custom code for MutationObserver
+        with a FIXME to move this out once we update the opaque roots API.
+        * dom/MutationObserver.cpp:
+        (WebCore::MutationObserver::getObservedNodes): Plumbing to expose the observed nodes
+        to the GC controller.
+        (WebCore):
+        * dom/MutationObserver.h:
+        * dom/MutationObserverRegistration.cpp:
+        (WebCore::MutationObserverRegistration::addRegistrationNodesToSet): More plumbing.
+        (WebCore):
+        * dom/MutationObserverRegistration.h:
+        (MutationObserverRegistration):
+
 2012-11-19  Tony Chang  <t...@chromium.org>
 
         Move more non-settings out of InternalSettings

Modified: trunk/Source/WebCore/bindings/v8/V8GCController.cpp (135227 => 135228)


--- trunk/Source/WebCore/bindings/v8/V8GCController.cpp	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/bindings/v8/V8GCController.cpp	2012-11-20 02:16:33 UTC (rev 135228)
@@ -38,6 +38,7 @@
 #include "V8AbstractEventListener.h"
 #include "V8Binding.h"
 #include "V8MessagePort.h"
+#include "V8MutationObserver.h"
 #include "V8Node.h"
 #include "V8RecursionScope.h"
 #include "WrapperTypeInfo.h"
@@ -176,6 +177,14 @@
             MessagePort* port = static_cast<MessagePort*>(object);
             if (port->isEntangled() || port->hasPendingActivity())
                 m_grouper.keepAlive(wrapper);
+#if ENABLE(MUTATION_OBSERVERS)
+        } else if (V8MutationObserver::info.equals(type)) {
+            // FIXME: Allow opaqueRootForGC to operate on multiple roots and move this logic into V8MutationObserverCustom.
+            MutationObserver* observer = static_cast<MutationObserver*>(object);
+            HashSet<Node*> observedNodes = observer->getObservedNodes();
+            for (HashSet<Node*>::iterator it = observedNodes.begin(); it != observedNodes.end(); ++it)
+                m_grouper.addToGroup(V8GCController::opaqueRootForGC(*it), wrapper);
+#endif // ENABLE(MUTATION_OBSERVERS)
         } else {
             ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper);
             if (activeDOMObject && activeDOMObject->hasPendingActivity())

Modified: trunk/Source/WebCore/dom/MutationObserver.cpp (135227 => 135228)


--- trunk/Source/WebCore/dom/MutationObserver.cpp	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/dom/MutationObserver.cpp	2012-11-20 02:16:33 UTC (rev 135228)
@@ -167,6 +167,14 @@
     activeMutationObservers().add(this);
 }
 
+HashSet<Node*> MutationObserver::getObservedNodes() const
+{
+    HashSet<Node*> observedNodes;
+    for (HashSet<MutationObserverRegistration*>::const_iterator iter = m_registrations.begin(); iter != m_registrations.end(); ++iter)
+        (*iter)->addRegistrationNodesToSet(observedNodes);
+    return observedNodes;
+}
+
 void MutationObserver::deliver()
 {
     // Calling clearTransientRegistrations() can modify m_registrations, so it's necessary

Modified: trunk/Source/WebCore/dom/MutationObserver.h (135227 => 135228)


--- trunk/Source/WebCore/dom/MutationObserver.h	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/dom/MutationObserver.h	2012-11-20 02:16:33 UTC (rev 135228)
@@ -87,6 +87,8 @@
     void enqueueMutationRecord(PassRefPtr<MutationRecord>);
     void setHasTransientRegistration();
 
+    HashSet<Node*> getObservedNodes() const;
+
 private:
     struct ObserverLessThan;
 

Modified: trunk/Source/WebCore/dom/MutationObserverRegistration.cpp (135227 => 135228)


--- trunk/Source/WebCore/dom/MutationObserverRegistration.cpp	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/dom/MutationObserverRegistration.cpp	2012-11-20 02:16:33 UTC (rev 135228)
@@ -124,6 +124,15 @@
     return m_attributeFilter.contains(attributeName->localName());
 }
 
+void MutationObserverRegistration::addRegistrationNodesToSet(HashSet<Node*>& nodes) const
+{
+    nodes.add(m_registrationNode);
+    if (!m_transientRegistrationNodes)
+        return;
+    for (NodeHashSet::const_iterator iter = m_transientRegistrationNodes->begin(); iter != m_transientRegistrationNodes->end(); ++iter)
+        nodes.add(iter->get());
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MUTATION_OBSERVERS)

Modified: trunk/Source/WebCore/dom/MutationObserverRegistration.h (135227 => 135228)


--- trunk/Source/WebCore/dom/MutationObserverRegistration.h	2012-11-20 02:11:53 UTC (rev 135227)
+++ trunk/Source/WebCore/dom/MutationObserverRegistration.h	2012-11-20 02:16:33 UTC (rev 135228)
@@ -60,6 +60,8 @@
     MutationRecordDeliveryOptions deliveryOptions() const { return m_options & (MutationObserver::AttributeOldValue | MutationObserver::CharacterDataOldValue); }
     MutationObserverOptions mutationTypes() const { return m_options & MutationObserver::AllMutationTypes; }
 
+    void addRegistrationNodesToSet(HashSet<Node*>&) const;
+
 private:
     MutationObserverRegistration(PassRefPtr<MutationObserver>, Node*, MutationObserverOptions, const HashSet<AtomicString>& attributeFilter);
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to