Changeset 54400 in webkit


Ignore:
Timestamp:
Feb 4, 2010 7:39:09 PM (14 years ago)
Author:
ggaren@apple.com
Message:

WebCore: REGRESSION (r52082): Missing event handlers on JQuery demo page (33383)
https://bugs.webkit.org/show_bug.cgi?id=33383
<rdar://problem/7559449>

Reviewed by Alexey Proskuryakov and Darin Adler.

There were two bugs here:

  1. A stale wrapper would invalidate a node's event listeners, even if

the node had a fresh wrapper keeping it alive.

The fix for this is for an event listener to keep a WeakGCPtr back-pointer
to the wrapper it expects to mark it. The wrapper destructor checks this
back-pointer, and only invalidates the event listener in the case of a match.

  1. Conversely, a stale wrapper would not invalidate a node's event

listeners soon enough, if its destructor didn't have a chance to run
before an event fired on the node. (This can only happen in cases where
we've made some other error and failed to mark a wrapper that was circuitously
observable in the DOM. But we know we have edge case bugs like this, and
we don't want them to be crashes.)

The fix for this is to check the wrapper back-pointer before firing the
event listener. As long as the the wrapper back-pointer is not null,
it's safe to fire the listener.

  • ForwardingHeaders/runtime/WeakGCPtr.h: Added. Appease build gods.
  • bindings/js/JSAbstractWorkerCustom.cpp:

(WebCore::JSAbstractWorker::addEventListener):
(WebCore::JSAbstractWorker::removeEventListener):

  • bindings/js/JSDOMApplicationCacheCustom.cpp:

(WebCore::JSDOMApplicationCache::addEventListener):
(WebCore::JSDOMApplicationCache::removeEventListener):

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::markChildren):
(WebCore::JSDOMWindow::addEventListener):
(WebCore::JSDOMWindow::removeEventListener): Updated to pass a wrapper
to the JSEventListener constructor.

  • bindings/js/JSEventListener.cpp:

(WebCore::JSEventListener::JSEventListener):
(WebCore::JSEventListener::initializeJSFunction):
(WebCore::JSEventListener::invalidateJSFunction):

  • bindings/js/JSEventListener.h:

(WebCore::JSEventListener::create):
(WebCore::JSEventListener::isolatedWorld):
(WebCore::JSEventListener::wrapper):
(WebCore::JSEventListener::setWrapper):
(WebCore::JSEventListener::jsFunction):
(WebCore::createJSAttributeEventListener): Implemented the back-pointer
described above. Refactored the jsFunction() accessor to return 0 if
the wrapper back-pointer is 0.

  • bindings/js/JSEventSourceCustom.cpp:

(WebCore::JSEventSource::addEventListener):
(WebCore::JSEventSource::removeEventListener):

  • bindings/js/JSLazyEventListener.cpp:

(WebCore::JSLazyEventListener::JSLazyEventListener):
(WebCore::JSLazyEventListener::initializeJSFunction):

  • bindings/js/JSLazyEventListener.h:

(WebCore::JSLazyEventListener::create):

  • bindings/js/JSMessagePortCustom.cpp:

(WebCore::JSMessagePort::markChildren):
(WebCore::JSMessagePort::addEventListener):
(WebCore::JSMessagePort::removeEventListener):

  • bindings/js/JSNodeCustom.cpp:

(WebCore::JSNode::addEventListener):
(WebCore::JSNode::removeEventListener):
(WebCore::JSNode::markChildren):

  • bindings/js/JSSVGElementInstanceCustom.cpp:

(WebCore::JSSVGElementInstance::addEventListener):
(WebCore::JSSVGElementInstance::removeEventListener):

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocket::addEventListener):
(WebCore::JSWebSocket::removeEventListener):

  • bindings/js/JSWorkerContextCustom.cpp:

(WebCore::JSWorkerContext::markChildren):
(WebCore::JSWorkerContext::addEventListener):
(WebCore::JSWorkerContext::removeEventListener):

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::markChildren):
(WebCore::JSXMLHttpRequest::addEventListener):
(WebCore::JSXMLHttpRequest::removeEventListener):

  • bindings/js/JSXMLHttpRequestUploadCustom.cpp:

