WebKit Bugzilla
Attachment 369738 Details for
Bug 197457
: The JS wrapper of target in an ResizeObserverEntry should not get collected
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197457-20190514002422.patch (text/plain), 22.89 KB, created by
cathiechen
on 2019-05-13 09:24:23 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
cathiechen
Created:
2019-05-13 09:24:23 PDT
Size:
22.89 KB
patch
obsolete
>Subversion Revision: 245053 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 6210b9469ac6fc157f4f8e0501aca11d5cb69199..74a16b9631815475608aea9210c3523b19da23f3 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,39 @@ >+2019-05-12 Cathie Chen <cathiechen@igalia.com> >+ >+ JS wrapper of target in an ResizeObserverEntry/ResizeObserver should not get collected >+ https://bugs.webkit.org/show_bug.cgi?id=197457 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The JS wrappers of targets in ResizeObserverEntry could be collected if no other reference to these targets. >+ In order to keep the JS wrappers alive, add targets to OpaqueRoot. >+ >+ For ResizeObserver, if targets removed from DOM tree, it will get fired for the last time. >+ So it should keep the JS wrappers alive from removing the target to ResizeObserver::deliverObservations. >+ Add these targets to a GCReachableRef list and clear the list during delivering. >+ >+ Tests: resize-observer/element-leak.html >+ resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html >+ resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html >+ >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * bindings/js/JSResizeObserverEntryCustom.cpp: Copied from Source/WebCore/page/ResizeObserverEntry.idl. >+ (WebCore::JSResizeObserverEntry::visitAdditionalChildren): >+ * dom/Document.cpp: >+ (WebCore::Document::nodeChildrenWillBeRemoved): >+ (WebCore::Document::nodeWillBeRemoved): >+ * dom/Element.cpp: >+ (WebCore::Element::addResizeObserverPendingTargetIfNeeded): >+ * dom/Element.h: >+ * page/ResizeObserver.cpp: >+ (WebCore::ResizeObserver::deliverObservations): >+ (WebCore::ResizeObserver::removeObservation): >+ (WebCore::ResizeObserver::addPendingTarget): >+ (WebCore::ResizeObserver::stop): >+ * page/ResizeObserver.h: >+ * page/ResizeObserverEntry.idl: >+ > 2019-05-08 Rob Buis <rbuis@igalia.com> > > Link prefetch not useful for top-level navigation >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index bcecba9089766f90f950c21783af62e118ffb6cc..a0afda01cf9c493ec2219d958e0a0a26d6ca44ed 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -530,6 +530,7 @@ bindings/js/JSPromiseRejectionEventCustom.cpp > bindings/js/JSReadableStreamSourceCustom.cpp > bindings/js/JSRemoteDOMWindowBase.cpp > bindings/js/JSRemoteDOMWindowCustom.cpp >+bindings/js/JSResizeObserverEntryCustom.cpp > bindings/js/JSSVGPathSegCustom.cpp > bindings/js/JSSVGViewSpecCustom.cpp > bindings/js/JSStyleSheetCustom.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 680d6446f594c5f5bce02500f0ac5151ff7759a6..e22fdf50154ea3b6b2d9086cedb8ccb59a68884a 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -8759,6 +8759,7 @@ > 585D6DFB1A15355600FA4F12 /* SimpleLineLayoutResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutResolver.cpp; sourceTree = "<group>"; }; > 585D6E011A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutFlowContents.cpp; sourceTree = "<group>"; }; > 585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutFlowContents.h; sourceTree = "<group>"; }; >+ 5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSResizeObserverEntryCustom.cpp; sourceTree = "<group>"; }; > 589556EC18D4A44000764B03 /* BorderEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderEdge.h; sourceTree = "<group>"; }; > 58AEE2F318D4BCCF0022E7FE /* BorderEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BorderEdge.cpp; sourceTree = "<group>"; }; > 58B2F9EA2232D43B00938D63 /* ResizeObserverEntry.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ResizeObserverEntry.idl; sourceTree = "<group>"; }; >@@ -20632,6 +20633,7 @@ > CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */, > 833CF70F20DB3F5F00141BCC /* JSPerformanceObserverCustom.cpp */, > A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */, >+ 5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */, > 83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */, > 460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */, > BC98A27C0C0C9950004BEBF7 /* JSStyleSheetCustom.cpp */, >diff --git a/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp b/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..6b2a4c2d34127cdc6e51d9431d2e90252f8b2e69 >--- /dev/null >+++ b/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp >@@ -0,0 +1,39 @@ >+/* >+ * Copyright (C) 2019 Igalia S.L. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "JSResizeObserverEntry.h" >+ >+#include "JSNodeCustom.h" >+ >+namespace WebCore { >+ >+void JSResizeObserverEntry::visitAdditionalChildren(JSC::SlotVisitor& visitor) >+{ >+ visitor.addOpaqueRoot(root(wrapped().target())); >+ visitor.addOpaqueRoot(wrapped().contentRect()); >+} >+ >+} >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index 86a2abd55b39e3e476715d4f01f4a89c83450535..bf0ed523c58f81997d2cb557dff6e5902730993c 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -4426,6 +4426,10 @@ void Document::nodeChildrenWillBeRemoved(ContainerNode& container) > frame->eventHandler().nodeWillBeRemoved(*n); > frame->selection().nodeWillBeRemoved(*n); > frame->page()->dragCaretController().nodeWillBeRemoved(*n); >+#if ENABLE(RESIZE_OBSERVER) >+ if (is<Element>(*n)) >+ downcast<Element>(*n).addResizeObserverPendingTargetIfNeeded(); >+#endif > } > } > >@@ -4456,6 +4460,10 @@ void Document::nodeWillBeRemoved(Node& node) > frame->eventHandler().nodeWillBeRemoved(node); > frame->selection().nodeWillBeRemoved(node); > frame->page()->dragCaretController().nodeWillBeRemoved(node); >+#if ENABLE(RESIZE_OBSERVER) >+ if (is<Element>(node)) >+ downcast<Element>(node).addResizeObserverPendingTargetIfNeeded(); >+#endif > } > > if (is<Text>(node)) >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index c4913bebf58c05ef9ff2c594e684514f943f490e..a9226276b6e435c56b0fddb8c03679422957ed61 100644 >--- a/Source/WebCore/dom/Element.cpp >+++ b/Source/WebCore/dom/Element.cpp >@@ -3558,6 +3558,19 @@ ResizeObserverData* Element::resizeObserverData() > { > return hasRareData() ? elementRareData()->resizeObserverData() : nullptr; > } >+ >+void Element::addResizeObserverPendingTargetIfNeeded() >+{ >+ if (!isConnected()) >+ return; >+ >+ auto* observerData = resizeObserverData(); >+ if (!observerData) >+ return; >+ >+ for (auto& observer : observerData->observers) >+ observer->addPendingTarget(*this); >+} > #endif > > SpellcheckAttributeState Element::spellcheckAttributeState() const >diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h >index 5f3f876268ca5687677a6710e3dce03554270fc2..68a61da382a986d67dc68770bf8a9e15748d716e 100644 >--- a/Source/WebCore/dom/Element.h >+++ b/Source/WebCore/dom/Element.h >@@ -594,6 +594,7 @@ public: > #if ENABLE(RESIZE_OBSERVER) > ResizeObserverData& ensureResizeObserverData(); > ResizeObserverData* resizeObserverData(); >+ void addResizeObserverPendingTargetIfNeeded(); > #endif > > Element* findAnchorElementForLink(String& outAnchorName); >diff --git a/Source/WebCore/page/ResizeObserver.cpp b/Source/WebCore/page/ResizeObserver.cpp >index 9ff2b6ebc455462e436166f9d35367ea7fde8d7a..25257316c59eb9db7e419724e15f4ed7ae43b3d3 100644 >--- a/Source/WebCore/page/ResizeObserver.cpp >+++ b/Source/WebCore/page/ResizeObserver.cpp >@@ -121,6 +121,7 @@ void ResizeObserver::deliverObservations() > entries.append(ResizeObserverEntry::create(observation->target(), observation->computeContentRect())); > } > m_activeObservations.clear(); >+ m_pendingTargets.clear(); > m_callback->handleEvent(entries, *this); > } > >@@ -145,6 +146,10 @@ void ResizeObserver::removeAllTargets() > > bool ResizeObserver::removeObservation(const Element& target) > { >+ m_pendingTargets.removeFirstMatching([&target](auto& pendingTarget) { >+ return pendingTarget.ptr() == ⌖ >+ }); >+ > m_activeObservations.removeFirstMatching([&target](auto& observation) { > return observation->target() == ⌖ > }); >@@ -154,6 +159,12 @@ bool ResizeObserver::removeObservation(const Element& target) > }); > } > >+void ResizeObserver::addPendingTarget(Element& target) >+{ >+ m_pendingTargets.append(target); >+} >+ >+ > bool ResizeObserver::hasPendingActivity() const > { > return (hasObservations() && m_document) || !m_activeObservations.isEmpty(); >@@ -173,7 +184,7 @@ void ResizeObserver::stop() > { > disconnect(); > m_callback = nullptr; >- m_observations.clear(); >+ m_pendingTargets.clear(); > m_activeObservations.clear(); > } > >diff --git a/Source/WebCore/page/ResizeObserver.h b/Source/WebCore/page/ResizeObserver.h >index a1819609f6e0c3ee55bcdca3ac221fcaaa86b6e6..d60648631d4429282044a403d5de865ba822b44b 100644 >--- a/Source/WebCore/page/ResizeObserver.h >+++ b/Source/WebCore/page/ResizeObserver.h >@@ -28,6 +28,7 @@ > #if ENABLE(RESIZE_OBSERVER) > > #include "ActiveDOMObject.h" >+#include "GCReachableRef.h" > #include "ResizeObservation.h" > #include "ResizeObserverCallback.h" > #include <wtf/RefCounted.h> >@@ -62,6 +63,8 @@ public: > bool hasSkippedObservations() const { return m_hasSkippedObservations; } > void setHasSkippedObservations(bool skipped) { m_hasSkippedObservations = skipped; } > >+ void addPendingTarget(Element&); >+ > // ActiveDOMObject. > bool hasPendingActivity() const override; > const char* activeDOMObjectName() const override; >@@ -80,6 +83,7 @@ private: > Vector<Ref<ResizeObservation>> m_observations; > > Vector<Ref<ResizeObservation>> m_activeObservations; >+ Vector<GCReachableRef<Element>> m_pendingTargets; > bool m_hasSkippedObservations { false }; > }; > >diff --git a/Source/WebCore/page/ResizeObserverEntry.idl b/Source/WebCore/page/ResizeObserverEntry.idl >index b051bb57bec6925add74acd265442df05f79832a..72f85dcfce6bc0aa62a8980e25363102bd3492b0 100644 >--- a/Source/WebCore/page/ResizeObserverEntry.idl >+++ b/Source/WebCore/page/ResizeObserverEntry.idl >@@ -28,7 +28,8 @@ > [ > Conditional=RESIZE_OBSERVER, > ImplementationLacksVTable, >- EnabledBySetting=ResizeObserver >+ EnabledBySetting=ResizeObserver, >+ JSCustomMarkFunction > ] interface ResizeObserverEntry { > readonly attribute Element target; > readonly attribute DOMRectReadOnly contentRect; >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 2f702f48d4ba65115347508448a8bff03bc7bda7..8a47ce8387f6050af2e09c8a96ca8969f86517b7 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,18 @@ >+2019-05-12 Cathie Chen <cathiechen@igalia.com> >+ >+ JS wrapper of target in an ResizeObserverEntry/ResizeObserver should not get collected >+ https://bugs.webkit.org/show_bug.cgi?id=197457 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * resize-observer/element-leak-expected.txt: Added. >+ * resize-observer/element-leak.html: Added. >+ * resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt: Added. >+ * resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html: Added. >+ * resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt: Added. >+ * resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html: Added. >+ * resize-observer/resources/element-leak-frame.html: Added. >+ > 2019-05-08 Rob Buis <rbuis@igalia.com> > > Link prefetch not useful for top-level navigation >diff --git a/LayoutTests/resize-observer/element-leak-expected.txt b/LayoutTests/resize-observer/element-leak-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..84ad90becdf909c19b9cb30e51ce5657bc14eb9f >--- /dev/null >+++ b/LayoutTests/resize-observer/element-leak-expected.txt >@@ -0,0 +1,4 @@ >+ >+PASS ResizeObserver implemented >+PASS test0: Test elements leak >+ >diff --git a/LayoutTests/resize-observer/element-leak.html b/LayoutTests/resize-observer/element-leak.html >new file mode 100644 >index 0000000000000000000000000000000000000000..7d3a9105db1196cb378365d89d60e08cf0ca3c29 >--- /dev/null >+++ b/LayoutTests/resize-observer/element-leak.html >@@ -0,0 +1,74 @@ >+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<html> >+<head> >+<script src="../resources/testharness.js"></script> >+<script src="../resources/testharnessreport.js"></script> >+<script src="../resources/gc.js"></script> >+</head> >+<body> >+<div id="mylog"></div> >+<iframe id="testFrame" src="resources/element-leak-frame.html"></iframe> >+<script> >+if (window.testRunner) >+ testRunner.dumpAsText(); >+ >+var testresult; >+function log(text) { >+ document.getElementById('mylog').textContent += text + `${internals.numberOfLiveNodes()}` + ` | `; >+} >+ >+function documentShouldDie(documentIdentifier) >+{ >+ return new Promise(function(resolve, reject) { >+ handle = setInterval(function() { >+ log('gc begin: '); >+ gc(); >+ log('gc end: '); >+ if (internals && !internals.isDocumentAlive(documentIdentifier)) { >+ clearInterval(handle); >+ resolve(); >+ testresult = true; >+ log('resolved: '); >+ } >+ }, 10); >+ }); >+} >+ >+function test0() { >+ let test = async_test('test0: Test elements leak'); >+ window.addEventListener('message', event => { >+ switch(event.data) { >+ case 'Notified': >+ log('notified with livenodes: '); >+ test.step( () => { >+ var testFrame = document.getElementById("testFrame"); >+ let frameDocumentIdentifier = internals.documentIdentifier(testFrame.contentDocument); >+ testFrame.remove(); >+ log('frame removed: '); >+ documentShouldDie(frameDocumentIdentifier).then(function() { >+ assert_true(testresult, 'element leaking'); >+ test.done(); >+ }); >+ >+ }); >+ break; >+ } >+ }, false); >+ >+ test.step_timeout(() => { >+ testresult = false; >+ assert_true(testresult, 'element leaking'); >+ log('timeout: '); >+ test.done(); >+ }, 5000); >+} >+ >+test(_ => { >+ assert_own_property(window, "ResizeObserver"); >+}, "ResizeObserver implemented"); >+ >+test0(); >+ >+</script> >+</body> >+</html> >diff --git a/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt b/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a5be9926a5a122dc0b0441c66c1ade67718b3e55 >--- /dev/null >+++ b/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt >@@ -0,0 +1,22 @@ >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications. >+This tests that JS wrappers of targets in an ResizeObserverEntry do not get collected. >+ >+PASS >+PASS >+PASS >+PASS >+PASS >+PASS >+PASS >+PASS >+PASS >+PASS >+ >diff --git a/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html b/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html >new file mode 100644 >index 0000000000000000000000000000000000000000..0c2fb46c635fa489e73f4b19d356ec89dff2eae0 >--- /dev/null >+++ b/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html >@@ -0,0 +1,60 @@ >+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<html> >+<body> >+<p>This tests that JS wrappers of targets in an ResizeObserverEntry do not get collected.</p> >+<pre id="log"></pre> >+<script src="../resources/gc.js"></script> >+<script> >+ >+if (window.testRunner) >+ testRunner.dumpAsText(); >+ >+const targetCount = 5; >+const iterationCount = 10; >+ >+async function observe() { >+ for (let i = 0; i < targetCount; ++i) { >+ let target = document.createElement('div'); >+ target.myState = 'live'; >+ document.body.appendChild(target); >+ } >+ >+ return new Promise((resolve) => { >+ const observer = new ResizeObserver(entries => { >+ resolve(entries); >+ observer.disconnect(); >+ }); >+ document.querySelectorAll('div').forEach(target => { observer.observe(target); }); >+ }); >+} >+ >+function check(entries) { >+ let deadCount = 0; >+ for (const entry of entries) { >+ if (entry.target.myState != 'live') >+ deadCount++; >+ } >+ document.getElementById('log').textContent += (deadCount ? `FAIL - ${deadCount} targets lost JS wrappers` : 'PASS') + '\n'; >+} >+ >+async function runAll() { >+ if (window.testRunner) >+ testRunner.waitUntilDone(); >+ >+ for (let j = 0; j < iterationCount; ++j) { >+ const entries = await observe(); >+ document.querySelectorAll('div').forEach(target => { target.remove(); }); >+ await Promise.resolve(); >+ gc(); >+ check(entries); >+ } >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+ >+runAll(); >+ >+</script> >+</body> >+</html> >diff --git a/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt b/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..1fe5345c387b0760b2ebea7d982807bc400fd6d8 >--- /dev/null >+++ b/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt >@@ -0,0 +1,4 @@ >+This tests that JS wrappers of targets removed from document to be delivered to an resize observer do not get collected. >+ >+PASS >+ >diff --git a/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html b/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html >new file mode 100644 >index 0000000000000000000000000000000000000000..3dff784c9e894700ec72472934e702ce8a16da09 >--- /dev/null >+++ b/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html >@@ -0,0 +1,55 @@ >+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<html> >+<body> >+<p>This tests that JS wrappers of targets removed from document to be delivered to an resize observer do not get collected.</p> >+<pre id="log"></pre> >+<script src="../resources/gc.js"></script> >+<script> >+ >+if (window.testRunner) >+ testRunner.dumpAsText(); >+ >+const targetCount = 5; >+const iterationCount = 10; >+var deadCount = 0; >+ >+async function runAll() { >+ if (window.testRunner) >+ testRunner.waitUntilDone(); >+ >+ for (let i = 0; i < iterationCount; ++i) { >+ runTest(); >+ gc(); >+ await new Promise((resolve) => requestAnimationFrame(resolve)) >+ } >+ >+ document.getElementById('log').textContent = (deadCount ? `FAIL - ${deadCount} targets lost JS wrappers` : 'PASS') + '\n'; >+ >+ if (window.testRunner) >+ testRunner.notifyDone(); >+} >+ >+function runTest() { >+ document.querySelectorAll('div').forEach(target => { target.remove(); }); >+ >+ for (let i = 0; i < targetCount; ++i) { >+ let target = document.createElement('div'); >+ target.myState = 'live'; >+ document.body.appendChild(target); >+ } >+ >+ document.querySelectorAll('div').forEach(target => { observer.observe(target); }); >+} >+ >+const observer = new ResizeObserver(entries => { >+ for (const entry of entries) { >+ if (entry.target.myState != 'live') >+ deadCount++; >+ } >+}); >+ >+runAll(); >+ >+</script> >+</body> >+</html> >diff --git a/LayoutTests/resize-observer/resources/element-leak-frame.html b/LayoutTests/resize-observer/resources/element-leak-frame.html >new file mode 100644 >index 0000000000000000000000000000000000000000..e4bf7981f739db0d0d9273287fa929069af6c0d9 >--- /dev/null >+++ b/LayoutTests/resize-observer/resources/element-leak-frame.html >@@ -0,0 +1,25 @@ >+<body></body> >+<script type="text/javascript"> >+ >+const targetCount = 1000; >+ >+var ro = new ResizeObserver( entries => { >+ for (let entry of entries) { >+ entry.target.myEntry = entry; >+ entry.target.remove(); >+ } >+ ro.disconnect(); >+ parent.postMessage('Notified', '*') >+}); >+ >+ >+for (let i = 0; i < targetCount; ++i) { >+ var target = document.createElement('div'); >+ document.body.appendChild(target); >+} >+ >+document.querySelectorAll('div').forEach(target => { >+ ro.observe(target); >+}); >+ >+</script> >\ No newline at end of file
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ews-watchlist
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197457
:
368670
|
369394
|
369426
|
369680
|
369681
|
369683
|
369738
|
369746
|
369752
|
369755
|
369756
|
369764
|
369833
|
369837
|
369840
|
369844
|
369845
|
369846
|
369847
|
369848
|
369854
|
369861
|
369862
|
369866
|
369870
|
369876
|
369877
|
369921
|
369922
|
369923
|
369925
|
369926
|
369927
|
369935
|
369942
|
370111
|
370681
|
371183
|
371186
|
371241