2009-04-13 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Apr 2009 04:52:51 +0000 (04:52 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Apr 2009 04:52:51 +0000 (04:52 +0000)
        Reviewed by Cameron Zwarich.

        More fix for https://bugs.webkit.org/show_bug.cgi?id=21260
        Unbounded memory growth when churning elements with anonymous event handler functions

        Stop using protected event listeners on the window object.

        * bindings/js/JSDOMWindowCustom.cpp:
        (WebCore::JSDOMWindow::mark): Mark our event listeners, since they're
        no longer protected.

        (WebCore::JSDOMWindow::addEventListener):
        (WebCore::JSDOMWindow::removeEventListener): Create unprotected event
        listeners, since we mark them now.

        * bindings/js/JSEventListener.h: Made some functions public so
        DOMWindow could call them.

        * bindings/js/JSNodeCustom.cpp: Moved markEventListeners to a header,
        so it could be shared.

        * bindings/scripts/CodeGeneratorJS.pm: Generate event listener marking
        and invalidating code for the DOMWindow.

        * dom/RegisteredEventListener.h:
        (WebCore::markEventListeners):
        (WebCore::invalidateEventListeners): Added helper functions.

        * page/DOMWindow.idl: Make the window's event listener attributes not
        protected.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@42476 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/bindings/js/JSDOMWindowCustom.cpp
WebCore/bindings/js/JSEventListener.h
WebCore/bindings/js/JSNodeCustom.cpp
WebCore/bindings/scripts/CodeGeneratorJS.pm
WebCore/dom/RegisteredEventListener.h
WebCore/page/DOMWindow.h
WebCore/page/DOMWindow.idl

index 577ec16..6c64176 100644 (file)
@@ -1,3 +1,36 @@
+2009-04-13  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Cameron Zwarich.
+
+        More fix for https://bugs.webkit.org/show_bug.cgi?id=21260
+        Unbounded memory growth when churning elements with anonymous event handler functions
+
+        Stop using protected event listeners on the window object.
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::mark): Mark our event listeners, since they're
+        no longer protected.
+
+        (WebCore::JSDOMWindow::addEventListener):
+        (WebCore::JSDOMWindow::removeEventListener): Create unprotected event
+        listeners, since we mark them now.
+
+        * bindings/js/JSEventListener.h: Made some functions public so
+        DOMWindow could call them.
+
+        * bindings/js/JSNodeCustom.cpp: Moved markEventListeners to a header,
+        so it could be shared.
+
+        * bindings/scripts/CodeGeneratorJS.pm: Generate event listener marking
+        and invalidating code for the DOMWindow.
+
+        * dom/RegisteredEventListener.h:
+        (WebCore::markEventListeners):
+        (WebCore::invalidateEventListeners): Added helper functions.
+
+        * page/DOMWindow.idl: Make the window's event listener attributes not
+        protected.
+
 2009-04-13  Eric Carlson  <eric.carlson@apple.com>
 
         Reviewed by Mark Rowe.
index e1a0e6d..27f209e 100644 (file)
@@ -52,6 +52,7 @@
 #include "MessagePort.h"
 #include "Page.h"
 #include "PlatformScreen.h"
+#include "RegisteredEventListener.h"
 #include "ScriptController.h"
 #include "Settings.h"
 #include "WindowFeatures.h"
