Diff
Modified: trunk/LayoutTests/ChangeLog (246056 => 246057)
--- trunk/LayoutTests/ChangeLog 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/LayoutTests/ChangeLog 2019-06-04 07:38:17 UTC (rev 246057)
@@ -1,3 +1,19 @@
+2019-06-04 Cathie Chen <[email protected]>
+
+ JS wrapper of target in ResizeObserverEntry/ResizeObserver shouldn't get collected ahead
+ https://bugs.webkit.org/show_bug.cgi?id=197457
+
+ Reviewed by Ryosuke Niwa.
+
+ * platform/win/TestExpectations:
+ * 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-06-03 Youenn Fablet <[email protected]>
Allow resizing of camera video feeds to very small resolutions
Modified: trunk/LayoutTests/platform/win/TestExpectations (246056 => 246057)
--- trunk/LayoutTests/platform/win/TestExpectations 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/LayoutTests/platform/win/TestExpectations 2019-06-04 07:38:17 UTC (rev 246057)
@@ -4401,3 +4401,7 @@
webkit.org/b/195623 http/tests/cache/link-prefetch-main-resource-iframe.html [ Skip ]
webkit.org/b/198112 http/tests/security/showModalDialog-sync-cross-origin-page-load2.html [ Skip ]
+
+# The removed elements couldn't be released properly in Win.
+# The relevant bug is https://bugs.webkit.org/show_bug.cgi?id=197908
+resize-observer/element-leak.html [ Skip ]
Added: trunk/LayoutTests/resize-observer/element-leak-expected.txt (0 => 246057)
--- trunk/LayoutTests/resize-observer/element-leak-expected.txt (rev 0)
+++ trunk/LayoutTests/resize-observer/element-leak-expected.txt 2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,4 @@
+
+PASS ResizeObserver implemented
+PASS Test elements leak
+
Added: trunk/LayoutTests/resize-observer/element-leak.html (0 => 246057)
--- trunk/LayoutTests/resize-observer/element-leak.html (rev 0)
+++ trunk/LayoutTests/resize-observer/element-leak.html 2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,42 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] -->
+<html>
+<meta name="timeout" content="long">
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<iframe id="testFrame" src=""
+<script>
+
+test(_ => {
+ assert_own_property(window, "ResizeObserver");
+}, "ResizeObserver implemented");
+
+promise_test(async () => {
+ return new Promise(function(resolve, reject) {
+ window.addEventListener('message', event => {
+ switch(event.data) {
+ case 'Notified':
+ var testFrame = document.getElementById("testFrame");
+ let frameDocumentIdentifier = internals.documentIdentifier(testFrame.contentDocument);
+ testFrame.remove();
+
+ handle = setInterval(function() {
+ gc();
+ if (internals && !internals.isDocumentAlive(frameDocumentIdentifier)) {
+ clearInterval(handle);
+ resolve();
+ }
+ }, 10);
+ break;
+ }
+ }, false);
+ setTimeout(() => reject("Test timed out"), 5000);
+ });
+}, 'Test elements leak');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt (0 => 246057)
--- trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt 2019-06-04 07:38:17 UTC (rev 246057)
@@ -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
+
Added: trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html (0 => 246057)
--- trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html 2019-06-04 07:38:17 UTC (rev 246057)
@@ -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=""
+<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>
Added: trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt (0 => 246057)
--- trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt 2019-06-04 07:38:17 UTC (rev 246057)
@@ -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
+
Added: trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html (0 => 246057)
--- trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html 2019-06-04 07:38:17 UTC (rev 246057)
@@ -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=""
+<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>
Added: trunk/LayoutTests/resize-observer/resources/element-leak-frame.html (0 => 246057)
--- trunk/LayoutTests/resize-observer/resources/element-leak-frame.html (rev 0)
+++ trunk/LayoutTests/resize-observer/resources/element-leak-frame.html 2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<body></body>
+<script src=""
+<script type="text/_javascript_">
+
+const targetCount = 1000;
+var resizeObserver = new ResizeObserver( entries => {
+ for (let entry of entries)
+ entry.target.myEntry = entry;
+
+ resizeObserver.disconnect();
+ document.querySelectorAll('div').forEach(target => target.remove());
+ // Make sure targets be added to m_opaqueRoots.
+ gc();
+ parent.postMessage('Notified', '*');
+});
+
+for (let i = 0; i < targetCount; ++i) {
+ var target = document.createElement('div');
+ document.body.appendChild(target);
+}
+
+document.querySelectorAll('div').forEach(target => resizeObserver.observe(target));
+
+</script>
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (246056 => 246057)
--- trunk/Source/WebCore/ChangeLog 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/ChangeLog 2019-06-04 07:38:17 UTC (rev 246057)
@@ -1,3 +1,33 @@
+2019-06-04 Cathie Chen <[email protected]>
+
+ JS wrapper of target in ResizeObserverEntry/ResizeObserver shouldn't get collected ahead
+ https://bugs.webkit.org/show_bug.cgi?id=197457
+
+ Reviewed by Ryosuke Niwa.
+
+ Add JSCustomMarkFunction to make sure JS wrappers wouldn't be collected when JSResizeObserverEntry live.
+
+ For ResizeObserver, if targets are removed, it will get fired for the last time. We also need to keep these JS
+ wrappers live. So add these targets to a GCReachableRef list once they're observed.
+
+ Add element-leak.html to test the targets with `entry.target.myEntry = entry` could be released properly.
+
+ 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: Added.
+ (WebCore::JSResizeObserverEntry::visitAdditionalChildren):
+ * page/ResizeObserver.cpp:
+ (WebCore::ResizeObserver::observe):
+ (WebCore::ResizeObserver::removeAllTargets):
+ (WebCore::ResizeObserver::removeObservation):
+ (WebCore::ResizeObserver::stop):
+ * page/ResizeObserver.h:
+ * page/ResizeObserverEntry.idl:
+
2019-06-03 Andy Estes <[email protected]>
[Apple Pay] Disable script injection when canMakePayment APIs are called and return true
Modified: trunk/Source/WebCore/Sources.txt (246056 => 246057)
--- trunk/Source/WebCore/Sources.txt 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/Sources.txt 2019-06-04 07:38:17 UTC (rev 246057)
@@ -533,6 +533,7 @@
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
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (246056 => 246057)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-06-04 07:38:17 UTC (rev 246057)
@@ -8793,6 +8793,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>"; };
@@ -20690,6 +20691,7 @@
CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */,
833CF70F20DB3F5F00141BCC /* JSPerformanceObserverCustom.cpp */,
A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */,
+ 5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */,
83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */,
460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */,
BC98A27C0C0C9950004BEBF7 /* JSStyleSheetCustom.cpp */,
Copied: trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp (from rev 246056, trunk/Source/WebCore/page/ResizeObserverEntry.idl) (0 => 246057)
--- trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp 2019-06-04 07:38:17 UTC (rev 246057)
@@ -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());
+}
+
+}
Modified: trunk/Source/WebCore/page/ResizeObserver.cpp (246056 => 246057)
--- trunk/Source/WebCore/page/ResizeObserver.cpp 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserver.cpp 2019-06-04 07:38:17 UTC (rev 246057)
@@ -69,6 +69,7 @@
observerData.observers.append(makeWeakPtr(this));
m_observations.append(ResizeObservation::create(&target));
+ m_pendingTargets.append(target);
if (m_document) {
m_document->addResizeObserver(*this);
@@ -140,11 +141,17 @@
bool removed = removeTarget(*observation->target());
ASSERT_UNUSED(removed, removed);
}
+ m_pendingTargets.clear();
+ m_activeObservations.clear();
m_observations.clear();
}
bool ResizeObserver::removeObservation(const Element& target)
{
+ m_pendingTargets.removeFirstMatching([&target](auto& pendingTarget) {
+ return pendingTarget.ptr() == ⌖
+ });
+
m_activeObservations.removeFirstMatching([&target](auto& observation) {
return observation->target() == ⌖
});
@@ -173,8 +180,6 @@
{
disconnect();
m_callback = nullptr;
- m_observations.clear();
- m_activeObservations.clear();
}
} // namespace WebCore
Modified: trunk/Source/WebCore/page/ResizeObserver.h (246056 => 246057)
--- trunk/Source/WebCore/page/ResizeObserver.h 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserver.h 2019-06-04 07:38:17 UTC (rev 246057)
@@ -28,6 +28,7 @@
#if ENABLE(RESIZE_OBSERVER)
#include "ActiveDOMObject.h"
+#include "GCReachableRef.h"
#include "ResizeObservation.h"
#include "ResizeObserverCallback.h"
#include <wtf/RefCounted.h>
@@ -80,6 +81,7 @@
Vector<Ref<ResizeObservation>> m_observations;
Vector<Ref<ResizeObservation>> m_activeObservations;
+ Vector<GCReachableRef<Element>> m_pendingTargets;
bool m_hasSkippedObservations { false };
};
Modified: trunk/Source/WebCore/page/ResizeObserverEntry.idl (246056 => 246057)
--- trunk/Source/WebCore/page/ResizeObserverEntry.idl 2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserverEntry.idl 2019-06-04 07:38:17 UTC (rev 246057)
@@ -28,7 +28,8 @@
[
Conditional=RESIZE_OBSERVER,
ImplementationLacksVTable,
- EnabledBySetting=ResizeObserver
+ EnabledBySetting=ResizeObserver,
+ JSCustomMarkFunction
] interface ResizeObserverEntry {
readonly attribute Element target;
readonly attribute DOMRectReadOnly contentRect;