Reviewed by Darin Adler.

        https://bugs.webkit.org/show_bug.cgi?id=21970
        Make MessagePort event dispatch work in workers

        * bindings/js/JSDOMGlobalObject.cpp:
        (WebCore::JSDOMGlobalObject::JSDOMGlobalObjectData::JSDOMGlobalObjectData):
        (WebCore::JSDOMGlobalObject::~JSDOMGlobalObject):
        (WebCore::JSDOMGlobalObject::findJSEventListener):
        (WebCore::JSDOMGlobalObject::findOrCreateJSEventListener):
        (WebCore::JSDOMGlobalObject::findJSUnprotectedEventListener):
        (WebCore::JSDOMGlobalObject::findOrCreateJSUnprotectedEventListener):
        (WebCore::JSDOMGlobalObject::jsEventListeners):
        (WebCore::JSDOMGlobalObject::jsInlineEventListeners):
        (WebCore::JSDOMGlobalObject::jsUnprotectedEventListeners):
        (WebCore::JSDOMGlobalObject::jsUnprotectedInlineEventListeners):
        (WebCore::JSDOMGlobalObject::setCurrentEvent):
        (WebCore::JSDOMGlobalObject::currentEvent):
        (WebCore::toJSDOMGlobalObject):
        * bindings/js/JSDOMGlobalObject.h:
        * bindings/js/JSDOMWindowBase.cpp:
        (WebCore::JSDOMWindowBase::JSDOMWindowBaseData::JSDOMWindowBaseData):
        (WebCore::JSDOMWindowBase::~JSDOMWindowBase):
        (WebCore::JSDOMWindowBase::clearHelperObjectProperties):
        * bindings/js/JSDOMWindowBase.h:
        Moved event listener tracking from JSDOMWindow to JSDOMGlobalObject.

        * bindings/js/JSEventListener.cpp:
        (WebCore::JSAbstractEventListener::handleEvent):
        (WebCore::JSUnprotectedEventListener::JSUnprotectedEventListener):
        (WebCore::JSUnprotectedEventListener::~JSUnprotectedEventListener):
        (WebCore::JSUnprotectedEventListener::globalObject):
        (WebCore::JSUnprotectedEventListener::clearGlobalObject):
        (WebCore::JSEventListener::JSEventListener):
        (WebCore::JSEventListener::~JSEventListener):
        (WebCore::JSEventListener::globalObject):
        (WebCore::JSEventListener::clearGlobalObject):
        (WebCore::JSLazyEventListener::JSLazyEventListener):
        (WebCore::JSLazyEventListener::parseCode):
        * bindings/js/JSEventListener.h:
        (WebCore::JSUnprotectedEventListener::create):
        (WebCore::JSEventListener::create):
        (WebCore::JSLazyEventListener::create):
        Changed to use JSDOMGlobalObject and ScriptExecutionContext.

        * bindings/js/JSMessagePortCustom.cpp:
        (WebCore::JSMessagePort::startConversation):
        (WebCore::JSMessagePort::addEventListener):
        (WebCore::JSMessagePort::removeEventListener):
        (WebCore::JSMessagePort::setOnmessage):
        (WebCore::JSMessagePort::setOnclose):
        Updated bindings to work with JSDOMGlobalObject. Next step is to make code generator emit
        such code, and stop using a custom implementation for JSMessagePort inline event handler
        getters and setters.

        * dom/Document.cpp:
        (WebCore::Document::virtualURL):
        * dom/Document.h:
        * dom/ScriptExecutionContext.h:
        Expose url() method on ScriptExecutionContext (necessary for compiling scripts in
        JSLazyEventListener).



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@38033 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 66480bd..ca7179e 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,67 @@
+2008-10-30  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        https://bugs.webkit.org/show_bug.cgi?id=21970
+        Make MessagePort event dispatch work in workers
+
+        * bindings/js/JSDOMGlobalObject.cpp:
+        (WebCore::JSDOMGlobalObject::JSDOMGlobalObjectData::JSDOMGlobalObjectData):
+        (WebCore::JSDOMGlobalObject::~JSDOMGlobalObject):
+        (WebCore::JSDOMGlobalObject::findJSEventListener):
+        (WebCore::JSDOMGlobalObject::findOrCreateJSEventListener):
+        (WebCore::JSDOMGlobalObject::findJSUnprotectedEventListener):
+        (WebCore::JSDOMGlobalObject::findOrCreateJSUnprotectedEventListener):
+        (WebCore::JSDOMGlobalObject::jsEventListeners):
+        (WebCore::JSDOMGlobalObject::jsInlineEventListeners):
+        (WebCore::JSDOMGlobalObject::jsUnprotectedEventListeners):
+        (WebCore::JSDOMGlobalObject::jsUnprotectedInlineEventListeners):
+        (WebCore::JSDOMGlobalObject::setCurrentEvent):
+        (WebCore::JSDOMGlobalObject::currentEvent):
+        (WebCore::toJSDOMGlobalObject):
+        * bindings/js/JSDOMGlobalObject.h:
+        * bindings/js/JSDOMWindowBase.cpp:
+        (WebCore::JSDOMWindowBase::JSDOMWindowBaseData::JSDOMWindowBaseData):
+        (WebCore::JSDOMWindowBase::~JSDOMWindowBase):
+        (WebCore::JSDOMWindowBase::clearHelperObjectProperties):
+        * bindings/js/JSDOMWindowBase.h:
+        Moved event listener tracking from JSDOMWindow to JSDOMGlobalObject.
+
+        * bindings/js/JSEventListener.cpp:
+        (WebCore::JSAbstractEventListener::handleEvent):
+        (WebCore::JSUnprotectedEventListener::JSUnprotectedEventListener):
+        (WebCore::JSUnprotectedEventListener::~JSUnprotectedEventListener):
+        (WebCore::JSUnprotectedEventListener::globalObject):
+        (WebCore::JSUnprotectedEventListener::clearGlobalObject):
+        (WebCore::JSEventListener::JSEventListener):
+        (WebCore::JSEventListener::~JSEventListener):
+        (WebCore::JSEventListener::globalObject):
+        (WebCore::JSEventListener::clearGlobalObject):
+        (WebCore::JSLazyEventListener::JSLazyEventListener):
+        (WebCore::JSLazyEventListener::parseCode):
+        * bindings/js/JSEventListener.h:
+        (WebCore::JSUnprotectedEventListener::create):
+        (WebCore::JSEventListener::create):
+        (WebCore::JSLazyEventListener::create):
+        Changed to use JSDOMGlobalObject and ScriptExecutionContext.
+
+        * bindings/js/JSMessagePortCustom.cpp:
+        (WebCore::JSMessagePort::startConversation):
+        (WebCore::JSMessagePort::addEventListener):
+        (WebCore::JSMessagePort::removeEventListener):
+        (WebCore::JSMessagePort::setOnmessage):
+        (WebCore::JSMessagePort::setOnclose):
+        Updated bindings to work with JSDOMGlobalObject. Next step is to make code generator emit
+        such code, and stop using a custom implementation for JSMessagePort inline event handler
+        getters and setters.
+
+        * dom/Document.cpp:
+        (WebCore::Document::virtualURL):
+        * dom/Document.h:
+        * dom/ScriptExecutionContext.h:
+        Expose url() method on ScriptExecutionContext (necessary for compiling scripts in
+        JSLazyEventListener).
+
 2008-10-31  Cameron Zwarich  <zwarich@apple.com>
 
         Not reviewed.