@@ -66,6 +67,8 @@ void JSDOMWindow::mark()
 {
     Base::mark();
 
+    markEventListeners(impl()->eventListeners());
+
     JSGlobalData& globalData = *Heap::heap(this)->globalData();
 
     markDOMObjectWrapper(globalData, impl()->optionalConsole());
@@ -585,7 +588,7 @@ JSValuePtr JSDOMWindow::addEventListener(ExecState* exec, const ArgList& args)
     if (!frame)
         return jsUndefined();
 
-    if (RefPtr<JSProtectedEventListener> listener = findOrCreateJSProtectedEventListener(args.at(exec, 1)))
+    if (RefPtr<JSEventListener> listener = findOrCreateJSEventListener(args.at(exec, 1)))
         impl()->addEventListener(AtomicString(args.at(exec, 0).toString(exec)), listener.release(), args.at(exec, 2).toBoolean(exec));
 
     return jsUndefined();
@@ -597,7 +600,7 @@ JSValuePtr JSDOMWindow::removeEventListener(ExecState* exec, const ArgList& args
     if (!frame)
         return jsUndefined();
 
-    if (JSProtectedEventListener* listener = findJSProtectedEventListener(args.at(exec, 1)))
+    if (JSEventListener* listener = findJSEventListener(args.at(exec, 1)))
         impl()->removeEventListener(AtomicString(args.at(exec, 0).toString(exec)), listener, args.at(exec, 2).toBoolean(exec));
 
     return jsUndefined();
index 4762ca1..9ff2d2d 100644 (file)
@@ -56,12 +56,13 @@ namespace WebCore {
 
         void clearGlobalObject();
 
-    private:
-        JSEventListener(JSC::JSObject* function, JSDOMGlobalObject*, bool isInline);
-
         virtual JSC::JSObject* jsFunction() const;
         virtual void clearJSFunction();
         virtual void markJSFunction();
+
+    private:
+        JSEventListener(JSC::JSObject* function, JSDOMGlobalObject*, bool isInline);
+
         virtual JSDOMGlobalObject* globalObject() const;
 
         void clearJSFunctionInline()
index 3bdb4a8..ded1866 100644 (file)
@@ -68,12 +68,6 @@ namespace WebCore {
 
 typedef int ExpectionCode;
 
-static inline void markEventListeners(const RegisteredEventListenerVector& listeners)
-{
-    for (size_t i = 0; i < listeners.size(); ++i)
-        listeners[i]->listener()->markJSFunction();
-}
-
 JSValuePtr JSNode::insertBefore(ExecState* exec, const ArgList& args)
 {
     ExceptionCode ec = 0;
index 449931b..f551020 100644 (file)
@@ -434,7 +434,7 @@ sub GenerateHeader
     }
 
     # Destructor
-    push(@headerContent, "    virtual ~$className();\n") if (!$hasParent or $interfaceName eq "Document");
+    push(@headerContent, "    virtual ~$className();\n") if (!$hasParent or $interfaceName eq "Document" or $interfaceName eq "DOMWindow");
 
     # Prototype
     push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"});
@@ -1007,16 +1007,17 @@ sub GenerateImplementation
     push(@implContent, "}\n\n");
 
     # Destructor
-    if (!$hasParent) {
+    if (!$hasParent || $interfaceName eq "DOMWindow") {
         push(@implContent, "${className}::~$className()\n");
         push(@implContent, "{\n");
 
          if ($interfaceName eq "Node") {
              $implIncludes{"RegisteredEventListener.h"} = 1;
              push(@implContent, "    forgetDOMNode(m_impl->document(), m_impl.get());\n");
-             push(@implContent, "    const RegisteredEventListenerVector& eventListeners = m_impl->eventListeners();\n");
-             push(@implContent, "    for (size_t i = 0; i < eventListeners.size(); ++i)\n");
-             push(@implContent, "        eventListeners[i]->listener()->clearJSFunction();\n");
+             push(@implContent, "    invalidateEventListeners(m_impl->eventListeners());\n");
+        } elsif ($interfaceName eq "DOMWindow") {
+             $implIncludes{"RegisteredEventListener.h"} = 1;
+             push(@implContent, "    invalidateEventListeners(impl()->eventListeners());\n");
         } else {
             if ($podType) {
                 my $animatedType = $implClassName;
index 51770fd..6d6cc0c 100644 (file)
@@ -54,6 +54,18 @@ namespace WebCore {
 
     typedef Vector<RefPtr<RegisteredEventListener> > RegisteredEventListenerVector;
 
+    inline void markEventListeners(const RegisteredEventListenerVector& listeners)
+    {
+        for (size_t i = 0; i < listeners.size(); ++i)
+            listeners[i]->listener()->markJSFunction();
+    }
+
+    inline void invalidateEventListeners(const RegisteredEventListenerVector& listeners)
+    {
+        for (size_t i = 0; i < listeners.size(); ++i)
+            listeners[i]->listener()->clearJSFunction();
+    }
+
 } // namespace WebCore
 
 #endif // RegisteredEventListener_h
index a5a05fb..96fcf79 100644 (file)
@@ -208,6 +208,7 @@ namespace WebCore {
         void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
         bool hasEventListener(const AtomicString& eventType);
         void removeAllEventListeners();
+        const RegisteredEventListenerVector& eventListeners() const { return m_eventListeners; }
 
         void setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener>);
         
index 07e4b71..442af64 100644 (file)
@@ -186,35 +186,35 @@ module window {
             raises(DOMException);
 
         // Events
-        attribute [ProtectedListener] EventListener onabort;
-        attribute [ProtectedListener] EventListener onblur;
-        attribute [ProtectedListener] EventListener onchange;
-        attribute [ProtectedListener] EventListener onclick;
-        attribute [ProtectedListener] EventListener ondblclick;
-        attribute [ProtectedListener] EventListener onerror;
-        attribute [ProtectedListener] EventListener onfocus;
-        attribute [ProtectedListener] EventListener onkeydown;
-        attribute [ProtectedListener] EventListener onkeypress;
-        attribute [ProtectedListener] EventListener onkeyup;
-        attribute [ProtectedListener] EventListener onload;
-        attribute [ProtectedListener] EventListener onmousedown;
-        attribute [ProtectedListener] EventListener onmousemove;
-        attribute [ProtectedListener] EventListener onmouseout;
-        attribute [ProtectedListener] EventListener onmouseover;
-        attribute [ProtectedListener] EventListener onmouseup;
-        attribute [ProtectedListener] EventListener onmousewheel;
-        attribute [ProtectedListener] EventListener onreset;
-        attribute [ProtectedListener] EventListener onresize;
-        attribute [ProtectedListener] EventListener onscroll;
-        attribute [ProtectedListener] EventListener onsearch;
-        attribute [ProtectedListener] EventListener onselect;
-        attribute [ProtectedListener] EventListener onsubmit;
-        attribute [ProtectedListener] EventListener onunload;
-        attribute [ProtectedListener] EventListener onbeforeunload;
-        attribute [ProtectedListener] EventListener onwebkitanimationstart;
-        attribute [ProtectedListener] EventListener onwebkitanimationiteration;
-        attribute [ProtectedListener] EventListener onwebkitanimationend;
-        attribute [ProtectedListener] EventListener onwebkittransitionend;
+        attribute EventListener onabort;
+        attribute EventListener onblur;
+        attribute EventListener onchange;
+        attribute EventListener onclick;
+        attribute EventListener ondblclick;
+        attribute EventListener onerror;
+        attribute EventListener onfocus;
+        attribute EventListener onkeydown;
+        attribute EventListener onkeypress;
+        attribute EventListener onkeyup;
+        attribute EventListener onload;
+        attribute EventListener onmousedown;
+        attribute EventListener onmousemove;
+        attribute EventListener onmouseout;
+        attribute EventListener onmouseover;
+        attribute EventListener onmouseup;
+        attribute EventListener onmousewheel;
+        attribute EventListener onreset;
+        attribute EventListener onresize;
+        attribute EventListener onscroll;
+        attribute EventListener onsearch;
+        attribute EventListener onselect;
+        attribute EventListener onsubmit;
+        attribute EventListener onunload;
+        attribute EventListener onbeforeunload;
+        attribute EventListener onwebkitanimationstart;
+        attribute EventListener onwebkitanimationiteration;
+        attribute EventListener onwebkitanimationend;
+        attribute EventListener onwebkittransitionend;
 
 #if defined(V8_BINDING)
         attribute [ProtectedListener] EventListener ondragdrop;