Title: [225729] trunk/LayoutTests
Revision
225729
Author
[email protected]
Date
2017-12-09 18:53:29 -0800 (Sat, 09 Dec 2017)

Log Message

Add test demonstrating leaks that happen when we create reference cycles with DOM objects
https://bugs.webkit.org/show_bug.cgi?id=180323

Reviewed by Filip Pizlo.

* fast/dom/reference-cycle-leaks-expected.txt: Added.
* fast/dom/reference-cycle-leaks.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (225728 => 225729)


--- trunk/LayoutTests/ChangeLog	2017-12-09 21:42:02 UTC (rev 225728)
+++ trunk/LayoutTests/ChangeLog	2017-12-10 02:53:29 UTC (rev 225729)
@@ -1,3 +1,13 @@
+2017-12-09  Darin Adler  <[email protected]>
+
+        Add test demonstrating leaks that happen when we create reference cycles with DOM objects
+        https://bugs.webkit.org/show_bug.cgi?id=180323
+
+        Reviewed by Filip Pizlo.
+
+        * fast/dom/reference-cycle-leaks-expected.txt: Added.
+        * fast/dom/reference-cycle-leaks.html: Added.
+
 2017-12-09  Ryosuke Niwa  <[email protected]>
 
         iOS: Crash in Document::updateLayout() via Document::processViewport

Added: trunk/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt (0 => 225729)


--- trunk/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt	2017-12-10 02:53:29 UTC (rev 225729)
@@ -0,0 +1,24 @@
+Tests for leaks caused by reference cycles that pass through the DOM implementation
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS checkForNodeLeaks(emptyFunction) is "did not leak"
+PASS checkForNodeLeaks(createNode) is "did not leak"
+PASS checkForNodeLeaks(createEventListenerCycle) is "did not leak"
+PASS checkForNodeLeaks(createTreeWalkerNodeCycle) is "did not leak"
+PASS checkForNodeLeaks(createTreeWalkerFilterCycle) is "did not leak"
+PASS checkForNodeLeaks(createPromiseCycle) is "did not leak"
+FAIL checkForNodeLeaks(createCustomEventDetailsCycle) should be did not leak. Was leaked.
+FAIL checkForNodeLeaks(createErrorEventDataCycle) should be did not leak. Was leaked.
+---- Did not test ExtendableMessageEvent because it is not enabled.
+FAIL checkForNodeLeaks(createMessageEventDataCycle) should be did not leak. Was leaked.
+FAIL checkForNodeLeaks(createPopStateEventStateCycle) should be did not leak. Was leaked.
+FAIL checkForNodeLeaks(createPromiseRejectionEventPromiseCycle) should be did not leak. Was leaked.
+PASS checkForNodeLeaks(createPromiseRejectionEventPromiseFunctionCycle) is "did not leak"
+FAIL checkForNodeLeaks(createPromiseRejectionEventReasonCycle) should be did not leak. Was leaked.
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/reference-cycle-leaks.html (0 => 225729)