@@ -170,6 +234,7 @@
         doesn't really fix a bug, since we can't really get into a situation where we move to a different 
         topBlockquote, but it simplifies the code.
 
+>>>>>>> .r38031
 2008-10-30  Dirk Schulze  <vbs85@gmx.de>
 
         Reviewed by Alp Toker.
diff --git a/WebCore/bindings/js/JSDOMGlobalObject.cpp b/WebCore/bindings/js/JSDOMGlobalObject.cpp
index 8260459..d9dae37 100644
--- a/WebCore/bindings/js/JSDOMGlobalObject.cpp
+++ b/WebCore/bindings/js/JSDOMGlobalObject.cpp
@@ -27,15 +27,48 @@
 #include "config.h"
 #include "JSDOMGlobalObject.h"
 
+#include "Document.h"
+#include "JSDOMWindow.h"
+#include "JSEventListener.h"
+
 using namespace JSC;
 
 namespace WebCore {
 
+JSDOMGlobalObject::JSDOMGlobalObjectData::JSDOMGlobalObjectData()
+    : evt(0)
+{
+}
+
 JSDOMGlobalObject::JSDOMGlobalObject(PassRefPtr<StructureID> structure, JSDOMGlobalObject::JSDOMGlobalObjectData* data, JSObject* thisValue)
     : JSGlobalObject(structure, data, thisValue)
 {
 }
 
+JSDOMGlobalObject::~JSDOMGlobalObject()
+{
+    // Clear any backpointers to the window
+    ListenersMap::iterator i1 = d()->jsEventListeners.begin();
+    ListenersMap::iterator e1 = d()->jsEventListeners.end();
+    for (; i1 != e1; ++i1)
+        i1->second->clearGlobalObject();
+
+    i1 = d()->jsInlineEventListeners.begin();
+    e1 = d()->jsInlineEventListeners.end();
+    for (; i1 != e1; ++i1)
+        i1->second->clearGlobalObject();
+
+    UnprotectedListenersMap::iterator i2 = d()->jsUnprotectedEventListeners.begin();
+    UnprotectedListenersMap::iterator e2 = d()->jsUnprotectedEventListeners.end();
+    for (; i2 != e2; ++i2)
+        i2->second->clearGlobalObject();
+
+    i2 = d()->jsUnprotectedInlineEventListeners.begin();
+    e2 = d()->jsUnprotectedInlineEventListeners.end();
+    for (; i2 != e2; ++i2)
+        i2->second->clearGlobalObject();
+}
+
 void JSDOMGlobalObject::mark()
 {
     Base::mark();
@@ -51,4 +84,85 @@
     }
 }
 
