Changeset 8557 in webkit


Ignore:
Timestamp:
Feb 10, 2005, 12:40:56 AM (20 years ago)
Author:
mjs
Message:

Reviewed by Darin.

<rdar://problem/3977973> pages on ebay leak referenced JavaScript objects -- over time browsing becomes super-slow

I fixed this by removing all event listeners for a document, it's
children, and any disconnected nodes that used to be in the
document at document detach time. Mozilla temporarily disables
event listeners on such nodes, but re-enables them if you
re-parant a node into a new document. However, in WebCore, you
can't re-parent a node into another document, so there is no
observable change in behavior.

We have to do this to break the possible reference cycles between
event listeners and the dom nodes they are attached to (e.g. via
scope chain, as in this case).

  • khtml/xml/dom_docimpl.cpp: (DocumentImpl::detach): (DocumentImpl::removeAllEventListenersFromAllNodesx): (DocumentImpl::registerDisconnectedNodeWithEventListeners): (DocumentImpl::unregisterDisconnectedNodeWithEventListeners): (DocumentImpl::removeAllDisconnectedNodeEventListeners):
  • khtml/xml/dom_docimpl.h:
  • khtml/xml/dom_nodeimpl.cpp: (NodeImpl::~NodeImpl): (NodeImpl::addEventListener): (NodeImpl::removeEventListener): (NodeImpl::removeAllEventListeners): (NodeImpl::removeHTMLEventListener): (NodeImpl::insertedIntoDocument): (NodeImpl::removedFromDocument):
  • khtml/xml/dom_nodeimpl.h:
Location:
trunk/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog-2005-08-23

    r8556 r8557  
     12005-02-08  Maciej Stachowiak  <mjs@apple.com>
     2
     3        Reviewed by Darin.
     4
     5        <rdar://problem/3977973> pages on ebay leak referenced JavaScript objects -- over time browsing becomes super-slow
     6
     7        I fixed this by removing all event listeners for a document, it's
     8        children, and any disconnected nodes that used to be in the
     9        document at document detach time. Mozilla temporarily disables
     10        event listeners on such nodes, but re-enables them if you
     11        re-parant a node into a new document. However, in WebCore, you
     12        can't re-parent a node into another document, so there is no
     13        observable change in behavior.
     14
     15        We have to do this to break the possible reference cycles between
     16        event listeners and the dom nodes they are attached to (e.g. via
     17        scope chain, as in this case).
     18
     19        * khtml/xml/dom_docimpl.cpp:
     20        (DocumentImpl::detach):
     21        (DocumentImpl::removeAllEventListenersFromAllNodesx):
     22        (DocumentImpl::registerDisconnectedNodeWithEventListeners):
     23        (DocumentImpl::unregisterDisconnectedNodeWithEventListeners):
     24        (DocumentImpl::removeAllDisconnectedNodeEventListeners):
     25        * khtml/xml/dom_docimpl.h:
     26        * khtml/xml/dom_nodeimpl.cpp:
     27        (NodeImpl::~NodeImpl):
     28        (NodeImpl::addEventListener):
     29        (NodeImpl::removeEventListener):
     30        (NodeImpl::removeAllEventListeners):
     31        (NodeImpl::removeHTMLEventListener):
     32        (NodeImpl::insertedIntoDocument):
     33        (NodeImpl::removedFromDocument):
     34        * khtml/xml/dom_nodeimpl.h:
     35
    1362005-02-09  Chris Blumenberg  <cblu@apple.com>
    237
  • trunk/WebCore/khtml/xml/dom_docimpl.cpp

    r8554 r8557  
    11921192    m_imageLoadEventDispatchingList.clear();
    11931193
     1194    removeAllEventListenersFromAllNodes();
     1195
    11941196    NodeBaseImpl::detach();
    11951197
     
    12041206        delete m_renderArena;
    12051207        m_renderArena = 0;
     1208    }
     1209}
     1210
     1211void DocumentImpl::removeAllEventListenersFromAllNodes()
     1212{
     1213    m_windowEventListeners.clear();
     1214    removeAllDisconnectedNodeEventListeners();
     1215    for (NodeImpl *n = this; n; n = n->traverseNextNode()) {
     1216        n->removeAllEventListeners();
     1217    }
     1218}
     1219
     1220void DocumentImpl::registerDisconnectedNodeWithEventListeners(NodeImpl *node)
     1221{
     1222    m_disconnectedNodesWithEventListeners.insert(node, node);
     1223}
     1224
     1225void DocumentImpl::unregisterDisconnectedNodeWithEventListeners(NodeImpl *node)
     1226{
     1227    m_disconnectedNodesWithEventListeners.remove(node);
     1228}
     1229
     1230void DocumentImpl::removeAllDisconnectedNodeEventListeners()
     1231{
     1232    for (QPtrDictIterator<NodeImpl> iter(m_disconnectedNodesWithEventListeners);
     1233         iter.current();
     1234         ++iter) {
     1235        iter.current()->removeAllEventListeners();
    12061236    }
    12071237}
  • trunk/WebCore/khtml/xml/dom_docimpl.h

    r8309 r8557  
    703703    DOMString m_policyBaseURL;
    704704
     705    QPtrDict<NodeImpl> m_disconnectedNodesWithEventListeners;
     706
    705707#if APPLE_CHANGES
    706708public:
     
    734736    void setDashboardRegions (const QValueList<khtml::DashboardRegionValue>& regions);
    735737   
     738    void removeAllEventListenersFromAllNodes();
     739
     740    void registerDisconnectedNodeWithEventListeners(NodeImpl *node);
     741    void unregisterDisconnectedNodeWithEventListeners(NodeImpl *node);
     742
    736743private:
     744    void removeAllDisconnectedNodeEventListeners();
     745
    737746    JSEditor *jsEditor();
    738747
  • trunk/WebCore/khtml/xml/dom_nodeimpl.cpp

    r8554 r8557  
    111111    if (m_render)
    112112        detach();
     113    if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument() && !inDocument())
     114        getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
    113115    delete m_regdListeners;
    114116    delete m_nodeLists;
     
    341343void NodeImpl::addEventListener(int id, EventListener *listener, const bool useCapture)
    342344{
     345    if (getDocument() && !getDocument()->attached())
     346        return;
     347
    343348    switch (id) {
    344349        case EventImpl::DOMSUBTREEMODIFIED_EVENT:
     
    379384    removeEventListener(id,listener,useCapture);
    380385
     386    // adding the first one
     387    if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
     388        getDocument()->registerDisconnectedNodeWithEventListeners(this);
     389       
    381390    m_regdListeners->append(rl);
    382391    listener->deref();
     
    394403        if (*(it.current()) == rl) {
    395404            m_regdListeners->removeRef(it.current());
     405            // removed last
     406            if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
     407                getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
    396408            return;
    397409        }
     410}
     411
     412void NodeImpl::removeAllEventListeners()
     413{
     414    delete m_regdListeners;
     415    m_regdListeners = 0;
    398416}
    399417
     
    408426            it.current()->listener->eventListenerType() == "_khtml_HTMLEventListener") {
    409427            m_regdListeners->removeRef(it.current());
     428            // removed last
     429            if (m_regdListeners->isEmpty() && getDocument() && !inDocument())
     430                getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
    410431            return;
    411432        }
     
    10951116void NodeImpl::insertedIntoDocument()
    10961117{
     1118    if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
     1119        getDocument()->unregisterDisconnectedNodeWithEventListeners(this);
     1120
    10971121    setInDocument(true);
    10981122}
     
    11001124void NodeImpl::removedFromDocument()
    11011125{
     1126    if (m_regdListeners && !m_regdListeners->isEmpty() && getDocument())
     1127        getDocument()->registerDisconnectedNodeWithEventListeners(this);
     1128
    11021129    setInDocument(false);
    11031130}
  • trunk/WebCore/khtml/xml/dom_nodeimpl.h

    r8492 r8557  
    278278    void setHTMLEventListener(int id, EventListener *listener);
    279279    EventListener *getHTMLEventListener(int id);
     280    void removeAllEventListeners();
    280281
    281282    bool dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent = false);
Note: See TracChangeset for help on using the changeset viewer.