IntersectionObserver leaks documents
authorajuma@chromium.org <ajuma@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Sep 2018 13:51:24 +0000 (13:51 +0000)
committerajuma@chromium.org <ajuma@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Sep 2018 13:51:24 +0000 (13:51 +0000)
commit873bd488bf0fa99a7ea488897097a72036fc14ea
treee46e9fd0791aa2ff573e662d0855d71a872c9693
parentc6adedfc52c64ab32def02c0e5f855de0b74f49a
IntersectionObserver leaks documents
https://bugs.webkit.org/show_bug.cgi?id=189128

Reviewed by Simon Fraser.

Source/WebCore:

Currently, Documents own IntersectionObservers while IntersectionObservers own callbacks
that have strong references to Documents. To break this cycle, make Documents only have
weak pointers to IntersectionObservers. Instead, manage the lifetime of an
IntersectionObserver as an ActiveDOMObject, overriding hasPendingActivity to keep
the observer alive while there are ongoing observations.

However, there is a still a potential reference cycle. The callback keeps global
references alive, so if there's a global reference to the observer in JavaScript,
we have an observer->callback->observer cycle, keeping the callback (and hence the Document)
alive. To break this cycle, make IntersectionObserver release the callback when its
Document is stopped.

With these changes, there are no longer any leaks reported with run-webkit-tests --world-leaks
on LayoutTests/intersection-observer and LayoutTests/imported/w3c/web-platform-tests/intersection-observer.

Tests: intersection-observer/no-document-leak.html
       intersection-observer/observer-and-callback-without-js-references.html

* dom/Document.cpp:
(WebCore::Document::addIntersectionObserver):
(WebCore::Document::removeIntersectionObserver):
* dom/Document.h:
* dom/Element.cpp:
(WebCore::Element::didMoveToNewDocument):
* page/IntersectionObserver.cpp:
(WebCore::IntersectionObserver::IntersectionObserver):
(WebCore::IntersectionObserver::~IntersectionObserver):
(WebCore::IntersectionObserver::observe):
(WebCore::IntersectionObserver::rootDestroyed):
(WebCore::IntersectionObserver::createTimestamp const):
(WebCore::IntersectionObserver::notify):
(WebCore::IntersectionObserver::hasPendingActivity const):
(WebCore::IntersectionObserver::activeDOMObjectName const):
(WebCore::IntersectionObserver::canSuspendForDocumentSuspension const):
(WebCore::IntersectionObserver::stop):
* page/IntersectionObserver.h:
(WebCore::IntersectionObserver::trackingDocument const):
(WebCore::IntersectionObserver::trackingDocument): Deleted.
* page/IntersectionObserver.idl:

LayoutTests:

* intersection-observer/no-document-leak-expected.txt: Added.
* intersection-observer/no-document-leak.html: Added.
* intersection-observer/observer-and-callback-without-js-references-expected.txt: Added.
* intersection-observer/observer-and-callback-without-js-references.html: Added.
* intersection-observer/resources/no-document-leak-frame.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235736 268f45cc-cd09-0410-ab3c-d52691b4dbfc
13 files changed:
LayoutTests/ChangeLog
LayoutTests/intersection-observer/no-document-leak-expected.txt [new file with mode: 0644]
LayoutTests/intersection-observer/no-document-leak.html [new file with mode: 0644]
LayoutTests/intersection-observer/observer-and-callback-without-js-references-expected.txt [new file with mode: 0644]
LayoutTests/intersection-observer/observer-and-callback-without-js-references.html [new file with mode: 0644]
LayoutTests/intersection-observer/resources/no-document-leak-frame.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/page/IntersectionObserver.cpp
Source/WebCore/page/IntersectionObserver.h
Source/WebCore/page/IntersectionObserver.idl