--- trunk/LayoutTests/fast/dom/reference-cycle-leaks.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/reference-cycle-leaks.html	2017-12-10 02:53:29 UTC (rev 225729)
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<script src=""
+<script>
+
+description('Tests for leaks caused by reference cycles that pass through the DOM implementation');
+
+function checkForNodeLeaks(testFunction, underlyingClass)
+{
+    // Bump this number as high as we need to, to get reproducible results.
+    const repetitions = 20;
+
+    gc();
+    const beforeCount = internals.numberOfLiveNodes();
+    for (var i = 0; i < repetitions; ++i)
+        testFunction();
+    gc();
+    const leaks = internals.numberOfLiveNodes() - beforeCount;
+
+    if (leaks == repetitions)
+        return "leaked";
+    if (leaks < repetitions / 10)
+        return "did not leak";
+    return "leaked an unexpected number of nodes: " + leaks + " leaks in " + repetitions + " runs";
+}
+
+function emptyFunction()
+{
+}
+
+function createNode()
+{
+    document.createTextNode("");
+}
+
+function createEventListenerCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.addEventListener("x", function () { return leakDetectionNode; });
+}
+
+function createPromiseCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    const promise = new Promise(function (resolve, reject) { });
+    promise.cycle = promise;
+    promise.leakDetectionNode = leakDetectionNode;
+}
+
+function createTreeWalkerNodeCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.treeWalker = document.createTreeWalker(leakDetectionNode);
+}
+
+function createTreeWalkerFilterCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    const filter = { leakDetectionNode: leakDetectionNode, acceptNode: function(node) { return leakDetectionNode; } };
+    leakDetectionNode.treeWalker = document.createTreeWalker(document, 0, filter);
+}
+
+function createCustomEventDetailsCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.event = new CustomEvent("x", { detail: leakDetectionNode });
+}
+
+function createErrorEventDataCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.event = new ErrorEvent("x", { error: leakDetectionNode });
+}
+
+function createExtendableMessageEventDataCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.event = new ExtendableMessageEvent("x", { data: leakDetectionNode });
+}
+
+function createMessageEventDataCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.event = new MessageEvent("x", { data: leakDetectionNode });
+}
+
+function createPromiseRejectionEventPromiseCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    const promise = new Promise(function (resolve, reject) { });
+    promise.leakDetectionNode = leakDetectionNode;
+    leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise });
+}
+
+function createPromiseRejectionEventPromiseFunctionCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    const promise = new Promise(function (resolve, reject) { return leakDetectionNode; });
+    leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise });
+}
+
+function createPromiseRejectionEventReasonCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    const promise = new Promise(function (resolve, reject) { });
+    leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise, reason: leakDetectionNode });
+}
+
+function createPopStateEventStateCycle()
+{
+    const leakDetectionNode = document.createTextNode("");
+    leakDetectionNode.event = new PopStateEvent("x", { state: leakDetectionNode });
+}
+
+function createIDBRequestResultCycle()
+{
+    // FIXME: Need to write this test and reorganize so it can be asynchronous.
+    // Get an IDBRequest with a result that is a structured clone (see IDBTransaction::didGetRecordOnServer).
+    // Add a property to the result object that references the request.
+    // Add another property to the result object that references a leak detection node.
+}
+
+function createPaymentResponseDetailsCycle()
+{
+    // FIXME: Need to write this test and reorganize so it can be asynchronous.
+    // Get a PaymentResponse, requires simulating a successful payment.
+    // Add a property to the details object that references the PaymentResponse.
+    // Add another property to the details object that references a leak detection node.
+}
+
+function createRTCStatsReportCycle()
+{
+    // FIXME: Need to write this test and reorganize so it can be asynchronous.
+    // Get an RTCStatsReport.
+    // Get one of the objects from the map.
+    // Add a property to that object that references the report.
+    // Add another property to that object that references a leak detection node.
+}
+
+function runLeakTest(testFunctionName, underlyingClassName)
+{
+    if (underlyingClassName && !(underlyingClassName in window))
+        debug('---- Did not test ' + underlyingClassName + ' because it is not enabled.');
+    else
+        shouldBeEqualToString('checkForNodeLeaks(' + testFunctionName + ')', 'did not leak');
+}
+
+function startTest()
+{
+    if (!window.internals || !internals.numberOfLiveNodes) {
+        testFailed('Test requires windows.internals, so must be run inside WebKitTestRunner');
+        return;
+    }
+
+    runLeakTest('emptyFunction');
+    runLeakTest('createNode');
+    runLeakTest('createEventListenerCycle');
+    runLeakTest('createTreeWalkerNodeCycle');
+    runLeakTest('createTreeWalkerFilterCycle');
+    runLeakTest('createPromiseCycle');
+
+    runLeakTest('createCustomEventDetailsCycle');
+    runLeakTest('createErrorEventDataCycle');
+    runLeakTest('createExtendableMessageEventDataCycle', 'ExtendableMessageEvent');
+    runLeakTest('createMessageEventDataCycle');
+    runLeakTest('createPopStateEventStateCycle');
+    runLeakTest('createPromiseRejectionEventPromiseCycle');
+    runLeakTest('createPromiseRejectionEventPromiseFunctionCycle');
+    runLeakTest('createPromiseRejectionEventReasonCycle');
+}
+
+startTest();
+
+</script>
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to