+JSEventListener* JSDOMGlobalObject::findJSEventListener(JSValue* val, bool isInline)
+{
+    if (!val->isObject())
+        return 0;
+    JSObject* object = asObject(val);
+    ListenersMap& listeners = isInline ? d()->jsInlineEventListeners : d()->jsEventListeners;
+    return listeners.get(object);
+}
+
+PassRefPtr<JSEventListener> JSDOMGlobalObject::findOrCreateJSEventListener(ExecState* exec, JSValue* val, bool isInline)
+{
+    if (JSEventListener* listener = findJSEventListener(val, isInline))
+        return listener;
+
+    if (!val->isObject())
+        return 0;
+
+    // The JSEventListener constructor adds it to our jsEventListeners map.
+    return JSEventListener::create(asObject(val), this, isInline).get();
+}
+
+JSUnprotectedEventListener* JSDOMGlobalObject::findJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool isInline)
+{
+    if (!val->isObject())
+        return 0;
+
+    UnprotectedListenersMap& listeners = isInline ? d()->jsUnprotectedInlineEventListeners : d()->jsUnprotectedEventListeners;
+    return listeners.get(asObject(val));
+}
+
+PassRefPtr<JSUnprotectedEventListener> JSDOMGlobalObject::findOrCreateJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool isInline)
+{
+    if (JSUnprotectedEventListener* listener = findJSUnprotectedEventListener(exec, val, isInline))
+        return listener;
+
+    if (!val->isObject())
+        return 0;
+
+    // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
+    return JSUnprotectedEventListener::create(asObject(val), this, isInline).get();
+}
+
+JSDOMGlobalObject::ListenersMap& JSDOMGlobalObject::jsEventListeners()
+{
+    return d()->jsEventListeners;
+}
+
+JSDOMGlobalObject::ListenersMap& JSDOMGlobalObject::jsInlineEventListeners()
+{
+    return d()->jsInlineEventListeners;
+}
+
+JSDOMGlobalObject::UnprotectedListenersMap& JSDOMGlobalObject::jsUnprotectedEventListeners()
+{
+    return d()->jsUnprotectedEventListeners;
+}
+
+JSDOMGlobalObject::UnprotectedListenersMap& JSDOMGlobalObject::jsUnprotectedInlineEventListeners()
+{
+    return d()->jsUnprotectedInlineEventListeners;
+}
+
+void JSDOMGlobalObject::setCurrentEvent(Event* evt)
+{
+    d()->evt = evt;
+}
+
+Event* JSDOMGlobalObject::currentEvent()
+{
+    return d()->evt;
+}
+
+JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext)
+{
+    if (scriptExecutionContext->isDocument())
+        return toJSDOMWindow(static_cast<Document*>(scriptExecutionContext)->frame());
+
+    // Not implemented yet.
+    return 0;
+}
+
 } // namespace WebCore
diff --git a/WebCore/bindings/js/JSDOMGlobalObject.h b/WebCore/bindings/js/JSDOMGlobalObject.h
index f31b9a5..3c210bb 100644
--- a/WebCore/bindings/js/JSDOMGlobalObject.h
+++ b/WebCore/bindings/js/JSDOMGlobalObject.h
@@ -31,6 +31,9 @@
 
 namespace WebCore {
 
+    class Event;
+    class JSEventListener;
+    class JSUnprotectedEventListener;
     class ScriptExecutionContext;
 
     typedef HashMap<const JSC::ClassInfo*, RefPtr<JSC::StructureID> > JSDOMStructureMap;
@@ -39,12 +42,10 @@
     class JSDOMGlobalObject : public JSC::JSGlobalObject {
         typedef JSC::JSGlobalObject Base;
     protected:
-        struct JSDOMGlobalObjectData : public JSC::JSGlobalObject::JSGlobalObjectData {
-            JSDOMStructureMap structures;
-            JSDOMConstructorMap constructors;
-        };
+        struct JSDOMGlobalObjectData;
 
         JSDOMGlobalObject(PassRefPtr<JSC::StructureID>, JSDOMGlobalObjectData*, JSC::JSObject* thisValue);
+        virtual ~JSDOMGlobalObject();
 
     public:
         JSDOMStructureMap& structures() { return d()->structures; }
@@ -52,8 +53,46 @@
 
         virtual ScriptExecutionContext* scriptExecutionContext() const = 0;
 
+        // Finds a wrapper of a JS EventListener, returns 0 if no existing one.
+        JSEventListener* findJSEventListener(JSC::JSValue*, bool isInline = false);
+
+        // Finds or creates a wrapper of a JS EventListener. JS EventListener object is GC-protected.
+        PassRefPtr<JSEventListener> findOrCreateJSEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
+
+        // Finds a wrapper of a GC-unprotected JS EventListener, returns 0 if no existing one.
+        JSUnprotectedEventListener* findJSUnprotectedEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
+
+        // Finds or creates a wrapper of a JS EventListener. JS EventListener object is *NOT* GC-protected.
+        PassRefPtr<JSUnprotectedEventListener> findOrCreateJSUnprotectedEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
+
+        typedef HashMap<JSC::JSObject*, JSEventListener*> ListenersMap;
+        typedef HashMap<JSC::JSObject*, JSUnprotectedEventListener*> UnprotectedListenersMap;
+
+        ListenersMap& jsEventListeners();
+        ListenersMap& jsInlineEventListeners();
+        UnprotectedListenersMap& jsUnprotectedEventListeners();
+        UnprotectedListenersMap& jsUnprotectedInlineEventListeners();
+
+        void setCurrentEvent(Event*);
+        Event* currentEvent();
+
         virtual void mark();
 
+    protected:
+        struct JSDOMGlobalObjectData : public JSC::JSGlobalObject::JSGlobalObjectData {
+            JSDOMGlobalObjectData();
+
+            JSDOMStructureMap structures;
+            JSDOMConstructorMap constructors;
+
+            JSDOMGlobalObject::ListenersMap jsEventListeners;
+            JSDOMGlobalObject::ListenersMap jsInlineEventListeners;
+            JSDOMGlobalObject::UnprotectedListenersMap jsUnprotectedEventListeners;
+            JSDOMGlobalObject::UnprotectedListenersMap jsUnprotectedInlineEventListeners;
+
+            Event* evt;
+        };
+
     private:
         JSDOMGlobalObjectData* d() const { return static_cast<JSDOMGlobalObjectData*>(JSC::JSVariableObject::d); }
     };
@@ -79,6 +118,8 @@
         return constructor;
     }
 
