Diff
Modified: trunk/LayoutTests/ChangeLog (268859 => 268860)
--- trunk/LayoutTests/ChangeLog 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/LayoutTests/ChangeLog 2020-10-22 12:41:10 UTC (rev 268860)
@@ -1,3 +1,13 @@
+2020-10-22 Cathie Chen <[email protected]>
+
+ ResizeObserver is not properly garbage collected
+ https://bugs.webkit.org/show_bug.cgi?id=215158
+
+ Reviewed by Frédéric Wang.
+
+ * resize-observer/resize-observer-callback-leak-expected.txt: Added.
+ * resize-observer/resize-observer-callback-leak.html: Added.
+
2020-10-22 Martin Robinson <[email protected]>
Scroll snap: don't create implicit snap points at scrollmin/scrollmax
Added: trunk/LayoutTests/resize-observer/resize-observer-callback-leak-expected.txt (0 => 268860)
--- trunk/LayoutTests/resize-observer/resize-observer-callback-leak-expected.txt (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-callback-leak-expected.txt 2020-10-22 12:41:10 UTC (rev 268860)
@@ -0,0 +1,4 @@
+
+PASS ResizeObserver implemented
+PASS test: Resize observer inside callback should be garbage collected if no one refers to it
+
Added: trunk/LayoutTests/resize-observer/resize-observer-callback-leak.html (0 => 268860)
--- trunk/LayoutTests/resize-observer/resize-observer-callback-leak.html (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-callback-leak.html 2020-10-22 12:41:10 UTC (rev 268860)
@@ -0,0 +1,47 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] -->
+<html>
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="container"></div>
+<script>
+function accessToObserverInCallback() {
+ let test = async_test("test: Resize observer inside callback should be garbage collected if no one refers to it");
+ let initialObserverCount = internals.numberOfResizeObservers(document);
+ const iterationCount = 50;
+ let callbackCount = 0;
+ for (let j = 0; j < iterationCount; ++j) {
+ const div = document.createElement('div');
+ container.appendChild(div);
+ let observer = new ResizeObserver(() => {
+ callbackCount++;
+ observer.disconnect();
+ container.removeChild(div);
+ if (callbackCount == iterationCount) {
+ window.requestAnimationFrame(() => {
+ gc();
+ test.step(() => {
+ let observerCount = internals.numberOfResizeObservers(document) - initialObserverCount;
+ assert_true(observerCount < iterationCount, 'Resize observers should be collected.');
+ test.done();
+ });
+ });
+ }
+ });
+ observer.observe(div);
+ }
+}
+
+test(_ => {
+ assert_own_property(window, "ResizeObserver");
+}, "ResizeObserver implemented");
+
+window._onload_ = accessToObserverInCallback();
+</script>
+
+</body>
+
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (268859 => 268860)
--- trunk/Source/WebCore/ChangeLog 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/ChangeLog 2020-10-22 12:41:10 UTC (rev 268860)
@@ -1,3 +1,33 @@
+2020-10-22 Cathie Chen <[email protected]>
+
+ ResizeObserver is not properly garbage collected
+ https://bugs.webkit.org/show_bug.cgi?id=215158
+
+ Reviewed by Frédéric Wang.
+
+ If ResizeObservers are referenced inside ResizeObserverCallbacks, they are not garbage collected properly. To fix this,
+ add IsWeakCallback to ResizeObserverCallback interface so that it uses JSC::Weak to store the callback. And add the callback
+ to visitor in JSResizeObserver::visitAdditionalChildren() to keep it alive. In order to test ResizeObserver leak, add test interface
+ numberOfResizeObservers() to Internals.idl.
+
+ Test: resize-observer/resize-observer-callback-leak.html
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * bindings/js/JSResizeObserverCustom.cpp: Copied from Source/WebCore/page/ResizeObserverCallback.idl.
+ (WebCore::JSResizeObserver::visitAdditionalChildren): Add callback to SlotVisitor.
+ * dom/Document.h:
+ (WebCore::Document::numberOfResizeObservers const):
+ * page/ResizeObserver.h:
+ (WebCore::ResizeObserver::callback):
+ * page/ResizeObserver.idl: Add JSCustomMarkFunction to the interface.
+ * page/ResizeObserverCallback.h:
+ * page/ResizeObserverCallback.idl: Add IsWeakCallback to the interface.
+ * testing/Internals.cpp: Add numberOfResizeObservers.
+ (WebCore::Internals::numberOfResizeObservers const):
+ * testing/Internals.h:
+ * testing/Internals.idl:
+
2020-10-22 Philippe Normand <[email protected]>
[GStreamer] Restrict ImageDecoder to WebProcess
Modified: trunk/Source/WebCore/Sources.txt (268859 => 268860)
--- trunk/Source/WebCore/Sources.txt 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/Sources.txt 2020-10-22 12:41:10 UTC (rev 268860)
@@ -570,6 +570,7 @@
bindings/js/JSReadableStreamSourceCustom.cpp
bindings/js/JSRemoteDOMWindowBase.cpp
bindings/js/JSRemoteDOMWindowCustom.cpp
+bindings/js/JSResizeObserverCustom.cpp
bindings/js/JSResizeObserverEntryCustom.cpp
bindings/js/JSSVGPathSegCustom.cpp
bindings/js/JSSVGViewSpecCustom.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (268859 => 268860)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-10-22 12:41:10 UTC (rev 268860)
@@ -9211,6 +9211,7 @@
5824ABA51AE81384009074B7 /* RubyTextElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RubyTextElement.h; sourceTree = "<group>"; };
582DE3221C30C85400BE02A8 /* TextDecorationPainter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextDecorationPainter.cpp; sourceTree = "<group>"; };
582DE3231C30C85400BE02A8 /* TextDecorationPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextDecorationPainter.h; sourceTree = "<group>"; };
+ 5868C7C42539DA3300BF9DF3 /* JSResizeObserverCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSResizeObserverCustom.cpp; 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>"; };
@@ -22358,6 +22359,7 @@
CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */,
833CF70F20DB3F5F00141BCC /* JSPerformanceObserverCustom.cpp */,
A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */,
+ 5868C7C42539DA3300BF9DF3 /* JSResizeObserverCustom.cpp */,
5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */,
83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */,
460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */,
Copied: trunk/Source/WebCore/bindings/js/JSResizeObserverCustom.cpp (from rev 268859, trunk/Source/WebCore/page/ResizeObserverCallback.idl) (0 => 268860)
--- trunk/Source/WebCore/bindings/js/JSResizeObserverCustom.cpp (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSResizeObserverCustom.cpp 2020-10-22 12:41:10 UTC (rev 268860)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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 "JSResizeObserver.h"
+
+#include <_javascript_Core/JSCInlines.h>
+
+namespace WebCore {
+
+void JSResizeObserver::visitAdditionalChildren(JSC::SlotVisitor& visitor)
+{
+ ResizeObserverCallback* callback = wrapped().callbackConcurrently();
+ if (callback)
+ callback->visitJSFunction(visitor);
+}
+
+}
Modified: trunk/Source/WebCore/dom/Document.h (268859 => 268860)
--- trunk/Source/WebCore/dom/Document.h 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/dom/Document.h 2020-10-22 12:41:10 UTC (rev 268860)
@@ -1412,6 +1412,7 @@
#if ENABLE(RESIZE_OBSERVER)
void addResizeObserver(ResizeObserver&);
void removeResizeObserver(ResizeObserver&);
+ unsigned numberOfResizeObservers() const { return m_resizeObservers.size(); }
bool hasResizeObservers();
// Return the minDepth of the active observations.
size_t gatherResizeObservations(size_t deeperThan);
Modified: trunk/Source/WebCore/page/ResizeObserver.h (268859 => 268860)
--- trunk/Source/WebCore/page/ResizeObserver.h 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/page/ResizeObserver.h 2020-10-22 12:41:10 UTC (rev 268860)
@@ -64,6 +64,8 @@
bool hasSkippedObservations() const { return m_hasSkippedObservations; }
void setHasSkippedObservations(bool skipped) { m_hasSkippedObservations = skipped; }
+ ResizeObserverCallback* callbackConcurrently() { return m_callback.get(); }
+
private:
ResizeObserver(Document&, Ref<ResizeObserverCallback>&&);
Modified: trunk/Source/WebCore/page/ResizeObserver.idl (268859 => 268860)
--- trunk/Source/WebCore/page/ResizeObserver.idl 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/page/ResizeObserver.idl 2020-10-22 12:41:10 UTC (rev 268860)
@@ -29,7 +29,8 @@
ActiveDOMObject,
Conditional=RESIZE_OBSERVER,
EnabledBySetting=ResizeObserver,
- Exposed=Window
+ Exposed=Window,
+ JSCustomMarkFunction,
] interface ResizeObserver {
[CallWith=Document] constructor(ResizeObserverCallback callback);
Modified: trunk/Source/WebCore/page/ResizeObserverCallback.h (268859 => 268860)
--- trunk/Source/WebCore/page/ResizeObserverCallback.h 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/page/ResizeObserverCallback.h 2020-10-22 12:41:10 UTC (rev 268860)
@@ -39,6 +39,9 @@
class ResizeObserverCallback : public RefCounted<ResizeObserverCallback>, public ActiveDOMCallback {
public:
using ActiveDOMCallback::ActiveDOMCallback;
+
+ virtual bool hasCallback() const = 0;
+
virtual CallbackResult<void> handleEvent(ResizeObserver&, const Vector<Ref<ResizeObserverEntry>>&, ResizeObserver&) = 0;
};
Modified: trunk/Source/WebCore/page/ResizeObserverCallback.idl (268859 => 268860)
--- trunk/Source/WebCore/page/ResizeObserverCallback.idl 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/page/ResizeObserverCallback.idl 2020-10-22 12:41:10 UTC (rev 268860)
@@ -28,4 +28,5 @@
[
Conditional=RESIZE_OBSERVER,
CallbackThisObject=ResizeObserver,
+ IsWeakCallback,
] callback ResizeObserverCallback = undefined (sequence<ResizeObserverEntry> entries, ResizeObserver observer);
Modified: trunk/Source/WebCore/testing/Internals.cpp (268859 => 268860)
--- trunk/Source/WebCore/testing/Internals.cpp 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/testing/Internals.cpp 2020-10-22 12:41:10 UTC (rev 268860)
@@ -2634,6 +2634,13 @@
}
#endif
+#if ENABLE(RESIZE_OBSERVER)
+unsigned Internals::numberOfResizeObservers(const Document& document) const
+{
+ return document.numberOfResizeObservers();
+}
+#endif
+
uint64_t Internals::documentIdentifier(const Document& document) const
{
return document.identifier().toUInt64();
Modified: trunk/Source/WebCore/testing/Internals.h (268859 => 268860)
--- trunk/Source/WebCore/testing/Internals.h 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/testing/Internals.h 2020-10-22 12:41:10 UTC (rev 268860)
@@ -447,6 +447,10 @@
unsigned numberOfIntersectionObservers(const Document&) const;
#endif
+#if ENABLE(RESIZE_OBSERVER)
+ unsigned numberOfResizeObservers(const Document&) const;
+#endif
+
uint64_t documentIdentifier(const Document&) const;
bool isDocumentAlive(uint64_t documentIdentifier) const;
Modified: trunk/Source/WebCore/testing/Internals.idl (268859 => 268860)
--- trunk/Source/WebCore/testing/Internals.idl 2020-10-22 10:00:32 UTC (rev 268859)
+++ trunk/Source/WebCore/testing/Internals.idl 2020-10-22 12:41:10 UTC (rev 268860)
@@ -514,6 +514,7 @@
unsigned long numberOfLiveDocuments();
unsigned long referencingNodeCount(Document document);
[Conditional=INTERSECTION_OBSERVER] unsigned long numberOfIntersectionObservers(Document document);
+ [Conditional = RESIZE_OBSERVER] unsigned long numberOfResizeObservers(Document document);
WindowProxy? openDummyInspectorFrontend(DOMString url);
undefined closeDummyInspectorFrontend();
[MayThrowException] undefined setInspectorIsUnderTest(boolean isUnderTest);