(WebCore::JSXMLHttpRequestUpload::markChildren):
(WebCore::JSXMLHttpRequestUpload::addEventListener):
(WebCore::JSXMLHttpRequestUpload::removeEventListener): Updated to pass a wrapper
to the JSEventListener constructor.

  • bindings/js/ScriptEventListener.cpp:

(WebCore::createAttributeEventListener): Updated to pass a wrapper
to the JSEventListener constructor.
(WebCore::getEventListenerHandlerBody): Updated for the fact that jsFunction()
is no longer a virtual accessor on the EventHandler base class.

  • bindings/scripts/CodeGeneratorJS.pm: Updated for the fact that jsFunction()

is no longer a virtual accessor on the EventHandler base class. Added a "JS"
to invalidateEventListeners and markEventListeners to clarify that these
actions are for JS event listeners only. Added a wrapper parameter to
invalidateEventListeners for the back-pointer check explained above.

  • dom/EventListener.h:

(WebCore::EventListener::invalidateJSFunction): ditto

  • dom/EventTarget.h:

(WebCore::EventTarget::markJSEventListeners):
(WebCore::EventTarget::invalidateJSEventListeners): ditto

LayoutTests: REGRESSION (r52082): Missing event handlers on JQuery demo page (33383)
https://bugs.webkit.org/show_bug.cgi?id=33383
<rdar://problem/7559449>

Reviewed by Alexey Proskuryakov and Darin Adler.

  • fast/events/bogus-event-listener-invalidation-expected.txt: Added.
  • fast/events/bogus-event-listener-invalidation.html: Added.