+    JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext*);
+
 } // namespace WebCore
 
 #endif // JSDOMGlobalObject_h
diff --git a/WebCore/bindings/js/JSDOMWindowBase.cpp b/WebCore/bindings/js/JSDOMWindowBase.cpp
index bbc3139..c1bac66 100644
--- a/WebCore/bindings/js/JSDOMWindowBase.cpp
+++ b/WebCore/bindings/js/JSDOMWindowBase.cpp
@@ -167,7 +167,6 @@
 
 JSDOMWindowBase::JSDOMWindowBaseData::JSDOMWindowBaseData(PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
     : impl(window)
-    , evt(0)
     , returnValueSlot(0)
     , shell(shell)
 {
@@ -200,27 +199,6 @@
         d()->impl->frame()->script()->clearFormerWindow(asJSDOMWindow(this));
 
     clearAllTimeouts();
-
-    // Clear any backpointers to the window
-    ListenersMap::iterator i2 = d()->jsEventListeners.begin();
-    ListenersMap::iterator e2 = d()->jsEventListeners.end();
-    for (; i2 != e2; ++i2)
-        i2->second->clearWindow();
-
-    i2 = d()->jsInlineEventListeners.begin();
-    e2 = d()->jsInlineEventListeners.end();
-    for (; i2 != e2; ++i2)
-        i2->second->clearWindow();
-
-    UnprotectedListenersMap::iterator i1 = d()->jsUnprotectedEventListeners.begin();
-    UnprotectedListenersMap::iterator e1 = d()->jsUnprotectedEventListeners.end();
-    for (; i1 != e1; ++i1)
-        i1->second->clearWindow();
-
-    i1 = d()->jsUnprotectedInlineEventListeners.begin();
-    e1 = d()->jsUnprotectedInlineEventListeners.end();
-    for (; i1 != e1; ++i1)
-        i1->second->clearWindow();
 }
 
 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
@@ -736,51 +714,9 @@
     return page->chrome()->shouldInterruptJavaScript();
 }
 
-JSEventListener* JSDOMWindowBase::findJSEventListener(JSValue* val, bool isInline)
-{
-    if (!val->isObject())
-        return 0;
-    JSObject* object = asObject(val);
-    ListenersMap& listeners = isInline ? d()->jsInlineEventListeners : d()->jsEventListeners;
-    return listeners.get(object);
-}
-
-PassRefPtr<JSEventListener> JSDOMWindowBase::findOrCreateJSEventListener(ExecState* exec, JSValue* val, bool isInline)
-{
-    if (JSEventListener* listener = findJSEventListener(val, isInline))
-        return listener;
-
-    if (!val->isObject())
-        return 0;
-
-    // The JSEventListener constructor adds it to our jsEventListeners map.
-    return JSEventListener::create(asObject(val), static_cast<JSDOMWindow*>(this), isInline).get();
-}
-
-JSUnprotectedEventListener* JSDOMWindowBase::findJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool isInline)
-{
-    if (!val->isObject())
-        return 0;
-
-    UnprotectedListenersMap& listeners = isInline ? d()->jsUnprotectedInlineEventListeners : d()->jsUnprotectedEventListeners;
-    return listeners.get(asObject(val));
-}
-
-PassRefPtr<JSUnprotectedEventListener> JSDOMWindowBase::findOrCreateJSUnprotectedEventListener(ExecState* exec, JSValue* val, bool isInline)
-{
-    if (JSUnprotectedEventListener* listener = findJSUnprotectedEventListener(exec, val, isInline))
-        return listener;
-
-    if (!val->isObject())
-        return 0;
-
-    // The JSUnprotectedEventListener constructor adds it to our jsUnprotectedEventListeners map.
-    return JSUnprotectedEventListener::create(asObject(val), static_cast<JSDOMWindow*>(this), isInline).get();
-}
-
 void JSDOMWindowBase::clearHelperObjectProperties()
 {
-    d()->evt = 0;
+    setCurrentEvent(0);
 }
 
 void JSDOMWindowBase::clear()
@@ -794,16 +730,6 @@
     clearHelperObjectProperties();
 }
 
-void JSDOMWindowBase::setCurrentEvent(Event* evt)
-{
-    d()->evt = evt;
-}
-
-Event* JSDOMWindowBase::currentEvent()
-{
-    return d()->evt;
-}
-
 JSObject* JSDOMWindowBase::toThisObject(ExecState*) const
 {
     return shell();
@@ -1057,26 +983,6 @@
     clearAllTimeouts();
 }
 
-JSDOMWindowBase::ListenersMap& JSDOMWindowBase::jsEventListeners()
-{
-    return d()->jsEventListeners;
-}
-
-JSDOMWindowBase::ListenersMap& JSDOMWindowBase::jsInlineEventListeners()
-{
-    return d()->jsInlineEventListeners;
-}
-
-JSDOMWindowBase::UnprotectedListenersMap& JSDOMWindowBase::jsUnprotectedEventListeners()
-{
-    return d()->jsUnprotectedEventListeners;
-}
-
-JSDOMWindowBase::UnprotectedListenersMap& JSDOMWindowBase::jsUnprotectedInlineEventListeners()
-{
-    return d()->jsUnprotectedInlineEventListeners;
-}
-
 void DOMWindowTimer::fired()
 {
     timerNestingLevel = m_nestingLevel;
diff --git a/WebCore/bindings/js/JSDOMWindowBase.h b/WebCore/bindings/js/JSDOMWindowBase.h
index 0cd0ae3..f345f47 100644
--- a/WebCore/bindings/js/JSDOMWindowBase.h
+++ b/WebCore/bindings/js/JSDOMWindowBase.h
@@ -76,34 +76,11 @@
 
         void timerFired(DOMWindowTimer*);
 
-        // Finds a wrapper of a JS EventListener, returns 0 if no existing one.
-        JSEventListener* findJSEventListener(JSC::JSValue*, bool isInline = false);
-
-        // Finds or creates a wrapper of a JS EventListener. JS EventListener object is GC-protected.
-        PassRefPtr<JSEventListener> findOrCreateJSEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
-
-        // Finds a wrapper of a GC-unprotected JS EventListener, returns 0 if no existing one.
-        JSUnprotectedEventListener* findJSUnprotectedEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
-
-        // Finds or creates a wrapper of a JS EventListener. JS EventListener object is *NOT* GC-protected.
-        PassRefPtr<JSUnprotectedEventListener> findOrCreateJSUnprotectedEventListener(JSC::ExecState*, JSC::JSValue*, bool isInline = false);
-
         void clear();
 
-        void setCurrentEvent(Event*);
-        Event* currentEvent();
-
         // Set a place to put a dialog return value when the window is cleared.
         void setReturnValueSlot(JSC::JSValue** slot);
 
-        typedef HashMap<JSC::JSObject*, JSEventListener*> ListenersMap;
-        typedef HashMap<JSC::JSObject*, JSUnprotectedEventListener*> UnprotectedListenersMap;
-
-        ListenersMap& jsEventListeners();
-        ListenersMap& jsInlineEventListeners();
-        UnprotectedListenersMap& jsUnprotectedEventListeners();
-        UnprotectedListenersMap& jsUnprotectedInlineEventListeners();
-
         virtual const JSC::ClassInfo* classInfo() const { return &s_info; }
         static const JSC::ClassInfo s_info;
 
@@ -135,11 +112,6 @@
 
             RefPtr<DOMWindow> impl;
 
-            JSDOMWindowBase::ListenersMap jsEventListeners;
-            JSDOMWindowBase::ListenersMap jsInlineEventListeners;
-            JSDOMWindowBase::UnprotectedListenersMap jsUnprotectedEventListeners;
-            JSDOMWindowBase::UnprotectedListenersMap jsUnprotectedInlineEventListeners;
-            Event* evt;
             JSC::JSValue** returnValueSlot;
             JSDOMWindowShell* shell;
 
diff --git a/WebCore/bindings/js/JSEventListener.cpp b/WebCore/bindings/js/JSEventListener.cpp
index b720d62..0944816 100644
--- a/WebCore/bindings/js/JSEventListener.cpp
+++ b/WebCore/bindings/js/JSEventListener.cpp
@@ -53,23 +53,34 @@
     if (!listener)
         return;
 
-    JSDOMWindow* window = this->window();
-    // Null check as clearWindow() can clear this and we still get called back by
+    JSDOMGlobalObject* globalObject = this->globalObject();
+    // Null check as clearGlobalObject() can clear this and we still get called back by
     // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275
-    if (!window)
-        return;
-    Frame* frame = window->impl()->frame();
-    if (!frame)
-        return;
-    // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
-    // FIXME: A better fix for this may be to change DMOWindow::frame() to not return a frame the detached window used to be in.
-    if (frame->domWindow() != window->impl())
-        return;
-    ScriptController* script = frame->script();
-    if (!script->isEnabled() || script->isPaused())
+    // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called.
+    if (!globalObject)
         return;
 
-    ExecState* exec = window->globalExec();
+    ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
+    if (!scriptExecutionContext)
+        return;
+
+    Frame* frame = 0;
+    if (scriptExecutionContext->isDocument()) {
+        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject);
+        frame = window->impl()->frame();
+        if (!frame)
+            return;
+        // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>.
+        // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in.
+        if (frame->domWindow() != window->impl())
+            return;
+        // FIXME: Is this check needed for other contexts?
+        ScriptController* script = frame->script();
+        if (!script->isEnabled() || script->isPaused())
+            return;
+    }
+
+    ExecState* exec = globalObject->globalExec();
 
     JSValue* handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent"));
     CallData callData;
@@ -85,29 +96,31 @@
         ArgList args;
         args.append(toJS(exec, event));
 
-        Event* savedEvent = window->currentEvent();
-        window->setCurrentEvent(event);
+        Event* savedEvent = globalObject->currentEvent();
+        globalObject->setCurrentEvent(event);
 
         JSValue* retval;
         if (handleEventFunction) {
-            window->startTimeoutCheck();
+            globalObject->startTimeoutCheck();
             retval = call(exec, handleEventFunction, callType, callData, listener, args);
         } else {
             JSValue* thisValue;
             if (isWindowEvent)
-                thisValue = window->shell();
+                thisValue = globalObject->toThisObject(exec);
             else
                 thisValue = toJS(exec, event->currentTarget());
-            window->startTimeoutCheck();
+            globalObject->startTimeoutCheck();
             retval = call(exec, listener, callType, callData, thisValue, args);
         }