Location:
trunk
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r54395 r54400  
     12010-01-27  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Reviewed by Alexey Proskuryakov and Darin Adler.
     4
     5        REGRESSION (r52082): Missing event handlers on JQuery demo page (33383)
     6        https://bugs.webkit.org/show_bug.cgi?id=33383
     7        <rdar://problem/7559449>
     8
     9        * fast/events/bogus-event-listener-invalidation-expected.txt: Added.
     10        * fast/events/bogus-event-listener-invalidation.html: Added.
     11
    1122010-02-04  Tony Chang  <tony@chromium.org>
    213
  • trunk/WebCore/ChangeLog

    r54395 r54400  
     12010-02-04  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Reviewed by Alexey Proskuryakov and Darin Adler.
     4
     5        REGRESSION (r52082): Missing event handlers on JQuery demo page (33383)
     6        https://bugs.webkit.org/show_bug.cgi?id=33383
     7        <rdar://problem/7559449>
     8       
     9        There were two bugs here:
     10       
     11        1. A stale wrapper would invalidate a node's event listeners, even if
     12        the node had a fresh wrapper keeping it alive.
     13       
     14        The fix for this is for an event listener to keep a WeakGCPtr back-pointer
     15        to the wrapper it expects to mark it. The wrapper destructor checks this
     16        back-pointer, and only invalidates the event listener in the case of a match.
     17
     18        2. Conversely, a stale wrapper would not invalidate a node's event
     19        listeners soon enough, if its destructor didn't have a chance to run
     20        before an event fired on the node. (This can only happen in cases where
     21        we've made some other error and failed to mark a wrapper that was circuitously
     22        observable in the DOM. But we know we have edge case bugs like this, and
     23        we don't want them to be crashes.)
     24       
     25        The fix for this is to check the wrapper back-pointer before firing the
     26        event listener. As long as the the wrapper back-pointer is not null,
     27        it's safe to fire the listener.
     28
     29        * ForwardingHeaders/runtime/WeakGCPtr.h: Added. Appease build gods.
     30
     31        * bindings/js/JSAbstractWorkerCustom.cpp:
     32        (WebCore::JSAbstractWorker::addEventListener):
     33        (WebCore::JSAbstractWorker::removeEventListener):
     34        * bindings/js/JSDOMApplicationCacheCustom.cpp:
     35        (WebCore::JSDOMApplicationCache::addEventListener):
     36        (WebCore::JSDOMApplicationCache::removeEventListener):
     37        * bindings/js/JSDOMWindowCustom.cpp:
     38        (WebCore::JSDOMWindow::markChildren):
     39        (WebCore::JSDOMWindow::addEventListener):
     40        (WebCore::JSDOMWindow::removeEventListener): Updated to pass a wrapper
     41        to the JSEventListener constructor.
     42
     43        * bindings/js/JSEventListener.cpp:
     44        (WebCore::JSEventListener::JSEventListener):
     45        (WebCore::JSEventListener::initializeJSFunction):
     46        (WebCore::JSEventListener::invalidateJSFunction):
     47        * bindings/js/JSEventListener.h:
     48        (WebCore::JSEventListener::create):
     49        (WebCore::JSEventListener::isolatedWorld):
     50        (WebCore::JSEventListener::wrapper):
     51        (WebCore::JSEventListener::setWrapper):
     52        (WebCore::JSEventListener::jsFunction):
     53        (WebCore::createJSAttributeEventListener): Implemented the back-pointer
     54        described above. Refactored the jsFunction() accessor to return 0 if
     55        the wrapper back-pointer is 0.
     56
     57        * bindings/js/JSEventSourceCustom.cpp:
     58        (WebCore::JSEventSource::addEventListener):
     59        (WebCore::JSEventSource::removeEventListener):
     60        * bindings/js/JSLazyEventListener.cpp:
     61        (WebCore::JSLazyEventListener::JSLazyEventListener):
     62        (WebCore::JSLazyEventListener::initializeJSFunction):
     63        * bindings/js/JSLazyEventListener.h:
     64        (WebCore::JSLazyEventListener::create):
     65        * bindings/js/JSMessagePortCustom.cpp:
     66        (WebCore::JSMessagePort::markChildren):
     67        (WebCore::JSMessagePort::addEventListener):
     68        (WebCore::JSMessagePort::removeEventListener):
     69        * bindings/js/JSNodeCustom.cpp:
     70        (WebCore::JSNode::addEventListener):
     71        (WebCore::JSNode::removeEventListener):
     72        (WebCore::JSNode::markChildren):
     73        * bindings/js/JSSVGElementInstanceCustom.cpp:
     74        (WebCore::JSSVGElementInstance::addEventListener):
     75        (WebCore::JSSVGElementInstance::removeEventListener):
     76        * bindings/js/JSWebSocketCustom.cpp:
     77        (WebCore::JSWebSocket::addEventListener):
     78        (WebCore::JSWebSocket::removeEventListener):
     79        * bindings/js/JSWorkerContextCustom.cpp:
     80        (WebCore::JSWorkerContext::markChildren):
     81        (WebCore::JSWorkerContext::addEventListener):
     82        (WebCore::JSWorkerContext::removeEventListener):
     83        * bindings/js/JSXMLHttpRequestCustom.cpp:
     84        (WebCore::JSXMLHttpRequest::markChildren):
     85        (WebCore::JSXMLHttpRequest::addEventListener):
     86        (WebCore::JSXMLHttpRequest::removeEventListener):
     87        * bindings/js/JSXMLHttpRequestUploadCustom.cpp:
     88        (WebCore::JSXMLHttpRequestUpload::markChildren):
     89        (WebCore::JSXMLHttpRequestUpload::addEventListener):
     90        (WebCore::JSXMLHttpRequestUpload::removeEventListener): Updated to pass a wrapper
     91        to the JSEventListener constructor.
     92
     93
     94        * bindings/js/ScriptEventListener.cpp:
     95        (WebCore::createAttributeEventListener): Updated to pass a wrapper
     96        to the JSEventListener constructor.
     97        (WebCore::getEventListenerHandlerBody): Updated for the fact that jsFunction()
     98        is no longer a virtual accessor on the EventHandler base class.
     99
     100        * bindings/scripts/CodeGeneratorJS.pm: Updated for the fact that jsFunction()
     101        is no longer a virtual accessor on the EventHandler base class. Added a "JS"
     102        to invalidateEventListeners and markEventListeners to clarify that these
     103        actions are for JS event listeners only. Added a wrapper parameter to
     104        invalidateEventListeners for the back-pointer check explained above.
     105
     106        * dom/EventListener.h:
     107        (WebCore::EventListener::invalidateJSFunction): ditto
     108
     109        * dom/EventTarget.h:
     110        (WebCore::EventTarget::markJSEventListeners):
     111        (WebCore::EventTarget::invalidateJSEventListeners): ditto
     112
    11132010-02-04  Tony Chang  <tony@chromium.org>
    2114
  • trunk/WebCore/bindings/js/JSAbstractWorkerCustom.cpp

    r49963 r54400  
    5151        return jsUndefined();
    5252
    53     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     53    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    5454    return jsUndefined();
    5555}
     
    6161        return jsUndefined();
    6262
    63     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     63    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    6464    return jsUndefined();
    6565}
  • trunk/WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp

    r49963 r54400  
    9292        return jsUndefined();
    9393
    94     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     94    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    9595    return jsUndefined();
    9696}
     
    102102        return jsUndefined();
    103103
    104     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     104    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    105105    return jsUndefined();
    106106}
  • trunk/WebCore/bindings/js/JSDOMWindowCustom.cpp

    r54182 r54400  
    9898    Base::markChildren(markStack);
    9999
    100     impl()->markEventListeners(markStack);
     100    impl()->markJSEventListeners(markStack);
    101101
    102102    JSGlobalData& globalData = *Heap::heap(this)->globalData();
     
    998998        return jsUndefined();
    999999
    1000     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     1000    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    10011001    return jsUndefined();
    10021002}
     
    10121012        return jsUndefined();
    10131013
    1014     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     1014    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    10151015    return jsUndefined();
    10161016}
  • trunk/WebCore/bindings/js/JSEventListener.cpp

    r53046 r54400  
    3232namespace WebCore {
    3333
    34 JSEventListener::JSEventListener(JSObject* function, bool isAttribute, DOMWrapperWorld* isolatedWorld)
     34JSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld)
    3535    : EventListener(JSEventListenerType)
    3636    , m_jsFunction(function)
     37    , m_wrapper(wrapper)
    3738    , m_isAttribute(isAttribute)
    3839    , m_isolatedWorld(isolatedWorld)
     
    4445}
    4546
    46 JSObject* JSEventListener::jsFunction(ScriptExecutionContext*) const
    47 {
    48     return m_jsFunction;
     47JSObject* JSEventListener::initializeJSFunction(ScriptExecutionContext*) const
     48{
     49    ASSERT_NOT_REACHED();
     50    return 0;
    4951}
    5052
     
    5355    if (m_jsFunction)
    5456        markStack.append(m_jsFunction);
     57}
     58
     59void JSEventListener::invalidateJSFunction(JSC::JSObject* wrapper)
     60{
     61    // Since m_wrapper is a WeakGCPtr, it pretends to be null, and therefore !=
     62    // to wrapper, when it's awaiting destruction. So, we check for == wrapper
     63    // or == null.
     64    if (!m_wrapper || m_wrapper == wrapper)
     65        m_wrapper = 0;
    5566}
    5667
  • trunk/WebCore/bindings/js/JSEventListener.h

    r53430 r54400  
    2323#include "EventListener.h"
    2424#include "JSDOMWindow.h"
    25 #include <runtime/Protect.h>
     25#include <runtime/WeakGCPtr.h>
    2626
    2727namespace WebCore {
     
    3131    class JSEventListener : public EventListener {
    3232    public:
    33         static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, bool isAttribute, DOMWrapperWorld* isolatedWorld)
     33        static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld)
    3434        {
    35             return adoptRef(new JSEventListener(listener, isAttribute, isolatedWorld));
     35            return adoptRef(new JSEventListener(listener, wrapper, isAttribute, isolatedWorld));
    3636        }
    3737
     
    5050        bool isAttribute() const { return m_isAttribute; }
    5151
    52         virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const;
     52        JSC::JSObject* jsFunction(ScriptExecutionContext*) const;
     53        DOMWrapperWorld* isolatedWorld() const { return m_isolatedWorld.get(); }
     54
     55        JSC::JSObject* wrapper() const { return m_wrapper.get(); }
     56        void setWrapper(JSC::JSObject* wrapper) const { m_wrapper = wrapper; }
    5357
    5458    private:
     59        virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const;
    5560        virtual void markJSFunction(JSC::MarkStack&);
     61        virtual void invalidateJSFunction(JSC::JSObject*);
    5662        virtual void handleEvent(ScriptExecutionContext*, Event*);
    5763        virtual bool reportError(ScriptExecutionContext*, const String& message, const String& url, int lineNumber);
    5864        virtual bool virtualisAttribute() const;
    59         void clearJSFunctionInline();
    6065
    6166    protected:
    62         JSEventListener(JSC::JSObject* function, bool isAttribute, DOMWrapperWorld* isolatedWorld);
     67        JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld* isolatedWorld);
    6368
     69    private:
    6470        mutable JSC::JSObject* m_jsFunction;
     71        mutable JSC::WeakGCPtr<JSC::JSObject> m_wrapper;
     72
    6573        bool m_isAttribute;
    6674        RefPtr<DOMWrapperWorld> m_isolatedWorld;
    6775    };
    6876
     77    inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const
     78    {
     79        if (!m_jsFunction)
     80            m_jsFunction = initializeJSFunction(scriptExecutionContext);
     81
     82        // Verify that we have a valid wrapper protecting our function from
     83        // garbage collection.
     84        ASSERT(m_wrapper || !m_jsFunction);
     85        if (!m_wrapper)
     86            return 0;
     87
     88        // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an
     89        // event listener can be almost anything, but this makes test-writing easier).
     90        ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction)->isObject());
     91
     92        return m_jsFunction;
     93    }
     94
    6995    // Creates a JS EventListener for an "onXXX" event attribute.
    70     inline PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::ExecState* exec, JSC::JSValue listener)
     96    inline PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper)
    7197    {
    7298        if (!listener.isObject())
    7399            return 0;
    74100
    75         return JSEventListener::create(asObject(listener), true, currentWorld(exec));
     101        return JSEventListener::create(asObject(listener), wrapper, true, currentWorld(exec));
    76102    }
    77103
  • trunk/WebCore/bindings/js/JSEventSourceCustom.cpp

    r49963 r54400  
    5050        return jsUndefined();
    5151
    52     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     52    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    5353    return jsUndefined();
    5454}
     
    6060        return jsUndefined();
    6161
    62     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     62    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    6363    return jsUndefined();
    6464}
  • trunk/WebCore/bindings/js/JSLazyEventListener.cpp

    r53046 r54400  
    3636#endif
    3737
    38 JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld)
    39     : JSEventListener(0, true, isolatedWorld)
     38JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, JSObject* wrapper, DOMWrapperWorld* isolatedWorld)
     39    : JSEventListener(0, wrapper, true, isolatedWorld)
    4040    , m_functionName(functionName)
    4141    , m_eventParameterName(eventParameterName)
    4242    , m_code(code)
    43     , m_parsed(false)
    4443    , m_sourceURL(sourceURL)
    4544    , m_lineNumber(lineNumber)
     
    4948    // will stay alive as long as this handler object is around
    5049    // and we need to avoid a reference cycle. If JS transfers
    51     // this handler to another node, parseCode will be called and
    52     // then originalNode is no longer needed.
     50    // this handler to another node, initializeJSFunction will
     51    // be called and then originalNode is no longer needed.
    5352
    5453    // A JSLazyEventListener can be created with a line number of zero when it is created with
     
    6968}
    7069
    71 JSObject* JSLazyEventListener::jsFunction(ScriptExecutionContext* executionContext) const
    72 {
    73     parseCode(executionContext);
    74     return m_jsFunction;
    75 }
    76 
    77 void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) const
     70JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const
    7871{
    7972    ASSERT(executionContext);
    8073    ASSERT(executionContext->isDocument());
    8174    if (!executionContext)
    82         return;
    83 
    84     if (m_parsed)
    85         return;
     75        return 0;
    8676
    8777    Frame* frame = static_cast<Document*>(executionContext)->frame();
    8878    if (!frame)
    89         return;
     79        return 0;
    9080
    9181    ScriptController* scriptController = frame->script();
    9282    if (!scriptController->canExecuteScripts())
    93         return;
     83        return 0;
    9484
    95     JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, m_isolatedWorld.get());
     85    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld());
    9686    if (!globalObject)
    97         return;
    98 
    99     // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
    100     if (m_originalNode) {
    101         JSLock lock(SilenceAssertionsOnly);
    102         // FIXME: Should pass the global object associated with the node
    103         toJS(globalObject->globalExec(), globalObject, m_originalNode);
    104     }
     87        return 0;
    10588
    10689    if (executionContext->isDocument()) {
     
    10891        Frame* frame = window->impl()->frame();
    10992        if (!frame)
    110             return;
     93            return 0;
    11194        // FIXME: Is this check needed for non-Document contexts?
    11295        ScriptController* script = frame->script();
    11396        if (!script->canExecuteScripts() || script->isPaused())
    114             return;
     97            return 0;
    11598    }
    116 
    117     m_parsed = true;
    11899
    119100    ExecState* exec = globalObject->globalExec();
     
    123104    args.append(jsString(exec, m_code));
    124105
    125     m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok?
    126 
    127     JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_jsFunction);
    128 
     106    JSObject* jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok?
    129107    if (exec->hadException()) {
    130108        exec->clearException();
     109        return 0;
     110    }
    131111
    132         // failed to parse, so let's just make this listener a no-op
    133         m_jsFunction = 0;
    134     } else if (m_originalNode) {
     112    JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction);
     113    if (m_originalNode) {
     114        if (!wrapper()) {
     115            // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating.
     116            JSLock lock(SilenceAssertionsOnly);
     117            // FIXME: Should pass the global object associated with the node
     118            setWrapper(asObject(toJS(globalObject->globalExec(), globalObject, m_originalNode)));
     119        }
     120
    135121        // Add the event's home element to the scope
    136122        // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
    137123        ScopeChain scope = listenerAsFunction->scope();
    138 
    139         JSValue thisObj = toJS(exec, globalObject, m_originalNode);
    140         if (thisObj.isObject()) {
    141             static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope);
    142             listenerAsFunction->setScope(scope);
    143         }
     124        static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, scope);
     125        listenerAsFunction->setScope(scope);
    144126    }
    145127
     
    149131    m_eventParameterName = String();
    150132    m_sourceURL = String();
     133    return jsFunction;
    151134}
    152135
  • trunk/WebCore/bindings/js/JSLazyEventListener.h

    r49963 r54400  
    3030    class JSLazyEventListener : public JSEventListener {
    3131    public:
    32         static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld)
     32        static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, JSC::JSObject* wrapper, DOMWrapperWorld* isolatedWorld)
    3333        {
    34             return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, node, sourceURL, lineNumber, isolatedWorld));
     34            return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, node, sourceURL, lineNumber, wrapper, isolatedWorld));
    3535        }
    3636        virtual ~JSLazyEventListener();
    3737
    3838    private:
    39         JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node*, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld);
     39        JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node*, const String& sourceURL, int lineNumber, JSC::JSObject* wrapper, DOMWrapperWorld* isolatedWorld);
    4040
    41         virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const;
     41        virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const;
    4242        virtual bool wasCreatedFromMarkup() const { return true; }
    43 
    44         void parseCode(ScriptExecutionContext*) const;
    4543
    4644        mutable String m_functionName;
    4745        mutable String m_eventParameterName;
    4846        mutable String m_code;
    49         mutable bool m_parsed;
    5047        mutable String m_sourceURL;
    5148        int m_lineNumber;
  • trunk/WebCore/bindings/js/JSMessagePortCustom.cpp

    r49963 r54400  
    5050        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), entangledPort);
    5151
    52     m_impl->markEventListeners(markStack);
     52    m_impl->markJSEventListeners(markStack);
    5353}
    5454
     
    5959        return jsUndefined();
    6060
    61     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     61    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    6262    return jsUndefined();
    6363}
     
    6969        return jsUndefined();
    7070
    71     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     71    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    7272    return jsUndefined();
    7373}
  • trunk/WebCore/bindings/js/JSNodeCustom.cpp

    r52082 r54400  
    115115        return jsUndefined();
    116116
    117     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     117    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    118118    return jsUndefined();
    119119}
     
    125125        return jsUndefined();
    126126
    127     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     127    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    128128    return jsUndefined();
    129129}
     
    138138
    139139    Node* node = m_impl.get();
    140     node->markEventListeners(markStack);
     140    node->markJSEventListeners(markStack);
    141141
    142142    // Nodes in the document are kept alive by JSDocument::mark, so, if we're in
  • trunk/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp

    r50850 r54400  
    5353        return jsUndefined();
    5454
    55     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     55    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    5656    return jsUndefined();
    5757}
     
    6363        return jsUndefined();
    6464
    65     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     65    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    6666    return jsUndefined();
    6767}
  • trunk/WebCore/bindings/js/JSWebSocketCustom.cpp

    r51377 r54400  
    6666        return jsUndefined();
    6767
    68     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     68    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    6969    return jsUndefined();
    7070}
     
    7676        return jsUndefined();
    7777
    78     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     78    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    7979    return jsUndefined();
    8080}
  • trunk/WebCore/bindings/js/JSWorkerContextCustom.cpp

    r52892 r54400  
    6161    markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator());
    6262
    63     impl()->markEventListeners(markStack);
     63    impl()->markJSEventListeners(markStack);
    6464}
    6565
     
    128128        return jsUndefined();
    129129
    130     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     130    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    131131    return jsUndefined();
    132132}
     
    138138        return jsUndefined();
    139139
    140     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     140    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    141141    return jsUndefined();
    142142}
  • trunk/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp

    r53574 r54400  
    5757        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), upload);
    5858
    59     m_impl->markEventListeners(markStack);
     59    m_impl->markJSEventListeners(markStack);
    6060}
    6161
     
    154154        return jsUndefined();
    155155
    156     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     156    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    157157    return jsUndefined();
    158158}
     
    164164        return jsUndefined();
    165165
    166     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     166    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    167167    return jsUndefined();
    168168}
  • trunk/WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp

    r49963 r54400  
    4949        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), xmlHttpRequest);
    5050
    51     m_impl->markEventListeners(markStack);
     51    m_impl->markJSEventListeners(markStack);
    5252}
    5353
     
    5858        return jsUndefined();
    5959
    60     impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     60    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), args.at(2).toBoolean(exec));
    6161    return jsUndefined();
    6262}
     
    6868        return jsUndefined();
    6969
    70     impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     70    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
    7171    return jsUndefined();
    7272}
  • trunk/WebCore/bindings/js/ScriptEventListener.cpp

    r53564 r54400  
    3838#include "Frame.h"
    3939#include "XSSAuditor.h"
     40#include <runtime/JSLock.h>
    4041
    4142using namespace JSC;
     
    5960    int lineNumber = 1;
    6061    String sourceURL;
     62    JSObject* wrapper = 0;
    6163   
    6264    // FIXME: We should be able to provide accurate source information for frameless documents, too (e.g. for importing nodes from XMLHttpRequest.responseXML).
     
    7375        lineNumber = scriptController->eventHandlerLineNumber();
    7476        sourceURL = node->document()->url().string();
     77
     78        JSC::JSLock lock(SilenceAssertionsOnly);
     79        JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(node->document(), mainThreadNormalWorld());
     80        wrapper = asObject(toJS(globalObject->globalExec(), globalObject, node));
    7581    }
    7682
    77     return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber, mainThreadNormalWorld());
     83    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber, wrapper, mainThreadNormalWorld());
    7884}
    7985
     
    101107    lineNumber = scriptController->eventHandlerLineNumber();
    102108    sourceURL = frame->document()->url().string();
    103     return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), 0, sourceURL, lineNumber, mainThreadNormalWorld());
     109    JSObject* wrapper = toJSDOMWindow(frame, mainThreadNormalWorld());
     110    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), 0, sourceURL, lineNumber, wrapper, mainThreadNormalWorld());
    104111}
    105112
    106113String getEventListenerHandlerBody(ScriptExecutionContext* context, ScriptState* scriptState, EventListener* eventListener)
    107114{
    108     JSC::JSObject* functionObject = eventListener->jsFunction(context);
    109     if (!functionObject)
     115    const JSEventListener* jsListener = JSEventListener::cast(eventListener);
     116    if (!jsListener)
    110117        return "";
    111     return functionObject->toString(scriptState);
     118    JSC::JSObject* jsFunction = jsListener->jsFunction(context);
     119    if (!jsFunction)
     120        return "";
     121    return jsFunction->toString(scriptState);
    112122}
    113123
  • trunk/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r54182 r54400  
    11991199        if ($eventTarget) {
    12001200            $implIncludes{"RegisteredEventListener.h"} = 1;
    1201             push(@implContent, "    impl()->invalidateEventListeners();\n");
     1201            push(@implContent, "    impl()->invalidateJSEventListeners(this);\n");
    12021202        }
    12031203
     
    12191219        push(@implContent, "{\n");
    12201220        push(@implContent, "    Base::markChildren(markStack);\n");
    1221         push(@implContent, "    impl()->markEventListeners(markStack);\n");
     1221        push(@implContent, "    impl()->markJSEventListeners(markStack);\n");
    12221222        push(@implContent, "}\n\n");
    12231223    }
     
    13191319                    push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
    13201320                    push(@implContent, "    if (EventListener* listener = imp->$implGetterFunctionName()) {\n");
     1321                    push(@implContent, "        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
    13211322                    if ($implClassName eq "Document" || $implClassName eq "WorkerContext" || $implClassName eq "SharedWorkerContext" || $implClassName eq "DedicatedWorkerContext") {
    1322                         push(@implContent, "        if (JSObject* jsFunction = listener->jsFunction(imp))\n");
     1323                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(imp))\n");
    13231324                    } else {
    1324                         push(@implContent, "        if (JSObject* jsFunction = listener->jsFunction(imp->scriptExecutionContext()))\n");
     1325                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(imp->scriptExecutionContext()))\n");
    13251326                    }
    1326                     push(@implContent, "            return jsFunction;\n");
     1327                    push(@implContent, "                return jsFunction;\n");
     1328                    push(@implContent, "        }\n");
    13271329                    push(@implContent, "    }\n");
    13281330                    push(@implContent, "    return jsNull();\n");
     
    14781480                            push(@implContent, "    UNUSED_PARAM(exec);\n");
    14791481                            push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(thisObject)->impl());\n");
    1480                             push(@implContent, "    imp->set$implSetterFunctionName(createJSAttributeEventListener(exec, value));\n");
     1482                            push(@implContent, "    imp->set$implSetterFunctionName(createJSAttributeEventListener(exec, value, thisObject));\n");
    14811483                        } elsif ($attribute->signature->type =~ /Constructor$/) {
    14821484                            my $constructorType = $attribute->signature->type;
  • trunk/WebCore/dom/EventListener.h

    r48884 r54400  
    5252
    5353#if USE(JSC)
    54         virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const { return 0; }
    5554        virtual void markJSFunction(JSC::MarkStack&) { }
     55        virtual void invalidateJSFunction(JSC::JSObject*) { }
    5656#endif
    5757
  • trunk/WebCore/dom/EventTarget.h

    r52282 r54400  
    141141
    142142#if USE(JSC)
    143         void markEventListeners(JSC::MarkStack&);
    144         void invalidateEventListeners();
     143        void markJSEventListeners(JSC::MarkStack&);
     144        void invalidateJSEventListeners(JSC::JSObject*);
    145145#endif
    146146
     
    186186
    187187#if USE(JSC)
    188     inline void EventTarget::markEventListeners(JSC::MarkStack& markStack)
     188    inline void EventTarget::markJSEventListeners(JSC::MarkStack& markStack)
    189189    {
    190190        EventTargetData* d = eventTargetData();
     
    200200    }
    201201
    202     inline void EventTarget::invalidateEventListeners()
     202    inline void EventTarget::invalidateJSEventListeners(JSC::JSObject* wrapper)
    203203    {
    204204        EventTargetData* d = eventTargetData();
     
    206206            return;
    207207
    208         deleteAllValues(d->eventListenerMap);
    209         d->eventListenerMap.clear();
     208        EventListenerMap::iterator end = d->eventListenerMap.end();
     209        for (EventListenerMap::iterator it = d->eventListenerMap.begin(); it != end; ++it) {
     210            EventListenerVector& entry = *it->second;
     211            for (size_t i = 0; i < entry.size(); ++i)
     212                entry[i].listener->invalidateJSFunction(wrapper);
     213        }
    210214    }
    211215#endif
Note: See TracChangeset for help on using the changeset viewer.