-        window->stopTimeoutCheck();
+        globalObject->stopTimeoutCheck();
 
-        window->setCurrentEvent(savedEvent);
+        globalObject->setCurrentEvent(savedEvent);
 
-        if (exec->hadException())
-            frame->domWindow()->console()->reportCurrentException(exec);
-        else {
+        if (exec->hadException()) {
+            // FIXME: Report exceptions in non-Document contexts.
+            if (frame)
+                frame->domWindow()->console()->reportCurrentException(exec);
+        } else {
             if (!retval->isUndefinedOrNull() && event->storesResultAsString())
                 event->storeResult(retval->toString(exec));
             if (m_isInline) {
@@ -129,23 +142,23 @@
 
 // -------------------------------------------------------------------------
 
-JSUnprotectedEventListener::JSUnprotectedEventListener(JSObject* listener, JSDOMWindow* window, bool isInline)
+JSUnprotectedEventListener::JSUnprotectedEventListener(JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)
     : JSAbstractEventListener(isInline)
     , m_listener(listener)
-    , m_window(window)
+    , m_globalObject(globalObject)
 {
     if (m_listener) {
         JSDOMWindow::UnprotectedListenersMap& listeners = isInline
-            ? window->jsUnprotectedInlineEventListeners() : window->jsUnprotectedEventListeners();
+            ? globalObject->jsUnprotectedInlineEventListeners() : globalObject->jsUnprotectedEventListeners();
         listeners.set(m_listener, this);
     }
 }
 
 JSUnprotectedEventListener::~JSUnprotectedEventListener()
 {
-    if (m_listener && m_window) {
+    if (m_listener && m_globalObject) {
         JSDOMWindow::UnprotectedListenersMap& listeners = isInline()
-            ? m_window->jsUnprotectedInlineEventListeners() : m_window->jsUnprotectedEventListeners();
+            ? m_globalObject->jsUnprotectedInlineEventListeners() : m_globalObject->jsUnprotectedEventListeners();
         listeners.remove(m_listener);
     }
 }
@@ -155,14 +168,14 @@
     return m_listener;
 }
 
-JSDOMWindow* JSUnprotectedEventListener::window() const
+JSDOMGlobalObject* JSUnprotectedEventListener::globalObject() const
 {
-    return m_window;
+    return m_globalObject;
 }
 
-void JSUnprotectedEventListener::clearWindow()
+void JSUnprotectedEventListener::clearGlobalObject()
 {
-    m_window = 0;
+    m_globalObject = 0;
 }
 
 void JSUnprotectedEventListener::mark()
@@ -177,14 +190,14 @@
 
 // -------------------------------------------------------------------------
 
-JSEventListener::JSEventListener(JSObject* listener, JSDOMWindow* window, bool isInline)
+JSEventListener::JSEventListener(JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)
     : JSAbstractEventListener(isInline)
     , m_listener(listener)
-    , m_window(window)
+    , m_globalObject(globalObject)
 {
     if (m_listener) {
         JSDOMWindow::ListenersMap& listeners = isInline
-            ? m_window->jsInlineEventListeners() : m_window->jsEventListeners();
+            ? m_globalObject->jsInlineEventListeners() : m_globalObject->jsEventListeners();
         listeners.set(m_listener, this);
     }
 #ifndef NDEBUG
@@ -194,9 +207,9 @@
 
 JSEventListener::~JSEventListener()
 {
-    if (m_listener && m_window) {
+    if (m_listener && m_globalObject) {
         JSDOMWindow::ListenersMap& listeners = isInline()
-            ? m_window->jsInlineEventListeners() : m_window->jsEventListeners();
+            ? m_globalObject->jsInlineEventListeners() : m_globalObject->jsEventListeners();
         listeners.remove(m_listener);
     }
 #ifndef NDEBUG
@@ -209,20 +222,20 @@
     return m_listener;
 }
 
-JSDOMWindow* JSEventListener::window() const
+JSDOMGlobalObject* JSEventListener::globalObject() const
 {
-    return m_window;
+    return m_globalObject;
 }
 
-void JSEventListener::clearWindow()
+void JSEventListener::clearGlobalObject()
 {
-    m_window = 0;
+    m_globalObject = 0;
 }
 
 // -------------------------------------------------------------------------
 
-JSLazyEventListener::JSLazyEventListener(LazyEventListenerType type, const String& functionName, const String& code, JSDOMWindow* window, Node* node, int lineNumber)
-    : JSEventListener(0, window, true)
+JSLazyEventListener::JSLazyEventListener(LazyEventListenerType type, const String& functionName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber)
+    : JSEventListener(0, globalObject, true)
     , m_functionName(functionName)
     , m_code(code)
     , m_parsed(false)
@@ -269,19 +282,24 @@
     if (m_parsed)
         return;
 
-    Frame* frame = window()->impl()->frame();
-    if (!frame)
-        return;
-    ScriptController* script = frame->script();
-    if (!script->isEnabled() || script->isPaused())
-        return;
+    Frame* frame = 0;
+    if (globalObject()->scriptExecutionContext()->isDocument()) {
+        JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject());
+        frame = window->impl()->frame();
+        if (!frame)
+            return;
+        // FIXME: Is this check needed for non-Document contexts?
+        ScriptController* script = frame->script();
+        if (!script->isEnabled() || script->isPaused())
+            return;
+    }
 
     m_parsed = true;
 
-    ExecState* exec = window()->globalExec();
+    ExecState* exec = globalObject()->globalExec();
 
     ArgList args;
-    UString sourceURL(frame->loader()->url().string());
+    UString sourceURL(globalObject()->scriptExecutionContext()->url().string());
     args.append(eventParameterName(m_type, exec));
     args.append(jsString(exec, m_code));
 
@@ -314,7 +332,7 @@
 
     if (m_listener) {
         ASSERT(isInline());
-        JSDOMWindow::ListenersMap& listeners = window()->jsInlineEventListeners();
+        JSDOMWindow::ListenersMap& listeners = globalObject()->jsInlineEventListeners();
         listeners.set(m_listener, const_cast<JSLazyEventListener*>(this));
     }
 }
diff --git a/WebCore/bindings/js/JSEventListener.h b/WebCore/bindings/js/JSEventListener.h
index 326a518..3c9edd0 100644
--- a/WebCore/bindings/js/JSEventListener.h
+++ b/WebCore/bindings/js/JSEventListener.h
@@ -27,7 +27,7 @@
 namespace WebCore {
 
     class Event;
-    class JSDOMWindow;
+    class JSDOMGlobalObject;
     class Node;
 
     class JSAbstractEventListener : public EventListener {
@@ -35,7 +35,7 @@
         virtual void handleEvent(Event*, bool isWindowEvent);
         virtual bool isInline() const;
         virtual JSC::JSObject* listenerObj() const = 0;
-        virtual JSDOMWindow* window() const = 0;
+        virtual JSDOMGlobalObject* globalObject() const = 0;
 
     protected:
         JSAbstractEventListener(bool isInline)
@@ -49,43 +49,43 @@
 
     class JSUnprotectedEventListener : public JSAbstractEventListener {
     public:
-        static PassRefPtr<JSUnprotectedEventListener> create(JSC::JSObject* listener, JSDOMWindow* window, bool isInline)
+        static PassRefPtr<JSUnprotectedEventListener> create(JSC::JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)
         {
-            return adoptRef(new JSUnprotectedEventListener(listener, window, isInline));
+            return adoptRef(new JSUnprotectedEventListener(listener, globalObject, isInline));
         }
         virtual ~JSUnprotectedEventListener();
 
         virtual JSC::JSObject* listenerObj() const;
-        virtual JSDOMWindow* window() const;
-        void clearWindow();
+        virtual JSDOMGlobalObject* globalObject() const;
+        void clearGlobalObject();
         void mark();
 
     private:
-        JSUnprotectedEventListener(JSC::JSObject* listener, JSDOMWindow*, bool isInline);
+        JSUnprotectedEventListener(JSC::JSObject* listener, JSDOMGlobalObject*, bool isInline);
 
         JSC::JSObject* m_listener;
-        JSDOMWindow* m_window;
+        JSDOMGlobalObject* m_globalObject;
     };
 
     class JSEventListener : public JSAbstractEventListener {
     public:
-        static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSDOMWindow* window, bool isInline)
+        static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSDOMGlobalObject* globalObject, bool isInline)
         {
-            return adoptRef(new JSEventListener(listener, window, isInline));
+            return adoptRef(new JSEventListener(listener, globalObject, isInline));
         }
         virtual ~JSEventListener();
 
         virtual JSC::JSObject* listenerObj() const;
-        virtual JSDOMWindow* window() const;
-        void clearWindow();
+        virtual JSDOMGlobalObject* globalObject() const;
+        void clearGlobalObject();
 
     protected:
-        JSEventListener(JSC::JSObject* listener, JSDOMWindow*, bool isInline);
+        JSEventListener(JSC::JSObject* listener, JSDOMGlobalObject*, bool isInline);
 
         mutable JSC::ProtectedPtr<JSC::JSObject> m_listener;
 
     private:
-        JSC::ProtectedPtr<JSDOMWindow> m_window;
+        JSC::ProtectedPtr<JSDOMGlobalObject> m_globalObject;
     };
 
     class JSLazyEventListener : public JSEventListener {
@@ -99,14 +99,14 @@
 
         virtual bool wasCreatedFromMarkup() const { return true; }
 
-        static PassRefPtr<JSLazyEventListener> create(LazyEventListenerType type, const String& functionName, const String& code, JSDOMWindow* window, Node* node, int lineNumber)
+        static PassRefPtr<JSLazyEventListener> create(LazyEventListenerType type, const String& functionName, const String& code, JSDOMGlobalObject* globalObject, Node* node, int lineNumber)
         {
-            return adoptRef(new JSLazyEventListener(type, functionName, code, window, node, lineNumber));
+            return adoptRef(new JSLazyEventListener(type, functionName, code, globalObject, node, lineNumber));
         }
         virtual JSC::JSObject* listenerObj() const;
 
     protected:
-        JSLazyEventListener(LazyEventListenerType type, const String& functionName, const String& code, JSDOMWindow*, Node*, int lineNumber);
+        JSLazyEventListener(LazyEventListenerType type, const String& functionName, const String& code, JSDOMGlobalObject*, Node*, int lineNumber);
 
     private:
         void parseCode() const;
diff --git a/WebCore/bindings/js/JSMessagePortCustom.cpp b/WebCore/bindings/js/JSMessagePortCustom.cpp
index e7027ea..711cd30 100644
--- a/WebCore/bindings/js/JSMessagePortCustom.cpp
+++ b/WebCore/bindings/js/JSMessagePortCustom.cpp
@@ -29,7 +29,7 @@
 #include "AtomicString.h"
 #include "Event.h"
 #include "Frame.h"
-#include "JSDOMWindowCustom.h"
+#include "JSDOMGlobalObject.h"
 #include "JSEvent.h"
 #include "JSEventListener.h"
 #include "MessagePort.h"
@@ -67,18 +67,18 @@
 
 JSValue* JSMessagePort::startConversation(ExecState* exec, const ArgList& args)
 {
-    DOMWindow* window = asJSDOMWindow(exec->lexicalGlobalObject())->impl();
+    JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
     const UString& message = args.at(exec, 0)->toString(exec);
 
-    return toJS(exec, impl()->startConversation(window->document(), message).get());
+    return toJS(exec, impl()->startConversation(globalObject->scriptExecutionContext(), message).get());
 }
 
 JSValue* JSMessagePort::addEventListener(ExecState* exec, const ArgList& args)
 {
-    Frame* frame = impl()->associatedFrame();
-    if (!frame)
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext());
+    if (!globalObject)
         return jsUndefined();
-    RefPtr<JSUnprotectedEventListener> listener = toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, args.at(exec, 1));
+    RefPtr<JSUnprotectedEventListener> listener = globalObject->findOrCreateJSUnprotectedEventListener(exec, args.at(exec, 1));
     if (!listener)
         return jsUndefined();
     impl()->addEventListener(args.at(exec, 0)->toString(exec), listener.release(), args.at(exec, 2)->toBoolean(exec));
@@ -87,10 +87,10 @@
 
 JSValue* JSMessagePort::removeEventListener(ExecState* exec, const ArgList& args)
 {
-    Frame* frame = impl()->associatedFrame();
-    if (!frame)
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext());
+    if (!globalObject)
         return jsUndefined();
-    JSUnprotectedEventListener* listener = toJSDOMWindow(frame)->findJSUnprotectedEventListener(exec, args.at(exec, 1));
+    JSUnprotectedEventListener* listener = globalObject->findJSUnprotectedEventListener(exec, args.at(exec, 1));
     if (!listener)
         return jsUndefined();
     impl()->removeEventListener(args.at(exec, 0)->toString(exec), listener, args.at(exec, 2)->toBoolean(exec));
@@ -100,10 +100,10 @@
 
 void JSMessagePort::setOnmessage(ExecState* exec, JSValue* value)
 {
-    Frame* frame = impl()->associatedFrame();
-    if (!frame)
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext());
+    if (!globalObject)
         return;
-    impl()->setOnmessage(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
+    impl()->setOnmessage(globalObject->findOrCreateJSUnprotectedEventListener(exec, value, true));
 }
 
 JSValue* JSMessagePort::onmessage(ExecState*) const
@@ -116,10 +116,10 @@
 
 void JSMessagePort::setOnclose(ExecState* exec, JSValue* value)
 {
-    Frame* frame = impl()->associatedFrame();
-    if (!frame)
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext());
+    if (!globalObject)
         return;
-    impl()->setOnclose(toJSDOMWindow(frame)->findOrCreateJSUnprotectedEventListener(exec, value, true));
+    impl()->setOnclose(globalObject->findOrCreateJSUnprotectedEventListener(exec, value, true));
 }
 
 JSValue* JSMessagePort::onclose(ExecState*) const
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 03cc8b8..df7153a 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -1703,6 +1703,11 @@
     m_windowEventListeners.clear();
 }
 
+const KURL& Document::virtualURL() const
+{
+    return m_url;
+}
+
 void Document::setURL(const KURL& url)
 {
     const KURL& newURL = url.isEmpty() ? blankURL() : url;
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index ab01ab3..2e9f5b8 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -779,6 +779,8 @@
     virtual void refScriptExecutionContext() { ref(); }
     virtual void derefScriptExecutionContext() { deref(); }
 
+    virtual const KURL& virtualURL() const; // Same as url(), but needed for ScriptExecutionContext to implement it without a performance loss for direct calls.
+
     CSSStyleSelector* m_styleSelector;
     bool m_didCalculateStyleSelector;
 
diff --git a/WebCore/dom/ScriptExecutionContext.h b/WebCore/dom/ScriptExecutionContext.h
index 13ea763..565dbe0 100644
--- a/WebCore/dom/ScriptExecutionContext.h
+++ b/WebCore/dom/ScriptExecutionContext.h
@@ -46,6 +46,8 @@
         virtual bool isDocument() const { return false; }
         virtual bool isWorkerContext() const { return false; }
 
+        const KURL& url() const { return virtualURL(); }
+
         // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked.
         void stopActiveDOMObjects();
         void createdActiveDOMObject(ActiveDOMObject*, void* upcastPointer);
@@ -63,6 +65,8 @@
         void deref() { derefScriptExecutionContext(); }
 
     private:
+        virtual const KURL& virtualURL() const = 0;
+
         bool m_firedMessagePortTimer;
         HashSet<MessagePort*> m_messagePorts;