WebCore: https://bugs.webkit.org/show_bug.cgi?id=30696
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Oct 2009 04:33:56 +0000 (04:33 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Oct 2009 04:33:56 +0000 (04:33 +0000)
Add support for IsolatedWorlds to JSC bindings.

Patch by Gavin Barraclough <barraclough@apple.com> on 2009-10-16
Reviewed by Sam Weinig & Geoff Garen.

An IsolatedWorld is basically a parallel, separate copy of the window shells and DOM wrapper objects for
a given document.  To support isolation this patch:

    * Adds support to the ScriptController to track multiple window shells, one per world.
    * Adds support to Document to support multiple separate wrapper-maps, one per world.
    * Replaces the single global DOM wrapper map (on the WebCoreJSClientData) with separate maps,
      stored on the (new) IsolatedWorld objects.

In addition to supporting separate copies of these objects, two other features are supported:

    * It is necessary to track the current world on entry into JSC, so that within callbacks out to WebCore
      we can determine which world (and as such, set of DOM bindings) we should be operating on.
    * EventListeners & Callbacks are run in the world they were registered in.
      This requires the handler to retain a reference to the world.

No new tests. (Enabled existing isolated world layout tests.)

* WebCore.base.exp:
* bindings/js/JSAbstractWorkerCustom.cpp:
(WebCore::JSAbstractWorker::addEventListener):
(WebCore::JSAbstractWorker::removeEventListener):
* bindings/js/JSCallbackData.cpp:
(WebCore::JSCallbackData::invokeCallback):
* bindings/js/JSCallbackData.h:
(WebCore::JSCallbackData::JSCallbackData):
* bindings/js/JSCustomXPathNSResolver.cpp:
(WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
* bindings/js/JSDOMApplicationCacheCustom.cpp:
(WebCore::JSDOMApplicationCache::addEventListener):
(WebCore::JSDOMApplicationCache::removeEventListener):
* bindings/js/JSDOMBinding.cpp:
(WebCore::removeWrappers):
(WebCore::DOMObjectWrapperMap::get):
(WebCore::DOMObjectWrapperMap::set):
(WebCore::DOMObjectWrapperMap::remove):
(WebCore::DOMObjectWrapperMap::take):
(WebCore::IsolatedWorld::IsolatedWorld):
(WebCore::IsolatedWorld::~IsolatedWorld):
(WebCore::EnterIsolatedWorld::EnterIsolatedWorld):
(WebCore::EnterIsolatedWorld::~EnterIsolatedWorld):
(WebCore::JSGlobalDataWorldIterator::JSGlobalDataWorldIterator):
(WebCore::JSGlobalDataWorldIterator::operator bool):
(WebCore::JSGlobalDataWorldIterator::operator*):
(WebCore::JSGlobalDataWorldIterator::operator->):
(WebCore::JSGlobalDataWorldIterator::operator++):
(WebCore::getCurrentWorld):
(WebCore::getNormalWorld):
(WebCore::commonNormalWorld):
(WebCore::commonCurrentWorld):
(WebCore::DOMObjectHashTableMap::mapFor):
(WebCore::DOMObjectWrapperMap::mapFor):
(WebCore::forgetDOMObject):
(WebCore::getCachedDOMNodeWrapper):
(WebCore::forgetDOMNode):
(WebCore::cacheDOMNodeWrapper):
(WebCore::forgetAllDOMNodesForDocument):
(WebCore::forgetWorldOfDOMNodesForDocument):
(WebCore::isObservableThroughDOM):
(WebCore::markDOMNodesForDocument):
(WebCore::markActiveObjectsForContext):
(WebCore::takeWrappers):
(WebCore::updateDOMNodeDocument):
(WebCore::markDOMObjectWrapper):
(WebCore::allowsAccessFromFrame):
(WebCore::printErrorMessageForFrame):
(WebCore::JSC_DebuggerCallFrame_evaluateInWorld):
(WebCore::JSC_callInWorld):
(WebCore::JSC_constructInWorld):
(WebCore::JSC_evaluateInWorld):
* bindings/js/JSDOMBinding.h:
(WebCore::IsolatedWorld::rememberDocument):
(WebCore::IsolatedWorld::forgetDocument):
(WebCore::IsolatedWorld::rememberScriptController):
(WebCore::IsolatedWorld::forgetScriptController):
(WebCore::DOMObjectHashTableMap::~DOMObjectHashTableMap):
(WebCore::DOMObjectHashTableMap::get):
(WebCore::WebCoreJSClientData::WebCoreJSClientData):
(WebCore::WebCoreJSClientData::currentWorld):
(WebCore::WebCoreJSClientData::normalWorld):
(WebCore::WebCoreJSClientData::rememberWorld):
(WebCore::WebCoreJSClientData::forgetWorld):
(WebCore::debuggerWorld):
(WebCore::pluginWorld):
* bindings/js/JSDOMGlobalObject.cpp:
(WebCore::JSDOMGlobalObject::createJSAttributeEventListener):
(WebCore::toJSDOMGlobalObject):
* bindings/js/JSDOMGlobalObject.h:
* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::printErrorMessage):
(WebCore::JSDOMWindowBase::commonJSGlobalData):
(WebCore::toJS):
(WebCore::toJSDOMWindow):
* bindings/js/JSDOMWindowBase.h:
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::createWindow):
(WebCore::JSDOMWindow::open):
(WebCore::JSDOMWindow::showModalDialog):
(WebCore::JSDOMWindow::setTimeout):
(WebCore::JSDOMWindow::setInterval):
(WebCore::JSDOMWindow::addEventListener):
(WebCore::JSDOMWindow::removeEventListener):
* bindings/js/JSDOMWindowShell.cpp:
(WebCore::toJS):
(WebCore::toJSDOMWindowShell):
* bindings/js/JSDOMWindowShell.h:
* bindings/js/JSDesktopNotificationsCustom.cpp:
(WebCore::JSNotification::addEventListener):
(WebCore::):
* bindings/js/JSEventListener.cpp:
(WebCore::JSEventListener::JSEventListener):
(WebCore::JSEventListener::handleEvent):
(WebCore::JSEventListener::reportError):
* bindings/js/JSEventListener.h:
(WebCore::JSEventListener::create):
* bindings/js/JSEventSourceCustom.cpp:
(WebCore::JSEventSource::addEventListener):
(WebCore::JSEventSource::removeEventListener):
* bindings/js/JSEventTarget.cpp:
(WebCore::toJS):
* bindings/js/JSHTMLDocumentCustom.cpp:
(WebCore::JSHTMLDocument::open):
* bindings/js/JSHTMLFrameSetElementCustom.cpp:
(WebCore::JSHTMLFrameSetElement::nameGetter):
* bindings/js/JSInspectorBackendCustom.cpp:
(WebCore::JSInspectorBackend::databaseForId):
(WebCore::JSInspectorBackend::inspectedWindow):
(WebCore::JSInspectorBackend::nodeForId):
* bindings/js/JSLazyEventListener.cpp:
(WebCore::JSLazyEventListener::JSLazyEventListener):
(WebCore::JSLazyEventListener::parseCode):
* bindings/js/JSLazyEventListener.h:
(WebCore::JSLazyEventListener::create):
* bindings/js/JSMessageChannelCustom.cpp:
(WebCore::JSMessageChannel::markChildren):
* 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/JSNodeFilterCondition.cpp:
(WebCore::JSNodeFilterCondition::acceptNode):
* bindings/js/JSQuarantinedObjectWrapper.cpp:
(WebCore::JSQuarantinedObjectWrapper::construct):
(WebCore::JSQuarantinedObjectWrapper::call):
* bindings/js/JSSVGElementInstanceCustom.cpp:
(WebCore::JSSVGElementInstance::addEventListener):
(WebCore::JSSVGElementInstance::removeEventListener):
* bindings/js/JSSharedWorkerCustom.cpp:
(WebCore::JSSharedWorker::markChildren):
* bindings/js/JSWebSocketCustom.cpp:
(WebCore::JSWebSocket::addEventListener):
(WebCore::JSWebSocket::removeEventListener):
* bindings/js/JSWorkerContextCustom.cpp:
(WebCore::JSWorkerContext::addEventListener):
(WebCore::JSWorkerContext::removeEventListener):
(WebCore::JSWorkerContext::setTimeout):
(WebCore::JSWorkerContext::setInterval):
* bindings/js/JSXMLHttpRequestConstructor.cpp:
(WebCore::constructXMLHttpRequest):
* 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):
* bindings/js/ScheduledAction.cpp:
(WebCore::ScheduledAction::create):
(WebCore::ScheduledAction::ScheduledAction):
(WebCore::ScheduledAction::executeFunctionInContext):
(WebCore::ScheduledAction::execute):
* bindings/js/ScheduledAction.h:
(WebCore::ScheduledAction::ScheduledAction):
* bindings/js/ScriptCachedFrameData.cpp:
(WebCore::ScriptCachedFrameData::ScriptCachedFrameData):
(WebCore::ScriptCachedFrameData::restore):
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::~ScriptController):
(WebCore::ScriptController::evaluateInWorld):
(WebCore::ScriptController::evaluate):
(WebCore::ScriptController::evaluateInIsolatedWorld):
(WebCore::ScriptController::clearWindowShell):
(WebCore::ScriptController::initScript):
(WebCore::ScriptController::processingUserGestureEvent):
(WebCore::ScriptController::attachDebugger):
(WebCore::ScriptController::updateDocument):
(WebCore::ScriptController::bindingRootObject):
(WebCore::ScriptController::createRootObject):
(WebCore::ScriptController::windowScriptNPObject):
(WebCore::ScriptController::jsObjectForPluginElement):
* bindings/js/ScriptController.h:
(WebCore::ScriptController::windowShell):
(WebCore::ScriptController::existingWindowShell):
(WebCore::ScriptController::globalObject):
(WebCore::ScriptController::forgetWorld):
* bindings/js/ScriptControllerMac.mm:
(WebCore::ScriptController::windowScriptObject):
* bindings/js/ScriptEventListener.cpp:
(WebCore::createAttributeEventListener):
* bindings/js/ScriptFunctionCall.cpp:
(WebCore::ScriptFunctionCall::call):
(WebCore::ScriptFunctionCall::construct):
* bindings/js/ScriptObjectQuarantine.cpp:
(WebCore::getQuarantinedScriptObject):
* bindings/js/ScriptState.cpp:
(WebCore::scriptStateFromNode):
(WebCore::scriptStateFromPage):
* bindings/js/ScriptState.h:
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
(WebCore::WorkerScriptController::evaluate):
* bindings/objc/DOMInternal.mm:
(-[WebScriptObject _initializeScriptDOMNodeImp]):
* bindings/objc/WebScriptObject.mm:
(-[WebScriptObject callWebScriptMethod:withArguments:]):
(-[WebScriptObject evaluateWebScript:]):
* bindings/scripts/CodeGeneratorJS.pm:
* bridge/NP_jsobject.cpp:
(_NPN_InvokeDefault):
(_NPN_Invoke):
(_NPN_Evaluate):
(_NPN_Construct):
* bridge/jni/jni_jsobject.mm:
(JavaJSObject::call):
(JavaJSObject::eval):
* dom/Document.cpp:
(WebCore::Document::createWrapperCache):
* dom/Document.h:
(WebCore::Document::wrapperCacheMap):
(WebCore::Document::getWrapperCache):
* inspector/InspectorController.cpp:
(WebCore::InspectorController::startUserInitiatedProfiling):
(WebCore::InspectorController::stopUserInitiatedProfiling):
* inspector/JavaScriptCallFrame.cpp:
(WebCore::JavaScriptCallFrame::evaluate):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::dispatchWindowObjectAvailable):
* platform/network/mac/AuthenticationMac.mm:
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::XMLHttpRequest):
(WebCore::XMLHttpRequest::dropProtection):
* xml/XMLHttpRequest.h:
(WebCore::XMLHttpRequest::create):

WebKit/mac: https://bugs.webkit.org/show_bug.cgi?id=30696
Update to incorporate support for IsolatedWorlds in JSC bindings.

Patch by Gavin Barraclough <barraclough@apple.com> on 2009-10-16
Reviewed by Sam Weinig & Geoff Garen.

* WebView/WebFrame.mm:
(-[WebFrame _attachScriptDebugger]):
(-[WebFrame _stringByEvaluatingJavaScriptFromString:forceUserGesture:]):
(-[WebFrame globalContext]):
* WebView/WebScriptDebugDelegate.mm:
(-[WebScriptCallFrame evaluateWebScript:]):
* WebView/WebView.mm:
(-[WebView aeDescByEvaluatingJavaScriptFromString:]):

WebKit/win: https://bugs.webkit.org/show_bug.cgi?id=30696
Update to incorporate support for IsolatedWorlds in JSC bindings.

Patch by Gavin Barraclough <barraclough@apple.com> on 2009-10-22
Reviewed by Sam Weinig & Geoff Garen.

* Interfaces/IWebFramePrivate.idl:
* WebFrame.cpp:
(WebFrame::globalContext):
(WebFrame::windowObjectCleared):
(WebFrame::stringByEvaluatingJavaScriptInIsolatedWorld):
* WebFrame.h:

WebKitTools: https://bugs.webkit.org/show_bug.cgi?id=30696
Enable isolated-worlds tests on mac.

Patch by Gavin Barraclough <barraclough@apple.com> on 2009-10-22
Reviewed by Sam Weinig & Geoff Garen.

Add private interface for DRT to invoke execution in a given world.

* DumpRenderTree/LayoutTestController.cpp:
(evaluateScriptInIsolatedWorldCallback):
(LayoutTestController::staticFunctions):
* DumpRenderTree/LayoutTestController.h:
* DumpRenderTree/mac/LayoutTestControllerMac.mm:
(LayoutTestController::evaluateScriptInIsolatedWorld):
* DumpRenderTree/win/LayoutTestControllerWin.cpp:
(LayoutTestController::evaluateScriptInIsolatedWorld):

LayoutTests: https://bugs.webkit.org/show_bug.cgi?id=30696
Enable isolated-worlds tests on mac.
  * Update the results to switch from windows to unix line-endings.
  * Update all-window-prototypes.html to allow for properties on
    the global object with null prototypes (just skip over them).

Patch by Gavin Barraclough <barraclough@apple.com> on 2009-10-19
Reviewed by Sam Weinig & Geoff Garen.

* http/tests/security/isolatedWorld/all-window-properties-expected.txt:
* http/tests/security/isolatedWorld/all-window-prototypes-expected.txt:
* http/tests/security/isolatedWorld/all-window-prototypes.html:
* http/tests/security/isolatedWorld/body-properties-expected.txt:
* http/tests/security/isolatedWorld/body-prototype-expected.txt:
* http/tests/security/isolatedWorld/document-properties-expected.txt:
* http/tests/security/isolatedWorld/document-prototype-expected.txt:
* http/tests/security/isolatedWorld/global-variables-expected.txt:
* http/tests/security/isolatedWorld/image-properties-expected.txt:
* http/tests/security/isolatedWorld/image-prototype-expected.txt:
* http/tests/security/isolatedWorld/location-properties-expected.txt:
* http/tests/security/isolatedWorld/location-prototype-expected.txt:
* http/tests/security/isolatedWorld/number-prototype-expected.txt:
* http/tests/security/isolatedWorld/object-prototype-expected.txt:
* http/tests/security/isolatedWorld/storage-properties-expected.txt:
* http/tests/security/isolatedWorld/storage-prototype-expected.txt:
* http/tests/security/isolatedWorld/string-prototype-expected.txt:
* http/tests/security/isolatedWorld/window-properties-expected.txt:
* platform/mac/Skipped:

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

101 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/security/isolatedWorld/all-window-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/all-window-prototypes-expected.txt
LayoutTests/http/tests/security/isolatedWorld/all-window-prototypes.html
LayoutTests/http/tests/security/isolatedWorld/body-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/body-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/document-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/document-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/global-variables-expected.txt
LayoutTests/http/tests/security/isolatedWorld/image-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/image-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/location-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/location-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/number-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/object-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/storage-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/storage-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/string-prototype-expected.txt
LayoutTests/http/tests/security/isolatedWorld/window-properties-expected.txt
LayoutTests/http/tests/security/isolatedWorld/world-reuse-expected.txt
LayoutTests/platform/mac/Skipped
WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/bindings/ScriptControllerBase.cpp
WebCore/bindings/js/JSAbstractWorkerCustom.cpp
WebCore/bindings/js/JSCallbackData.cpp
WebCore/bindings/js/JSCallbackData.h
WebCore/bindings/js/JSCustomXPathNSResolver.cpp
WebCore/bindings/js/JSDOMApplicationCacheCustom.cpp
WebCore/bindings/js/JSDOMBinding.cpp
WebCore/bindings/js/JSDOMBinding.h
WebCore/bindings/js/JSDOMGlobalObject.cpp
WebCore/bindings/js/JSDOMGlobalObject.h
WebCore/bindings/js/JSDOMWindowBase.cpp
WebCore/bindings/js/JSDOMWindowBase.h
WebCore/bindings/js/JSDOMWindowCustom.cpp
WebCore/bindings/js/JSDOMWindowShell.cpp
WebCore/bindings/js/JSDOMWindowShell.h
WebCore/bindings/js/JSDesktopNotificationsCustom.cpp
WebCore/bindings/js/JSEventListener.cpp
WebCore/bindings/js/JSEventListener.h
WebCore/bindings/js/JSEventSourceCustom.cpp
WebCore/bindings/js/JSEventTarget.cpp
WebCore/bindings/js/JSHTMLDocumentCustom.cpp
WebCore/bindings/js/JSHTMLFrameSetElementCustom.cpp
WebCore/bindings/js/JSInspectorBackendCustom.cpp
WebCore/bindings/js/JSLazyEventListener.cpp
WebCore/bindings/js/JSLazyEventListener.h
WebCore/bindings/js/JSMessageChannelCustom.cpp
WebCore/bindings/js/JSMessagePortCustom.cpp
WebCore/bindings/js/JSNodeCustom.cpp
WebCore/bindings/js/JSNodeFilterCondition.cpp
WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp
WebCore/bindings/js/JSSVGElementInstanceCustom.cpp
WebCore/bindings/js/JSSharedWorkerCustom.cpp
WebCore/bindings/js/JSWebSocketCustom.cpp
WebCore/bindings/js/JSWorkerContextCustom.cpp
WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
WebCore/bindings/js/JSXMLHttpRequestUploadCustom.cpp
WebCore/bindings/js/ScheduledAction.cpp
WebCore/bindings/js/ScheduledAction.h
WebCore/bindings/js/ScriptCachedFrameData.cpp
WebCore/bindings/js/ScriptController.cpp
WebCore/bindings/js/ScriptController.h
WebCore/bindings/js/ScriptControllerMac.mm
WebCore/bindings/js/ScriptEventListener.cpp
WebCore/bindings/js/ScriptFunctionCall.cpp
WebCore/bindings/js/ScriptObjectQuarantine.cpp
WebCore/bindings/js/ScriptState.cpp
WebCore/bindings/js/ScriptState.h
WebCore/bindings/js/WorkerScriptController.cpp
WebCore/bindings/js/WorkerScriptController.h
WebCore/bindings/objc/DOMInternal.mm
WebCore/bindings/objc/WebScriptObject.mm
WebCore/bindings/scripts/CodeGeneratorJS.pm
WebCore/bridge/NP_jsobject.cpp
WebCore/bridge/jni/jni_jsobject.mm
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/ScriptExecutionContext.cpp
WebCore/dom/ScriptExecutionContext.h
WebCore/inspector/InspectorController.cpp
WebCore/inspector/JavaScriptCallFrame.cpp
WebCore/loader/FrameLoader.cpp
WebCore/plugins/PluginView.cpp
WebCore/xml/XMLHttpRequest.cpp
WebCore/xml/XMLHttpRequest.h
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebFrame.mm
WebKit/mac/WebView/WebFramePrivate.h
WebKit/mac/WebView/WebScriptDebugDelegate.mm
WebKit/mac/WebView/WebView.mm
WebKit/win/ChangeLog
WebKit/win/Interfaces/IWebFramePrivate.idl
WebKit/win/WebFrame.cpp
WebKit/win/WebFrame.h
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/LayoutTestController.cpp
WebKitTools/DumpRenderTree/LayoutTestController.h
WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp

index f776e0a..3d24acf 100644 (file)
@@ -1,3 +1,33 @@
+2009-10-19  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig & Geoff Garen.
+
+        https://bugs.webkit.org/show_bug.cgi?id=30696
+        Enable isolated-worlds tests on mac.
+          * Update the results to switch from windows to unix line-endings.
+          * Update all-window-prototypes.html to allow for properties on
+            the global object with null prototypes (just skip over them).
+
+        * http/tests/security/isolatedWorld/all-window-properties-expected.txt:
+        * http/tests/security/isolatedWorld/all-window-prototypes-expected.txt:
+        * http/tests/security/isolatedWorld/all-window-prototypes.html:
+        * http/tests/security/isolatedWorld/body-properties-expected.txt:
+        * http/tests/security/isolatedWorld/body-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/document-properties-expected.txt:
+        * http/tests/security/isolatedWorld/document-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/global-variables-expected.txt:
+        * http/tests/security/isolatedWorld/image-properties-expected.txt:
+        * http/tests/security/isolatedWorld/image-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/location-properties-expected.txt:
+        * http/tests/security/isolatedWorld/location-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/number-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/object-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/storage-properties-expected.txt:
+        * http/tests/security/isolatedWorld/storage-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/string-prototype-expected.txt:
+        * http/tests/security/isolatedWorld/window-properties-expected.txt:
+        * platform/mac/Skipped:
+
 2009-10-22  Brian Weinstein  <bweinstein@apple.com>
 
         Updating expected results - unreviewed.
index 9bc433a..36be8f7 100644 (file)
@@ -5,8 +5,11 @@
 <script>
 for (p in window) {
   var obj = window[p];
-  if (obj)
-    obj.__proto__.foo = "FAIL: Visible in isolated world.";
+  if (obj) {
+    var proto = obj.__proto__;
+    if (proto)
+      proto.foo = "FAIL: Visible in isolated world.";
+  }
 }
 
 if (window.layoutTestController) {
index 8567d57..22717cc 100644 (file)
@@ -1,7 +1,7 @@
-\r
-Expecting undefined: undefined\r
-Expecting bar: bar\r
-Expecting undefined: undefined\r
-Expecting undefined,undefined: undefined,undefined\r
-Expecting undefined,undefined: undefined,undefined\r
-\r
+
+Expecting undefined: undefined
+Expecting bar: bar
+Expecting undefined: undefined
+Expecting undefined,undefined: undefined,undefined
+Expecting undefined,undefined: undefined,undefined
+
index 5efeb0a..c1b52da 100644 (file)
@@ -70,30 +70,6 @@ svg/hixie/perf/002.xml
 # <rdar://problem/6710625> Test media/video-error-abort.html doesn't work
 media/video-error-abort.html
 
-# This port doesn't support isolated worlds yet.
-http/tests/security/isolatedWorld/all-window-properties.html
-http/tests/security/isolatedWorld/all-window-prototypes.html
-http/tests/security/isolatedWorld/body-properties.html
-http/tests/security/isolatedWorld/body-prototype.html
-http/tests/security/isolatedWorld/click-event.html
-http/tests/security/isolatedWorld/document-open.html
-http/tests/security/isolatedWorld/document-properties.html
-http/tests/security/isolatedWorld/document-prototype.html
-http/tests/security/isolatedWorld/global-variables.html
-http/tests/security/isolatedWorld/image-properties.html
-http/tests/security/isolatedWorld/image-prototype.html
-http/tests/security/isolatedWorld/location-properties.html
-http/tests/security/isolatedWorld/location-prototype.html
-http/tests/security/isolatedWorld/window-setTimeout-function.html
-http/tests/security/isolatedWorld/window-setTimeout-string.html
-http/tests/security/isolatedWorld/storage-properties.html
-http/tests/security/isolatedWorld/storage-prototype.html
-http/tests/security/isolatedWorld/number-prototype.html
-http/tests/security/isolatedWorld/object-prototype.html
-http/tests/security/isolatedWorld/string-prototype.html
-http/tests/security/isolatedWorld/window-properties.html
-http/tests/security/isolatedWorld/world-reuse.html
-
 # New test with questionable results
 # See https://bugs.webkit.org/show_bug.cgi?id=28079 for explanation.
 fast/forms/menulist-style-color.html
index 1229c6a..2babb18 100644 (file)
@@ -1,3 +1,258 @@
+2009-10-16  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig & Geoff Garen.
+
+        https://bugs.webkit.org/show_bug.cgi?id=30696
+        Add support for IsolatedWorlds to JSC bindings.
+
+        An IsolatedWorld is basically a parallel, separate copy of the window shells and DOM wrapper objects for
+        a given document.  To support isolation this patch:
+
+            * Adds support to the ScriptController to track multiple window shells, one per world.
+            * Adds support to Document to support multiple separate wrapper-maps, one per world.
+            * Replaces the single global DOM wrapper map (on the WebCoreJSClientData) with separate maps,
+              stored on the (new) IsolatedWorld objects.
+
+        In addition to supporting separate copies of these objects, two other features are supported:
+
+            * It is necessary to track the current world on entry into JSC, so that within callbacks out to WebCore
+              we can determine which world (and as such, set of DOM bindings) we should be operating on.
+            * EventListeners & Callbacks are run in the world they were registered in.
+              This requires the handler to retain a reference to the world.
+
+        No new tests. (Enabled existing isolated world layout tests.)
+
+        * WebCore.base.exp:
+        * bindings/js/JSAbstractWorkerCustom.cpp:
+        (WebCore::JSAbstractWorker::addEventListener):
+        (WebCore::JSAbstractWorker::removeEventListener):
+        * bindings/js/JSCallbackData.cpp:
+        (WebCore::JSCallbackData::invokeCallback):
+        * bindings/js/JSCallbackData.h:
+        (WebCore::JSCallbackData::JSCallbackData):
+        * bindings/js/JSCustomXPathNSResolver.cpp:
+        (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
+        * bindings/js/JSDOMApplicationCacheCustom.cpp:
+        (WebCore::JSDOMApplicationCache::addEventListener):
+        (WebCore::JSDOMApplicationCache::removeEventListener):
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::removeWrappers):
+        (WebCore::DOMObjectWrapperMap::get):
+        (WebCore::DOMObjectWrapperMap::set):
+        (WebCore::DOMObjectWrapperMap::remove):
+        (WebCore::DOMObjectWrapperMap::take):
+        (WebCore::IsolatedWorld::IsolatedWorld):
+        (WebCore::IsolatedWorld::~IsolatedWorld):
+        (WebCore::EnterIsolatedWorld::EnterIsolatedWorld):
+        (WebCore::EnterIsolatedWorld::~EnterIsolatedWorld):
+        (WebCore::JSGlobalDataWorldIterator::JSGlobalDataWorldIterator):
+        (WebCore::JSGlobalDataWorldIterator::operator bool):
+        (WebCore::JSGlobalDataWorldIterator::operator*):
+        (WebCore::JSGlobalDataWorldIterator::operator->):
+        (WebCore::JSGlobalDataWorldIterator::operator++):
+        (WebCore::getCurrentWorld):
+        (WebCore::getNormalWorld):
+        (WebCore::commonNormalWorld):
+        (WebCore::commonCurrentWorld):
+        (WebCore::DOMObjectHashTableMap::mapFor):
+        (WebCore::DOMObjectWrapperMap::mapFor):
+        (WebCore::forgetDOMObject):
+        (WebCore::getCachedDOMNodeWrapper):
+        (WebCore::forgetDOMNode):
+        (WebCore::cacheDOMNodeWrapper):
+        (WebCore::forgetAllDOMNodesForDocument):
+        (WebCore::forgetWorldOfDOMNodesForDocument):
+        (WebCore::isObservableThroughDOM):
+        (WebCore::markDOMNodesForDocument):
+        (WebCore::markActiveObjectsForContext):
+        (WebCore::takeWrappers):
+        (WebCore::updateDOMNodeDocument):
+        (WebCore::markDOMObjectWrapper):
+        (WebCore::allowsAccessFromFrame):
+        (WebCore::printErrorMessageForFrame):
+        (WebCore::JSC_DebuggerCallFrame_evaluateInWorld):
+        (WebCore::JSC_callInWorld):
+        (WebCore::JSC_constructInWorld):
+        (WebCore::JSC_evaluateInWorld):
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::IsolatedWorld::rememberDocument):
+        (WebCore::IsolatedWorld::forgetDocument):
+        (WebCore::IsolatedWorld::rememberScriptController):
+        (WebCore::IsolatedWorld::forgetScriptController):
+        (WebCore::DOMObjectHashTableMap::~DOMObjectHashTableMap):
+        (WebCore::DOMObjectHashTableMap::get):
+        (WebCore::WebCoreJSClientData::WebCoreJSClientData):
+        (WebCore::WebCoreJSClientData::currentWorld):
+        (WebCore::WebCoreJSClientData::normalWorld):
+        (WebCore::WebCoreJSClientData::rememberWorld):
+        (WebCore::WebCoreJSClientData::forgetWorld):
+        (WebCore::debuggerWorld):
+        (WebCore::pluginWorld):
+        * bindings/js/JSDOMGlobalObject.cpp:
+        (WebCore::JSDOMGlobalObject::createJSAttributeEventListener):
+        (WebCore::toJSDOMGlobalObject):
+        * bindings/js/JSDOMGlobalObject.h:
+        * bindings/js/JSDOMWindowBase.cpp:
+        (WebCore::JSDOMWindowBase::printErrorMessage):
+        (WebCore::JSDOMWindowBase::commonJSGlobalData):
+        (WebCore::toJS):
+        (WebCore::toJSDOMWindow):
+        * bindings/js/JSDOMWindowBase.h:
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::createWindow):
+        (WebCore::JSDOMWindow::open):
+        (WebCore::JSDOMWindow::showModalDialog):
+        (WebCore::JSDOMWindow::setTimeout):
+        (WebCore::JSDOMWindow::setInterval):
+        (WebCore::JSDOMWindow::addEventListener):
+        (WebCore::JSDOMWindow::removeEventListener):
+        * bindings/js/JSDOMWindowShell.cpp:
+        (WebCore::toJS):
+        (WebCore::toJSDOMWindowShell):
+        * bindings/js/JSDOMWindowShell.h:
+        * bindings/js/JSDesktopNotificationsCustom.cpp:
+        (WebCore::JSNotification::addEventListener):
+        (WebCore::):
+        * bindings/js/JSEventListener.cpp:
+        (WebCore::JSEventListener::JSEventListener):
+        (WebCore::JSEventListener::handleEvent):
+        (WebCore::JSEventListener::reportError):
+        * bindings/js/JSEventListener.h:
+        (WebCore::JSEventListener::create):
+        * bindings/js/JSEventSourceCustom.cpp:
+        (WebCore::JSEventSource::addEventListener):
+        (WebCore::JSEventSource::removeEventListener):
+        * bindings/js/JSEventTarget.cpp:
+        (WebCore::toJS):
+        * bindings/js/JSHTMLDocumentCustom.cpp:
+        (WebCore::JSHTMLDocument::open):
+        * bindings/js/JSHTMLFrameSetElementCustom.cpp:
+        (WebCore::JSHTMLFrameSetElement::nameGetter):
+        * bindings/js/JSInspectorBackendCustom.cpp:
+        (WebCore::JSInspectorBackend::databaseForId):
+        (WebCore::JSInspectorBackend::inspectedWindow):
+        (WebCore::JSInspectorBackend::nodeForId):
+        * bindings/js/JSLazyEventListener.cpp:
+        (WebCore::JSLazyEventListener::JSLazyEventListener):
+        (WebCore::JSLazyEventListener::parseCode):
+        * bindings/js/JSLazyEventListener.h:
+        (WebCore::JSLazyEventListener::create):
+        * bindings/js/JSMessageChannelCustom.cpp:
+        (WebCore::JSMessageChannel::markChildren):
+        * 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/JSNodeFilterCondition.cpp:
+        (WebCore::JSNodeFilterCondition::acceptNode):
+        * bindings/js/JSQuarantinedObjectWrapper.cpp:
+        (WebCore::JSQuarantinedObjectWrapper::construct):
+        (WebCore::JSQuarantinedObjectWrapper::call):
+        * bindings/js/JSSVGElementInstanceCustom.cpp:
+        (WebCore::JSSVGElementInstance::addEventListener):
+        (WebCore::JSSVGElementInstance::removeEventListener):
+        * bindings/js/JSSharedWorkerCustom.cpp:
+        (WebCore::JSSharedWorker::markChildren):
+        * bindings/js/JSWebSocketCustom.cpp:
+        (WebCore::JSWebSocket::addEventListener):
+        (WebCore::JSWebSocket::removeEventListener):
+        * bindings/js/JSWorkerContextCustom.cpp:
+        (WebCore::JSWorkerContext::addEventListener):
+        (WebCore::JSWorkerContext::removeEventListener):
+        (WebCore::JSWorkerContext::setTimeout):
+        (WebCore::JSWorkerContext::setInterval):
+        * bindings/js/JSXMLHttpRequestConstructor.cpp:
+        (WebCore::constructXMLHttpRequest):
+        * 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):
+        * bindings/js/ScheduledAction.cpp:
+        (WebCore::ScheduledAction::create):
+        (WebCore::ScheduledAction::ScheduledAction):
+        (WebCore::ScheduledAction::executeFunctionInContext):
+        (WebCore::ScheduledAction::execute):
+        * bindings/js/ScheduledAction.h:
+        (WebCore::ScheduledAction::ScheduledAction):
+        * bindings/js/ScriptCachedFrameData.cpp:
+        (WebCore::ScriptCachedFrameData::ScriptCachedFrameData):
+        (WebCore::ScriptCachedFrameData::restore):
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::~ScriptController):
+        (WebCore::ScriptController::evaluateInWorld):
+        (WebCore::ScriptController::evaluate):
+        (WebCore::ScriptController::evaluateInIsolatedWorld):
+        (WebCore::ScriptController::clearWindowShell):
+        (WebCore::ScriptController::initScript):
+        (WebCore::ScriptController::processingUserGestureEvent):
+        (WebCore::ScriptController::attachDebugger):
+        (WebCore::ScriptController::updateDocument):
+        (WebCore::ScriptController::bindingRootObject):
+        (WebCore::ScriptController::createRootObject):
+        (WebCore::ScriptController::windowScriptNPObject):
+        (WebCore::ScriptController::jsObjectForPluginElement):
+        * bindings/js/ScriptController.h:
+        (WebCore::ScriptController::windowShell):
+        (WebCore::ScriptController::existingWindowShell):
+        (WebCore::ScriptController::globalObject):
+        (WebCore::ScriptController::forgetWorld):
+        * bindings/js/ScriptControllerMac.mm:
+        (WebCore::ScriptController::windowScriptObject):
+        * bindings/js/ScriptEventListener.cpp:
+        (WebCore::createAttributeEventListener):
+        * bindings/js/ScriptFunctionCall.cpp:
+        (WebCore::ScriptFunctionCall::call):
+        (WebCore::ScriptFunctionCall::construct):
+        * bindings/js/ScriptObjectQuarantine.cpp:
+        (WebCore::getQuarantinedScriptObject):
+        * bindings/js/ScriptState.cpp:
+        (WebCore::scriptStateFromNode):
+        (WebCore::scriptStateFromPage):
+        * bindings/js/ScriptState.h:
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::WorkerScriptController):
+        (WebCore::WorkerScriptController::evaluate):
+        * bindings/objc/DOMInternal.mm:
+        (-[WebScriptObject _initializeScriptDOMNodeImp]):
+        * bindings/objc/WebScriptObject.mm:
+        (-[WebScriptObject callWebScriptMethod:withArguments:]):
+        (-[WebScriptObject evaluateWebScript:]):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        * bridge/NP_jsobject.cpp:
+        (_NPN_InvokeDefault):
+        (_NPN_Invoke):
+        (_NPN_Evaluate):
+        (_NPN_Construct):
+        * bridge/jni/jni_jsobject.mm:
+        (JavaJSObject::call):
+        (JavaJSObject::eval):
+        * dom/Document.cpp:
+        (WebCore::Document::createWrapperCache):
+        * dom/Document.h:
+        (WebCore::Document::wrapperCacheMap):
+        (WebCore::Document::getWrapperCache):
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::startUserInitiatedProfiling):
+        (WebCore::InspectorController::stopUserInitiatedProfiling):
+        * inspector/JavaScriptCallFrame.cpp:
+        (WebCore::JavaScriptCallFrame::evaluate):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::dispatchWindowObjectAvailable):
+        * platform/network/mac/AuthenticationMac.mm:
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::XMLHttpRequest):
+        (WebCore::XMLHttpRequest::dropProtection):
+        * xml/XMLHttpRequest.h:
+        (WebCore::XMLHttpRequest::create):
+
 2009-10-22  Joseph Pecoraro  <joepeck@webkit.org>
 
         Reviewed by Timothy Hatcher.
index d9ee12c..a7da54c 100644 (file)
@@ -272,7 +272,6 @@ __ZN7WebCore13HitTestResultD1Ev
 __ZN7WebCore13KeyboardEventC1ERKNS_12AtomicStringEbbPNS_9DOMWindowERKNS_6StringEjbbbbb
 __ZN7WebCore13TypingCommand39insertParagraphSeparatorInQuotedContentEPNS_8DocumentE
 __ZN7WebCore13toDeviceSpaceERKNS_9FloatRectEP8NSWindow
-__ZN7WebCore13toJSDOMWindowEPNS_5FrameE
 __ZN7WebCore14CachedResource12removeClientEPNS_20CachedResourceClientE
 __ZN7WebCore14CachedResource9addClientEPNS_20CachedResourceClientE
 __ZN7WebCore14DocumentLoader13attachToFrameEv
@@ -370,9 +369,10 @@ __ZN7WebCore16MIMETypeRegistry32isSupportedImageResourceMIMETypeERKNS_6StringE
 __ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_13FrameLoadTypeEb
 __ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_14NavigationTypeE
 __ZN7WebCore16NavigationActionC1Ev
-__ZN7WebCore16ScriptController10initScriptEv
+__ZN7WebCore16ScriptController10initScriptEPNS_15DOMWrapperWorldE
 __ZN7WebCore16ScriptController13executeScriptERKNS_6StringEb
 __ZN7WebCore16ScriptController18windowScriptObjectEv
+__ZN7WebCore16ScriptController28executeScriptInIsolatedWorldEjRKNS_6StringEb
 __ZN7WebCore16VisibleSelectionC1EPKNS_5RangeENS_9EAffinityE
 __ZN7WebCore16VisibleSelectionC1ERKNS_15VisiblePositionES3_
 __ZN7WebCore16colorFromNSColorEP7NSColor
@@ -386,6 +386,7 @@ __ZN7WebCore17DOMImplementation14isTextMIMETypeERKNS_6StringE
 __ZN7WebCore17GlyphPageTreeNode18treeGlyphPageCountEv
 __ZN7WebCore17HistoryController26saveDocumentAndScrollStateEv
 __ZN7WebCore17HTMLPlugInElement11getNPObjectEv
+__ZN7WebCore21mainThreadNormalWorldEv
 __ZN7WebCore17equalIgnoringCaseEPNS_10StringImplES1_
 __ZN7WebCore18deprecatedParseURLERKNS_6StringE
 __ZN7WebCore18isStartOfParagraphERKNS_15VisiblePositionE
@@ -454,6 +455,7 @@ __ZN7WebCore31applicationIsMicrosoftMessengerEv
 __ZN7WebCore32plainTextToMallocAllocatedBufferEPKNS_5RangeERjb
 __ZN7WebCore33setDefaultThreadViolationBehaviorENS_23ThreadViolationBehaviorENS_20ThreadViolationRoundE
 __ZN7WebCore36InitializeLoggingChannelsIfNecessaryEv
+__ZN7WebCore33DebuggerCallFrame_evaluateInWorldERKN3JSC17DebuggerCallFrameERKNS0_7UStringERNS0_7JSValueE
 __ZN7WebCore3macERKNS_10CredentialE
 __ZN7WebCore3macERKNS_23AuthenticationChallengeE
 __ZN7WebCore4Font11setCodePathENS0_8CodePathE
index 4d73d83..2d9eb02 100644 (file)
@@ -53,6 +53,46 @@ ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode)
     return result;
 }
 
+ScriptValue ScriptController::executeScriptInIsolatedWorld(unsigned worldID, const String& script, bool forceUserGesture)
+{
+    ScriptSourceCode sourceCode(script, forceUserGesture ? KURL() : m_frame->loader()->url());
+
+    if (!isEnabled() || isPaused())
+        return ScriptValue();
+
+    bool wasInExecuteScript = m_inExecuteScript;
+    m_inExecuteScript = true;
+
+    ScriptValue result = evaluateInIsolatedWorld(worldID, sourceCode);
+
+    if (!wasInExecuteScript) {
+        m_inExecuteScript = false;
+        Document::updateStyleForAllDocuments();
+    }
+
+    return result;
+}
+
+ScriptValue ScriptController::executeScriptInIsolatedWorld(DOMWrapperWorld* world, const String& script, bool forceUserGesture)
+{
+    ScriptSourceCode sourceCode(script, forceUserGesture ? KURL() : m_frame->loader()->url());
+
+    if (!isEnabled() || isPaused())
+        return ScriptValue();
+
+    bool wasInExecuteScript = m_inExecuteScript;
+    m_inExecuteScript = true;
+
+    ScriptValue result = evaluateInWorld(sourceCode, world);
+
+    if (!wasInExecuteScript) {
+        m_inExecuteScript = false;
+        Document::updateStyleForAllDocuments();
+    }
+
+    return result;
+}
+
 bool ScriptController::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument)
 {
     if (!protocolIsJavaScript(url))
index a6cbd91..6eca7bd 100644 (file)
@@ -50,7 +50,7 @@ JSValue JSAbstractWorker::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -60,7 +60,7 @@ JSValue JSAbstractWorker::removeEventListener(ExecState* exec, const ArgList& ar
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index d08f760..38292c7 100644 (file)
@@ -48,7 +48,12 @@ JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedE
 
     ExecState* exec = globalObject()->globalExec();
     
-    JSValue function = callback()->get(exec, Identifier(exec, "handleEvent"));
+    JSValue function;
+    {
+        // Switch worlds, just in case handleEvent is a getter and causes JS execution!
+        EnterDOMWrapperWorld worldEntry(exec, m_isolatedWorld.get());
+        function = callback()->get(exec, Identifier(exec, "handleEvent"));
+    }
     CallData callData;
     CallType callType = function.getCallData(callData);
     if (callType == CallTypeNone) {
@@ -59,7 +64,7 @@ JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedE
     }
     
     globalObject()->globalData()->timeoutChecker.start();
-    JSValue result = call(exec, function, callType, callData, callback(), args);
+    JSValue result = callInWorld(exec, function, callType, callData, callback(), args, m_isolatedWorld.get());
     globalObject()->globalData()->timeoutChecker.stop();
 
     Document::updateStyleForAllDocuments();
index 4fc9f84..5c86701 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef JSCallbackData_h
 #define JSCallbackData_h
 
+#include "JSDOMBinding.h"
 #include "JSDOMGlobalObject.h"
 #include <runtime/JSObject.h>
 #include <runtime/Protect.h>
@@ -47,6 +48,7 @@ public:
     JSCallbackData(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)
         : m_callback(callback)
         , m_globalObject(globalObject)
+        , m_isolatedWorld(currentWorld(globalObject->globalExec()))
     {
     }
     
@@ -63,6 +65,7 @@ public:
 private:
     JSC::ProtectedPtr<JSC::JSObject> m_callback;
     JSC::ProtectedPtr<JSDOMGlobalObject> m_globalObject;
+    RefPtr<DOMWrapperWorld> m_isolatedWorld;
 };
 
 } // namespace WebCore
index da4a53a..c2884d7 100644 (file)
@@ -90,7 +90,7 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix)
     args.append(jsString(exec, prefix));
 
     m_globalObject->globalData()->timeoutChecker.start();
-    JSValue retval = call(exec, function, callType, callData, m_customResolver, args);
+    JSValue retval = callInWorld(exec, function, callType, callData, m_customResolver, args, currentWorld(m_globalObject->globalExec()));
     m_globalObject->globalData()->timeoutChecker.stop();
 
     String result;
index 8634589..91ee51a 100644 (file)
@@ -91,7 +91,7 @@ JSValue JSDOMApplicationCache::addEventListener(ExecState* exec, const ArgList&
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -101,7 +101,7 @@ JSValue JSDOMApplicationCache::removeEventListener(ExecState* exec, const ArgLis
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 8168323..ef69c7b 100644 (file)
@@ -21,6 +21,8 @@
 #include "config.h"
 #include "JSDOMBinding.h"
 
+#include "debugger/DebuggerCallFrame.h"
+
 #include "ActiveDOMObject.h"
 #include "DOMCoreException.h"
 #include "Document.h"
@@ -44,6 +46,7 @@
 #include "MessagePort.h"
 #include "RangeException.h"
 #include "ScriptController.h"
+#include "Settings.h"
 #include "XMLHttpRequestException.h"
 #include <runtime/Error.h>
 #include <runtime/JSFunction.h>
@@ -72,6 +75,7 @@ namespace WebCore {
 using namespace HTMLNames;
 
 typedef Document::JSWrapperCache JSWrapperCache;
+typedef Document::JSWrapperCacheMap JSWrapperCacheMap;
 
 // For debugging, keep a set of wrappers currently registered, and check that
 // all are unregistered before they are destroyed. This has helped us fix at
@@ -80,6 +84,7 @@ typedef Document::JSWrapperCache JSWrapperCache;
 static void addWrapper(DOMObject* wrapper);
 static void removeWrapper(DOMObject* wrapper);
 static void removeWrappers(const JSWrapperCache& wrappers);
+static void removeWrappers(const DOMObjectWrapperMap& wrappers);
 
 #ifdef NDEBUG
 
@@ -95,6 +100,10 @@ static inline void removeWrappers(const JSWrapperCache&)
 {
 }
 
+static inline void removeWrappers(const DOMObjectWrapperMap&)
+{
+}
+
 #else
 
 static HashSet<DOMObject*>& wrapperSet()
@@ -124,7 +133,15 @@ static void removeWrapper(DOMObject* wrapper)
 
 static void removeWrappers(const JSWrapperCache& wrappers)
 {
-    for (JSWrapperCache::const_iterator it = wrappers.begin(); it != wrappers.end(); ++it)
+    JSWrapperCache::const_iterator wrappersEnd = wrappers.end();
+    for (JSWrapperCache::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
+        removeWrapper(it->second);
+}
+
+static inline void removeWrappers(const DOMObjectWrapperMap& wrappers)
+{
+    DOMObjectWrapperMap::const_iterator wrappersEnd = wrappers.end();
+    for (DOMObjectWrapperMap::const_iterator it = wrappers.begin(); it != wrappersEnd; ++it)
         removeWrapper(it->second);
 }
 
@@ -135,67 +152,120 @@ DOMObject::~DOMObject()
 
 #endif
 
-class DOMObjectWrapperMap {
-public:
-    static DOMObjectWrapperMap& mapFor(JSGlobalData&);
+DOMWrapperWorld::DOMWrapperWorld(JSC::JSGlobalData* globalData)
+    : m_globalData(globalData)
+{
+}
+
+DOMWrapperWorld::~DOMWrapperWorld()
+{
+    JSGlobalData::ClientData* clientData = m_globalData->clientData;
+    ASSERT(clientData);
+    static_cast<WebCoreJSClientData*>(clientData)->forgetWorld(this);
+
+    removeWrappers(m_wrappers);
 
-    DOMObject* get(void* objectHandle)
+    for (HashSet<Document*>::iterator iter = documentsWithWrappers.begin(); iter != documentsWithWrappers.end(); ++iter)
+        forgetWorldOfDOMNodesForDocument(*iter, this);
+    for (HashSet<ScriptController*>::iterator iter = scriptControllersWithShells.begin(); iter != scriptControllersWithShells.end(); ++iter)
+        (*iter)->forgetWorld(this);
+}
+
+EnterDOMWrapperWorld::EnterDOMWrapperWorld(JSC::JSGlobalData& globalData, DOMWrapperWorld* isolatedWorld)
+{
+    JSGlobalData::ClientData* clientData = globalData.clientData;
+    ASSERT(clientData);
+    m_clientData = static_cast<WebCoreJSClientData*>(clientData);
+    m_clientData->m_worldStack.append(isolatedWorld);
+}
+
+EnterDOMWrapperWorld::EnterDOMWrapperWorld(JSC::ExecState* exec, DOMWrapperWorld* isolatedWorld)
+{
+    JSGlobalData::ClientData* clientData = exec->globalData().clientData;
+    ASSERT(clientData);
+    m_clientData = static_cast<WebCoreJSClientData*>(clientData);
+    m_clientData->m_worldStack.append(isolatedWorld);
+}
+
+EnterDOMWrapperWorld::~EnterDOMWrapperWorld()
+{
+    m_clientData->m_worldStack.removeLast();
+}
+
+class JSGlobalDataWorldIterator {
+public:
+    JSGlobalDataWorldIterator(JSGlobalData* globalData)
+        : m_pos(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.begin())
+        , m_end(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.end())
     {
-        return m_map.get(objectHandle);
     }
 
-    void set(void* objectHandle, DOMObject* wrapper)
+    operator bool()
     {
-        addWrapper(wrapper);
-        m_map.set(objectHandle, wrapper);
+        return m_pos != m_end;
     }
 
-    void remove(void* objectHandle)
+    DOMWrapperWorld* operator*()
     {
-        removeWrapper(m_map.take(objectHandle));
+        ASSERT(m_pos != m_end);
+        return *m_pos;
     }
 
-private:
-    HashMap<void*, DOMObject*> m_map;
-};
-
-// Map from static HashTable instances to per-GlobalData ones.
-class DOMObjectHashTableMap {
-public:
-    static DOMObjectHashTableMap& mapFor(JSGlobalData&);
-
-    ~DOMObjectHashTableMap()
+    DOMWrapperWorld* operator->()
     {
-        HashMap<const JSC::HashTable*, JSC::HashTable>::iterator mapEnd = m_map.end();
-        for (HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
-            iter->second.deleteTable();
+        ASSERT(m_pos != m_end);
+        return *m_pos;
     }
 
-    const JSC::HashTable* get(const JSC::HashTable* staticTable)
+    JSGlobalDataWorldIterator& operator++()
     {
-        HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.find(staticTable);
-        if (iter != m_map.end())
-            return &iter->second;
-        return &m_map.set(staticTable, JSC::HashTable(*staticTable)).first->second;
+        ++m_pos;
+        return *this;
     }
 
 private:
-    HashMap<const JSC::HashTable*, JSC::HashTable> m_map;
+    HashSet<DOMWrapperWorld*>::iterator m_pos;
+    HashSet<DOMWrapperWorld*>::iterator m_end;
 };
 
-class WebCoreJSClientData : public JSGlobalData::ClientData {
-public:
-    DOMObjectHashTableMap hashTableMap;
-    DOMObjectWrapperMap wrapperMap;
-};
+static inline DOMWrapperWorld* currentWorld(JSC::JSGlobalData& globalData)
+{
+    JSGlobalData::ClientData* clientData = globalData.clientData;
+    ASSERT(clientData);
+    return static_cast<WebCoreJSClientData*>(clientData)->currentWorld();
+}
+
+DOMWrapperWorld* currentWorld(JSC::ExecState* exec)
+{
+    return currentWorld(exec->globalData());
+}
+
+DOMWrapperWorld* normalWorld(JSC::JSGlobalData& globalData)
+{
+    JSGlobalData::ClientData* clientData = globalData.clientData;
+    ASSERT(clientData);
+    return static_cast<WebCoreJSClientData*>(clientData)->normalWorld();
+}
+
+DOMWrapperWorld* mainThreadNormalWorld()
+{
+    ASSERT(isMainThread());
+    return normalWorld(*JSDOMWindow::commonJSGlobalData());
+}
+
+DOMWrapperWorld* mainThreadCurrentWorld()
+{
+    ASSERT(isMainThread());
+
+    JSGlobalData::ClientData* clientData = JSDOMWindowBase::commonJSGlobalData()->clientData;
+    ASSERT(clientData);
+    return static_cast<WebCoreJSClientData*>(clientData)->currentWorld();
+}
 
 DOMObjectHashTableMap& DOMObjectHashTableMap::mapFor(JSGlobalData& globalData)
 {
     JSGlobalData::ClientData* clientData = globalData.clientData;
-    if (!clientData) {
-        clientData = new WebCoreJSClientData;
-        globalData.clientData = clientData;
-    }
+    ASSERT(clientData);
     return static_cast<WebCoreJSClientData*>(clientData)->hashTableMap;
 }
 
@@ -204,64 +274,102 @@ const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const
     return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
 }
 
-inline DOMObjectWrapperMap& DOMObjectWrapperMap::mapFor(JSGlobalData& globalData)
+//inline DOMObjectWrapperMap& DOMObjectWrapperMap::mapFor(JSGlobalData& globalData)
+inline DOMObjectWrapperMap& DOMObjectWrapperMapFor(JSGlobalData& globalData)
 {
-    JSGlobalData::ClientData* clientData = globalData.clientData;
-    if (!clientData) {
-        clientData = new WebCoreJSClientData;
-        globalData.clientData = clientData;
-    }
-    return static_cast<WebCoreJSClientData*>(clientData)->wrapperMap;
+    return currentWorld(globalData)->m_wrappers;
 }
 
 DOMObject* getCachedDOMObjectWrapper(JSGlobalData& globalData, void* objectHandle) 
 {
-    return DOMObjectWrapperMap::mapFor(globalData).get(objectHandle);
+    return DOMObjectWrapperMapFor(globalData).get(objectHandle);
 }
 
 void cacheDOMObjectWrapper(JSGlobalData& globalData, void* objectHandle, DOMObject* wrapper) 
 {
-    DOMObjectWrapperMap::mapFor(globalData).set(objectHandle, wrapper);
+    addWrapper(wrapper);
+    DOMObjectWrapperMapFor(globalData).set(objectHandle, wrapper);
 }
 
-void forgetDOMObject(JSGlobalData& globalData, void* objectHandle)
+JSNode* getCachedDOMNodeWrapper(Document* document, Node* node)
 {
-    DOMObjectWrapperMap::mapFor(globalData).remove(objectHandle);
+    if (document)
+        return document->getWrapperCache(mainThreadCurrentWorld())->get(node);
+    return static_cast<JSNode*>(DOMObjectWrapperMapFor(*JSDOMWindow::commonJSGlobalData()).get(node));
 }
 
-JSNode* getCachedDOMNodeWrapper(Document* document, Node* node)
+void forgetDOMObject(DOMObject* wrapper, void* objectHandle)
 {
-    if (!document)
-        return static_cast<JSNode*>(DOMObjectWrapperMap::mapFor(*JSDOMWindow::commonJSGlobalData()).get(node));
-    return document->wrapperCache().get(node);
+    JSC::JSGlobalData* globalData = Heap::heap(wrapper)->globalData();
+    for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
+        DOMObjectWrapperMap& wrappers = worldIter->m_wrappers;
+        DOMObjectWrapperMap::iterator iter = wrappers.find(objectHandle);
+        if ((iter != wrappers.end()) && (iter->second == wrapper)) {
+            removeWrapper(wrapper);
+            wrappers.remove(iter);
+            return;
+        }
+    }
+
+    // If the world went away, it should have removed this wrapper from the set.
+    ASSERT(!wrapperSet().contains(wrapper));
 }
 
-void forgetDOMNode(Document* document, Node* node)
+void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document)
 {
     if (!document) {
-        DOMObjectWrapperMap::mapFor(*JSDOMWindow::commonJSGlobalData()).remove(node);
+        forgetDOMObject(wrapper, node);
         return;
     }
-    removeWrapper(document->wrapperCache().take(node));
+
+    JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
+    for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
+        JSWrapperCache* wrappers = wrappersIter->second;
+        JSWrapperCache::iterator iter = wrappers->find(node);
+        if ((iter != wrappers->end()) && (iter->second == wrapper)) {
+            wrappers->remove(iter);
+            removeWrapper(wrapper);
+            return;
+        }
+    }
+
+    // If the world went away, it should have removed this wrapper from the set.
+    ASSERT(!wrapperSet().contains(wrapper));
 }
 
 void cacheDOMNodeWrapper(Document* document, Node* node, JSNode* wrapper)
 {
     if (!document) {
-        DOMObjectWrapperMap::mapFor(*JSDOMWindow::commonJSGlobalData()).set(node, wrapper);
+        addWrapper(wrapper);
+        DOMObjectWrapperMapFor(*JSDOMWindow::commonJSGlobalData()).set(node, wrapper);
         return;
     }
     addWrapper(wrapper);
-    document->wrapperCache().set(node, wrapper);
+    document->getWrapperCache(mainThreadCurrentWorld())->set(node, wrapper);
 }
 
 void forgetAllDOMNodesForDocument(Document* document)
 {
     ASSERT(document);
-    removeWrappers(document->wrapperCache());
+    JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
+    JSWrapperCacheMap::const_iterator wrappersMapEnd = wrapperCacheMap.end();
+    for (JSWrapperCacheMap::const_iterator wrappersMapIter = wrapperCacheMap.begin(); wrappersMapIter != wrappersMapEnd; ++wrappersMapIter) {
+        JSWrapperCache* wrappers = wrappersMapIter->second;
+        removeWrappers(*wrappers);
+        delete wrappers;
+        wrappersMapIter->first->forgetDocument(document);
+    }
+}
+
+void forgetWorldOfDOMNodesForDocument(Document* document, DOMWrapperWorld* world)
+{
+    JSWrapperCache* wrappers = document->wrapperCacheMap().take(world);
+    ASSERT(wrappers); // 'world' should only know about 'document' if 'document' knows about 'world'!
+    removeWrappers(*wrappers);
+    delete wrappers;
 }
 
-static inline bool isObservableThroughDOM(JSNode* jsNode)
+static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world)
 {
     // Certain conditions implicitly make a JS DOM node wrapper observable
     // through the DOM, even if no explicit reference to it remains.
@@ -287,14 +395,14 @@ static inline bool isObservableThroughDOM(JSNode* jsNode)
         // the custom markChildren functions rather than here.
         if (node->isElementNode()) {
             if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
-                if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), attributes)) {
+                if (DOMObject* wrapper = world->m_wrappers.get(attributes)) {
                     if (wrapper->hasCustomProperties())
                         return true;
                 }
             }
             if (node->isStyledElement()) {
                 if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
-                    if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), style)) {
+                    if (DOMObject* wrapper = world->m_wrappers.get(style)) {
                         if (wrapper->hasCustomProperties())
                             return true;
                     }
@@ -302,7 +410,7 @@ static inline bool isObservableThroughDOM(JSNode* jsNode)
             }
             if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
                 if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
-                    if (DOMObject* wrapper = getCachedDOMObjectWrapper(*jsNode->globalObject()->globalData(), context)) {
+                    if (DOMObject* wrapper = world->m_wrappers.get(context)) {
                         if (wrapper->hasCustomProperties())
                             return true;
                     }
@@ -333,14 +441,19 @@ static inline bool isObservableThroughDOM(JSNode* jsNode)
     return false;
 }
 
-void markDOMNodesForDocument(MarkStack& markStack, Document* doc)
+void markDOMNodesForDocument(MarkStack& markStack, Document* document)
 {
-    JSWrapperCache& nodeDict = doc->wrapperCache();
-    JSWrapperCache::iterator nodeEnd = nodeDict.end();
-    for (JSWrapperCache::iterator nodeIt = nodeDict.begin(); nodeIt != nodeEnd; ++nodeIt) {
-        JSNode* jsNode = nodeIt->second;
-        if (isObservableThroughDOM(jsNode))
-            markStack.append(jsNode);
+    JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
+    for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
+        DOMWrapperWorld* world = wrappersIter->first;
+        JSWrapperCache* nodeDict = wrappersIter->second;
+
+        JSWrapperCache::iterator nodeEnd = nodeDict->end();
+        for (JSWrapperCache::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) {
+            JSNode* jsNode = nodeIt->second;
+            if (isObservableThroughDOM(jsNode, world))
+                markStack.append(jsNode);
+        }
     }
 }
 
@@ -353,12 +466,10 @@ void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData,
     HashMap<ActiveDOMObject*, void*>::const_iterator activeObjectsEnd = activeObjects.end();
     for (HashMap<ActiveDOMObject*, void*>::const_iterator iter = activeObjects.begin(); iter != activeObjectsEnd; ++iter) {
         if (iter->first->hasPendingActivity()) {
-            DOMObject* wrapper = getCachedDOMObjectWrapper(globalData, iter->second);
             // Generally, an active object with pending activity must have a wrapper to mark its listeners.
             // However, some ActiveDOMObjects don't have JS wrappers (timers created by setTimeout is one example).
             // FIXME: perhaps need to make sure even timers have a markable 'wrapper'.
-            if (wrapper)
-                markStack.append(wrapper);
+            markDOMObjectWrapper(markStack, globalData, iter->second);
         }
     }
 
@@ -366,10 +477,31 @@ void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData,
     HashSet<MessagePort*>::const_iterator portsEnd = messagePorts.end();
     for (HashSet<MessagePort*>::const_iterator iter = messagePorts.begin(); iter != portsEnd; ++iter) {
         // If the message port is remotely entangled, then always mark it as in-use because we can't determine reachability across threads.
-        if (!(*iter)->locallyEntangledPort() || (*iter)->hasPendingActivity()) {
-            DOMObject* wrapper = getCachedDOMObjectWrapper(globalData, *iter);
-            if (wrapper)
-                markStack.append(wrapper);
+        if (!(*iter)->locallyEntangledPort() || (*iter)->hasPendingActivity())
+            markDOMObjectWrapper(markStack, globalData, *iter);
+    }
+}
+
+typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld;
+typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet;
+
+static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet)
+{
+    if (document) {
+        JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
+        for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
+            if (JSNode* wrapper = iter->second->take(node)) {
+                removeWrapper(wrapper);
+                wrapperSet.append(WrapperAndWorld(wrapper, iter->first));
+            }
+        }
+    } else {
+        for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
+            DOMWrapperWorld* world = *worldIter;
+            if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node))) {
+                removeWrapper(wrapper);
+                wrapperSet.append(WrapperAndWorld(wrapper, world));
+            }
         }
     }
 }
@@ -377,13 +509,18 @@ void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData,
 void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)
 {
     ASSERT(oldDocument != newDocument);
-    JSNode* wrapper = getCachedDOMNodeWrapper(oldDocument, node);
-    if (!wrapper)
-        return;
-    removeWrapper(wrapper);
-    cacheDOMNodeWrapper(newDocument, node, wrapper);
-    forgetDOMNode(oldDocument, node);
-    addWrapper(wrapper);
+
+    WrapperSet wrapperSet;
+    takeWrappers(node, oldDocument, wrapperSet);
+
+    for (unsigned i = 0; i < wrapperSet.size(); ++i) {
+        JSNode* wrapper = wrapperSet[i].first;
+        if (newDocument)
+            newDocument->getWrapperCache(wrapperSet[i].second)->set(node, wrapper);
+        else
+            wrapperSet[i].second->m_wrappers.set(node, wrapper);
+        addWrapper(wrapper);
+    }
 }
 
 void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object)
@@ -393,10 +530,11 @@ void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void*
     // but doing this correctly would be challenging.
     if (!object)
         return;
-    DOMObject* wrapper = getCachedDOMObjectWrapper(globalData, object);
-    if (!wrapper)
-        return;
-    markStack.append(wrapper);
+
+    for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) {
+        if (DOMObject* wrapper = worldIter->m_wrappers.get(object))
+            markStack.append(wrapper);
+    }
 }
 
 JSValue jsStringOrNull(ExecState* exec, const String& s)
@@ -543,7 +681,7 @@ bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
 {
     if (!frame)
         return false;
-    JSDOMWindow* window = toJSDOMWindow(frame);
+    JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
     return window && window->allowsAccessFrom(exec);
 }
 
@@ -551,7 +689,7 @@ bool allowsAccessFromFrame(ExecState* exec, Frame* frame, String& message)
 {
     if (!frame)
         return false;
-    JSDOMWindow* window = toJSDOMWindow(frame);
+    JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
     return window && window->allowsAccessFrom(exec, message);
 }
 
@@ -565,8 +703,16 @@ void printErrorMessageForFrame(Frame* frame, const String& message)
 {
     if (!frame)
         return;
-    if (JSDOMWindow* window = toJSDOMWindow(frame))
-        window->printErrorMessage(message);
+    if (message.isEmpty())
+        return;
+
+    Settings* settings = frame->settings();
+    if (!settings)
+        return;
+    if (settings->privateBrowsingEnabled())
+        return;
+
+    frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
 }
 
 Frame* toLexicalFrame(ExecState* exec)
@@ -664,4 +810,28 @@ bool DOMObject::defineOwnProperty(ExecState* exec, const Identifier&, PropertyDe
     return false;
 }
 
+JSValue DebuggerCallFrame_evaluateInWorld(const JSC::DebuggerCallFrame& debuggerCallFrame, const UString& script, JSValue& exception)
+{
+    EnterDOMWrapperWorld worldEntry(debuggerCallFrame.dynamicGlobalObject()->globalExec(), debuggerWorld());
+    return debuggerCallFrame.evaluate(script, exception);
+}
+
+JSValue callInWorld(ExecState* exec, JSValue function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, DOMWrapperWorld* isolatedWorld)
+{
+    EnterDOMWrapperWorld worldEntry(exec, isolatedWorld);
+    return JSC::call(exec, function, callType, callData, thisValue, args);
+}
+
+JSObject* constructInWorld(ExecState* exec, JSValue object, ConstructType constructType, const ConstructData& constructData, const ArgList& args, DOMWrapperWorld* isolatedWorld)
+{
+    EnterDOMWrapperWorld worldEntry(exec, isolatedWorld);
+    return JSC::construct(exec, object, constructType, constructData, args);
+}
+
+Completion evaluateInWorld(ExecState* exec, ScopeChain& scopeChain, const SourceCode& sourceCode, JSValue thisValue, DOMWrapperWorld* isolatedWorld)
+{
+    EnterDOMWrapperWorld worldEntry(exec, isolatedWorld);
+    return JSC::evaluate(exec, scopeChain, sourceCode, thisValue);
+}
+
 } // namespace WebCore
index 9af45d7..ba41d85 100644 (file)
 
 namespace JSC {
     class JSGlobalData;
+    class DebuggerCallFrame;
 }
 
 namespace WebCore {
 
     class Document;
     class Frame;
+    class JSNode;
     class KURL;
     class Node;
     class String;
-    class JSNode;
+    class ScriptController;
 
     typedef int ExceptionCode;
 
@@ -136,14 +138,104 @@ namespace WebCore {
         }
     };
 
+    typedef HashMap<void*, DOMObject*> DOMObjectWrapperMap;
+
+    class DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
+    public:
+        DOMWrapperWorld(JSC::JSGlobalData*);
+        ~DOMWrapperWorld();
+
+        void rememberDocument(Document* document) { documentsWithWrappers.add(document); }
+        void forgetDocument(Document* document) { documentsWithWrappers.remove(document); }
+        void rememberScriptController(ScriptController* scriptController) { scriptControllersWithShells.add(scriptController); }
+        void forgetScriptController(ScriptController* scriptController) { scriptControllersWithShells.remove(scriptController); }
+
+        // FIXME: can we make this private?
+        DOMObjectWrapperMap m_wrappers;
+
+    private:
+        JSC::JSGlobalData* m_globalData;
+        HashSet<Document*> documentsWithWrappers;
+        HashSet<ScriptController*> scriptControllersWithShells;
+    };
+
+    // Map from static HashTable instances to per-GlobalData ones.
+    class DOMObjectHashTableMap {
+    public:
+        static DOMObjectHashTableMap& mapFor(JSC::JSGlobalData&);
+
+        ~DOMObjectHashTableMap()
+        {
+            HashMap<const JSC::HashTable*, JSC::HashTable>::iterator mapEnd = m_map.end();
+            for (HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
+                iter->second.deleteTable();
+        }
+
+        const JSC::HashTable* get(const JSC::HashTable* staticTable)
+        {
+            HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.find(staticTable);
+            if (iter != m_map.end())
+                return &iter->second;
+            return &m_map.set(staticTable, JSC::HashTable(*staticTable)).first->second;
+        }
+
+    private:
+        HashMap<const JSC::HashTable*, JSC::HashTable> m_map;
+    };
+
+    class WebCoreJSClientData : public JSC::JSGlobalData::ClientData {
+        friend class EnterDOMWrapperWorld;
+        friend class JSGlobalDataWorldIterator;
+
+    public:
+        WebCoreJSClientData(JSC::JSGlobalData* globalData)
+            : m_normalWorld(globalData)
+        {
+            m_worldStack.append(&m_normalWorld);
+            m_worldSet.add(&m_normalWorld);
+        }
+        // FIXME: add a destructor to assert m_worldSet only contains m_normalWorld?
+
+        DOMWrapperWorld* currentWorld() { return m_worldStack.last(); }
+        DOMWrapperWorld* normalWorld() { return &m_normalWorld; }
+
+        void rememberWorld(DOMWrapperWorld* world)
+        {
+            ASSERT(!m_worldSet.contains(world));
+            m_worldSet.add(world);
+        }
+        void forgetWorld(DOMWrapperWorld* world)
+        {
+            ASSERT(m_worldSet.contains(world));
+            m_worldSet.remove(world);
+        }
+
+        DOMObjectHashTableMap hashTableMap;
+    private:
+        Vector<DOMWrapperWorld*> m_worldStack;
+        HashSet<DOMWrapperWorld*> m_worldSet;
+        DOMWrapperWorld m_normalWorld;
+    };
+
+    class EnterDOMWrapperWorld {
+    public:
+        EnterDOMWrapperWorld(JSC::JSGlobalData&, DOMWrapperWorld*);
+        EnterDOMWrapperWorld(JSC::ExecState*, DOMWrapperWorld*);
+        ~EnterDOMWrapperWorld();
+
+    private:
+        WebCoreJSClientData* m_clientData;
+    };
+
     DOMObject* getCachedDOMObjectWrapper(JSC::JSGlobalData&, void* objectHandle);
     void cacheDOMObjectWrapper(JSC::JSGlobalData&, void* objectHandle, DOMObject* wrapper);
-    void forgetDOMObject(JSC::JSGlobalData&, void* objectHandle);
+    void forgetDOMNode(DOMObject* wrapper, Node* node, Document* document);
+    void forgetDOMObject(DOMObject* wrapper, void* objectHandle);
 
     JSNode* getCachedDOMNodeWrapper(Document*, Node*);
     void cacheDOMNodeWrapper(Document*, Node*, JSNode* wrapper);
-    void forgetDOMNode(Document*, Node*);
     void forgetAllDOMNodesForDocument(Document*);
+    void forgetWorldOfDOMNodesForDocument(Document*, DOMWrapperWorld*);
     void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
     void markDOMNodesForDocument(JSC::MarkStack&, Document*);
     void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*);
@@ -154,6 +246,13 @@ namespace WebCore {
     JSC::Structure* getCachedDOMStructure(JSC::ExecState*, const JSC::ClassInfo*);
     JSC::Structure* cacheDOMStructure(JSC::ExecState*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
 
+    DOMWrapperWorld* currentWorld(JSC::ExecState*);
+    DOMWrapperWorld* normalWorld(JSC::JSGlobalData&);
+    DOMWrapperWorld* mainThreadCurrentWorld();
+    DOMWrapperWorld* mainThreadNormalWorld();
+    inline DOMWrapperWorld* debuggerWorld() { return mainThreadNormalWorld(); }
+    inline DOMWrapperWorld* pluginWorld() { return mainThreadNormalWorld(); }
+
     JSC::JSObject* getCachedDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*);
     void cacheDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*, JSC::JSObject* constructor);
 
@@ -305,6 +404,11 @@ namespace WebCore {
     bool processingUserGesture(JSC::ExecState*);
     KURL completeURL(JSC::ExecState*, const String& relativeURL);
 
+    JSC::JSValue DebuggerCallFrame_evaluateInWorld(const JSC::DebuggerCallFrame& debuggerCallFrame, const JSC::UString& script, JSC::JSValue& exception);
+    JSC::JSValue callInWorld(JSC::ExecState*, JSC::JSValue function, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList&, DOMWrapperWorld*);
+    JSC::JSObject* constructInWorld(JSC::ExecState* exec, JSC::JSValue object, JSC::ConstructType constructType, const JSC::ConstructData& constructData, const JSC::ArgList& args, DOMWrapperWorld*);
+    JSC::Completion evaluateInWorld(JSC::ExecState*, JSC::ScopeChain&, const JSC::SourceCode&, JSC::JSValue thisValue, DOMWrapperWorld*);
+
 } // namespace WebCore
 
 #endif // JSDOMBinding_h
index 53bb26b..011a4e4 100644 (file)
@@ -63,7 +63,7 @@ PassRefPtr<JSEventListener> JSDOMGlobalObject::createJSAttributeEventListener(JS
     if (!val.isObject())
         return 0;
 
-    return JSEventListener::create(asObject(val), true).get();
+    return JSEventListener::create(asObject(val), true, currentWorld(globalExec())).get();
 }
 
 void JSDOMGlobalObject::setCurrentEvent(Event* evt)
@@ -81,15 +81,34 @@ void JSDOMGlobalObject::destroyJSDOMGlobalObjectData(void* jsDOMGlobalObjectData
     delete static_cast<JSDOMGlobalObjectData*>(jsDOMGlobalObjectData);
 }
 
-JSDOMGlobalObject* toJSDOMGlobalObject(Document* document)
+JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, JSC::ExecState* exec)
 {
-    return toJSDOMWindow(document->frame());
+    return toJSDOMWindow(document->frame(), currentWorld(exec));
 }
 
-JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext)
+JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, JSC::ExecState* exec)
 {
     if (scriptExecutionContext->isDocument())
-        return toJSDOMGlobalObject(static_cast<Document*>(scriptExecutionContext));
+        return toJSDOMGlobalObject(static_cast<Document*>(scriptExecutionContext), exec);
+
+#if ENABLE(WORKERS)
+    if (scriptExecutionContext->isWorkerContext())
+        return static_cast<WorkerContext*>(scriptExecutionContext)->script()->workerContextWrapper();
+#endif
+
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, DOMWrapperWorld* world)
+{
+    return toJSDOMWindow(document->frame(), world);
+}
+
+JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, DOMWrapperWorld* world)
+{
+    if (scriptExecutionContext->isDocument())
+        return toJSDOMGlobalObject(static_cast<Document*>(scriptExecutionContext), world);
 
 #if ENABLE(WORKERS)
     if (scriptExecutionContext->isWorkerContext())
index ce26857..6b75a6f 100644 (file)
@@ -33,6 +33,7 @@ namespace WebCore {
 
     class Document;
     class Event;
+    class DOMWrapperWorld;
     class JSLazyEventListener;
     class JSEventListener;
     class ScriptExecutionContext;
@@ -102,8 +103,11 @@ namespace WebCore {
         return constructor;
     }
 
-    JSDOMGlobalObject* toJSDOMGlobalObject(Document*);
-    JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext*);
+    JSDOMGlobalObject* toJSDOMGlobalObject(Document*, JSC::ExecState*);
+    JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext*, JSC::ExecState*);
+
+    JSDOMGlobalObject* toJSDOMGlobalObject(Document*, DOMWrapperWorld*);
+    JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext*, DOMWrapperWorld*);
 
 } // namespace WebCore
 
index a04ef89..86ff149 100644 (file)
@@ -53,10 +53,11 @@ JSDOMWindowBase::JSDOMWindowBase(NonNullPassRefPtr<Structure> structure, PassRef
     addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
 }
 
-void JSDOMWindowBase::updateDocument()
+void JSDOMWindowBase::updateDocument(DOMWrapperWorld* world)
 {
     ASSERT(d()->impl->document());
     ExecState* exec = globalExec();
+    EnterDOMWrapperWorld worldEntry(exec, world);
     symbolTablePutWithAttributes(Identifier(exec, "document"), toJS(exec, this, d()->impl->document()), DontDelete | ReadOnly);
 }
 
@@ -79,21 +80,7 @@ String JSDOMWindowBase::crossDomainAccessErrorMessage(const JSGlobalObject* othe
 
 void JSDOMWindowBase::printErrorMessage(const String& message) const
 {
-    if (message.isEmpty())
-        return;
-
-    Frame* frame = impl()->frame();
-    if (!frame)
-        return;
-
-    Settings* settings = frame->settings();
-    if (!settings)
-        return;
-    
-    if (settings->privateBrowsingEnabled())
-        return;
-
-    impl()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
+    printErrorMessageForFrame(impl()->frame(), message);
 }
 
 ExecState* JSDOMWindowBase::globalExec()
@@ -157,13 +144,16 @@ JSDOMWindowShell* JSDOMWindowBase::shell() const
 
 JSGlobalData* JSDOMWindowBase::commonJSGlobalData()
 {
-    static JSGlobalData* globalData;
+    ASSERT(isMainThread());
+
+    static JSGlobalData* globalData = 0;
     if (!globalData) {
         globalData = JSGlobalData::createLeaked().releaseRef();
         globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds
 #ifndef NDEBUG
         globalData->mainThreadOnly = true;
 #endif
+        globalData->clientData = new WebCoreJSClientData(globalData);
     }
 
     return globalData;
@@ -181,21 +171,21 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
     return toJS(exec, domWindow);
 }
 
-JSValue toJS(ExecState*, DOMWindow* domWindow)
+JSValue toJS(ExecState* exec, DOMWindow* domWindow)
 {
     if (!domWindow)
         return jsNull();
     Frame* frame = domWindow->frame();
     if (!frame)
         return jsNull();
-    return frame->script()->windowShell();
+    return frame->script()->windowShell(currentWorld(exec));
 }
 
-JSDOMWindow* toJSDOMWindow(Frame* frame)
+JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld* world)
 {
     if (!frame)
         return 0;
-    return frame->script()->windowShell()->window();
+    return frame->script()->windowShell(world)->window();
 }
 
 JSDOMWindow* toJSDOMWindow(JSValue value)
index 52c3c1d..31e2486 100644 (file)
@@ -32,6 +32,7 @@ namespace WebCore {
     class DOMWindow;
     class Event;
     class Frame;
+    class DOMWrapperWorld;
     class JSDOMWindow;
     class JSDOMWindowShell;
     class JSLocation;
@@ -46,7 +47,7 @@ namespace WebCore {
         JSDOMWindowBase(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<DOMWindow>, JSDOMWindowShell*);
 
     public:
-        void updateDocument();
+        void updateDocument(DOMWrapperWorld*);
 
         DOMWindow* impl() const { return d()->impl.get(); }
         virtual ScriptExecutionContext* scriptExecutionContext() const;
@@ -102,7 +103,7 @@ namespace WebCore {
     JSC::JSValue toJS(JSC::ExecState*, DOMWindow*);
 
     // Returns JSDOMWindow or 0
-    JSDOMWindow* toJSDOMWindow(Frame*);
+    JSDOMWindow* toJSDOMWindow(Frame*, DOMWrapperWorld*);
     JSDOMWindow* toJSDOMWindow(JSC::JSValue);
 
 } // namespace WebCore
index deb92cb..2804b3c 100644 (file)
@@ -771,7 +771,8 @@ static Frame* createWindow(ExecState* exec, Frame* lexicalFrame, Frame* dynamicF
     newFrame->loader()->setOpener(openerFrame);
     newFrame->page()->setOpenedByDOM();
 
-    JSDOMWindow* newWindow = toJSDOMWindow(newFrame);
+    // FIXME: If a window is created from an isolated world, what are the consequences of this? 'dialogArguments' only appears back in the normal world?
+    JSDOMWindow* newWindow = toJSDOMWindow(newFrame, normalWorld(exec->globalData()));
 
     if (dialogArgs)
         newWindow->putDirect(Identifier(exec, "dialogArguments"), dialogArgs);
@@ -831,7 +832,7 @@ JSValue JSDOMWindow::open(ExecState* exec, const ArgList& args)
         if (!shouldAllowNavigation(exec, frame))
             return jsUndefined();
 
-        const JSDOMWindow* targetedWindow = toJSDOMWindow(frame);
+        const JSDOMWindow* targetedWindow = toJSDOMWindow(frame, currentWorld(exec));
         if (!completedURL.isEmpty() && (!protocolIsJavaScript(completedURL) || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) {
             bool userGesture = processingUserGesture(exec);
 
@@ -932,7 +933,7 @@ JSValue JSDOMWindow::showModalDialog(ExecState* exec, const ArgList& args)
     if (!dialogFrame)
         return jsUndefined();
 
-    JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame);
+    JSDOMWindow* dialogWindow = toJSDOMWindow(dialogFrame, currentWorld(exec));
     dialogFrame->page()->chrome()->runModal();
 
     Identifier returnValue(exec, "returnValue");
@@ -975,7 +976,7 @@ JSValue JSDOMWindow::postMessage(ExecState* exec, const ArgList& args)
 
 JSValue JSDOMWindow::setTimeout(ExecState* exec, const ArgList& args)
 {
-    ScheduledAction* action = ScheduledAction::create(exec, args);
+    ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
     if (exec->hadException())
         return jsUndefined();
     int delay = args.at(1).toInt32(exec);
@@ -984,7 +985,7 @@ JSValue JSDOMWindow::setTimeout(ExecState* exec, const ArgList& args)
 
 JSValue JSDOMWindow::setInterval(ExecState* exec, const ArgList& args)
 {
-    ScheduledAction* action = ScheduledAction::create(exec, args);
+    ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
     if (exec->hadException())
         return jsUndefined();
     int delay = args.at(1).toInt32(exec);
@@ -1052,7 +1053,7 @@ JSValue JSDOMWindow::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -1066,7 +1067,7 @@ JSValue JSDOMWindow::removeEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 3c3ff4c..9072f91 100644 (file)
@@ -171,18 +171,18 @@ void* JSDOMWindowShell::operator new(size_t size)
 // Conversion methods
 // ----
 
-JSValue toJS(ExecState*, Frame* frame)
+JSValue toJS(ExecState* exec, Frame* frame)
 {
     if (!frame)
         return jsNull();
-    return frame->script()->windowShell();
+    return frame->script()->windowShell(currentWorld(exec));
 }
 
-JSDOMWindowShell* toJSDOMWindowShell(Frame* frame)
+JSDOMWindowShell* toJSDOMWindowShell(Frame* frame, DOMWrapperWorld* isolatedWorld)
 {
     if (!frame)
         return 0;
-    return frame->script()->windowShell();
+    return frame->script()->windowShell(isolatedWorld);
 }
 
 } // namespace WebCore
index 1bb0938..36cb8d6 100644 (file)
@@ -88,7 +88,7 @@ namespace WebCore {
     };
 
     JSC::JSValue toJS(JSC::ExecState*, Frame*);
-    JSDOMWindowShell* toJSDOMWindowShell(Frame*);
+    JSDOMWindowShell* toJSDOMWindowShell(Frame*, DOMWrapperWorld*);
 
 } // namespace WebCore
 
index 9bff637..7485c1f 100644 (file)
@@ -67,7 +67,7 @@ JSValue JSNotification::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener)), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener)), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -77,7 +77,7 @@ JSValue JSNotification::removeEventListener(ExecState* exec, const ArgList& args
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 4f273fe..1a999a8 100644 (file)
@@ -31,10 +31,11 @@ using namespace JSC;
 
 namespace WebCore {
 
-JSEventListener::JSEventListener(JSObject* function, bool isAttribute)
+JSEventListener::JSEventListener(JSObject* function, bool isAttribute, DOMWrapperWorld* isolatedWorld)
     : EventListener(JSEventListenerType)
     , m_jsFunction(function)
     , m_isAttribute(isAttribute)
+    , m_isolatedWorld(isolatedWorld)
 {
 }
 
@@ -65,7 +66,7 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext
     if (!jsFunction)
         return;
 
-    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext);
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get());
     if (!globalObject)
         return;
 
@@ -86,7 +87,12 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext
 
     ExecState* exec = globalObject->globalExec();
 
-    JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
+    JSValue handleEventFunction;
+    {
+        // Switch worlds, just in case handleEvent is a getter and causes JS execution!
+        EnterDOMWrapperWorld worldEntry(exec, m_isolatedWorld.get());
+        handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent"));
+    }
     CallData callData;
     CallType callType = handleEventFunction.getCallData(callData);
     if (callType == CallTypeNone) {
@@ -108,8 +114,8 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext
 
         globalData->timeoutChecker.start();
         JSValue retval = handleEventFunction
-            ? call(exec, handleEventFunction, callType, callData, jsFunction, args)
-            : call(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args);
+            ? callInWorld(exec, handleEventFunction, callType, callData, jsFunction, args, m_isolatedWorld.get())
+            : callInWorld(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args, m_isolatedWorld.get());
         globalData->timeoutChecker.stop();
 
         globalObject->setCurrentEvent(savedEvent);
@@ -140,7 +146,7 @@ bool JSEventListener::reportError(ScriptExecutionContext* context, const String&
     if (!jsFunction)
         return false;
 
-    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context);
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get());
     ExecState* exec = globalObject->globalExec();
 
     CallData callData;
@@ -160,7 +166,7 @@ bool JSEventListener::reportError(ScriptExecutionContext* context, const String&
     JSValue thisValue = globalObject->toThisObject(exec);
 
     globalData->timeoutChecker.start();
-    JSValue returnValue = call(exec, jsFunction, callType, callData, thisValue, args);
+    JSValue returnValue = callInWorld(exec, jsFunction, callType, callData, thisValue, args, m_isolatedWorld.get());
     globalData->timeoutChecker.stop();
 
     // If an error occurs while handling the script error, it should be bubbled up.
index 285a9c4..bf3af48 100644 (file)
@@ -30,9 +30,9 @@ namespace WebCore {
 
     class JSEventListener : public EventListener {
     public:
-        static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, bool isAttribute)
+        static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, bool isAttribute, DOMWrapperWorld* isolatedWorld)
         {
-            return adoptRef(new JSEventListener(listener, isAttribute));
+            return adoptRef(new JSEventListener(listener, isAttribute, isolatedWorld));
         }
 
         static const JSEventListener* cast(const EventListener* listener)
@@ -59,10 +59,11 @@ namespace WebCore {
         void clearJSFunctionInline();
 
     protected:
-        JSEventListener(JSC::JSObject* function, bool isAttribute);
+        JSEventListener(JSC::JSObject* function, bool isAttribute, DOMWrapperWorld* isolatedWorld);
 
         mutable JSC::JSObject* m_jsFunction;
         bool m_isAttribute;
+        RefPtr<DOMWrapperWorld> m_isolatedWorld;
     };
 
 } // namespace WebCore
index 00dfe12..8f0dfb1 100644 (file)
@@ -49,7 +49,7 @@ JSValue JSEventSource::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -59,7 +59,7 @@ JSValue JSEventSource::removeEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 0421d10..6ea1135 100644 (file)
@@ -128,7 +128,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ
         return toJS(exec, globalObject, worker);
 
     if (DedicatedWorkerContext* workerContext = target->toDedicatedWorkerContext())
-        return toJSDOMGlobalObject(workerContext);
+        return toJSDOMGlobalObject(workerContext, exec);
 #endif
 
 #if ENABLE(SHARED_WORKERS)
@@ -136,7 +136,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ
         return toJS(exec, globalObject, sharedWorker);
 
     if (SharedWorkerContext* workerContext = target->toSharedWorkerContext())
-        return toJSDOMGlobalObject(workerContext);
+        return toJSDOMGlobalObject(workerContext, exec);
 #endif
 
 #if ENABLE(NOTIFICATIONS)
index c113ec7..0a3be1f 100644 (file)
@@ -105,14 +105,14 @@ JSValue JSHTMLDocument::open(ExecState* exec, const ArgList& args)
     if (args.size() > 2) {
         Frame* frame = static_cast<HTMLDocument*>(impl())->frame();
         if (frame) {
-            JSDOMWindowShell* wrapper = toJSDOMWindowShell(frame);
+            JSDOMWindowShell* wrapper = toJSDOMWindowShell(frame, currentWorld(exec));
             if (wrapper) {
                 JSValue function = wrapper->get(exec, Identifier(exec, "open"));
                 CallData callData;
                 CallType callType = function.getCallData(callData);
                 if (callType == CallTypeNone)
                     return throwError(exec, TypeError);
-                return call(exec, function, callType, callData, wrapper, args);
+                return callInWorld(exec, function, callType, callData, wrapper, args, currentWorld(exec));
             }
         }
         return jsUndefined();
index 05972e6..68769d6 100644 (file)
@@ -47,14 +47,14 @@ bool JSHTMLFrameSetElement::canGetItemsForName(ExecState*, HTMLFrameSetElement*
     return frame && frame->hasTagName(frameTag);
 }
 
-JSValue JSHTMLFrameSetElement::nameGetter(ExecState*, const Identifier& propertyName, const PropertySlot& slot)
+JSValue JSHTMLFrameSetElement::nameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
 {
     JSHTMLElement* thisObj = static_cast<JSHTMLElement*>(asObject(slot.slotBase()));
     HTMLElement* element = static_cast<HTMLElement*>(thisObj->impl());
 
     Node* frame = element->children()->namedItem(propertyName);
     if (Document* doc = static_cast<HTMLFrameElement*>(frame)->contentDocument()) {
-        if (JSDOMWindowShell* window = toJSDOMWindowShell(doc->frame()))
+        if (JSDOMWindowShell* window = toJSDOMWindowShell(doc->frame(), currentWorld(exec)))
             return window;
     }
 
index 391cacc..439f532 100644 (file)
@@ -131,7 +131,8 @@ JSValue JSInspectorBackend::databaseForId(ExecState* exec, const ArgList& args)
     Database* database = impl()->databaseForId(args.at(0).toInt32(exec));
     if (!database)
         return jsUndefined();
-    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame());
+    // Could use currentWorld(exec) ... but which exec!  The following mixed use of exec & inspectedWindow->globalExec() scares me!
+    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame(), debuggerWorld());
     return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), toJS(exec, database));
 }
 #endif
@@ -141,7 +142,7 @@ JSValue JSInspectorBackend::inspectedWindow(ExecState*, const ArgList&)
     InspectorController* ic = impl()->inspectorController();
     if (!ic)
         return jsUndefined();
-    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame());
+    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame(), debuggerWorld());
     return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow);
 }
 
@@ -266,7 +267,7 @@ JSValue JSInspectorBackend::nodeForId(ExecState* exec, const ArgList& args)
         return jsUndefined();
 
     JSLock lock(SilenceAssertionsOnly);
-    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame());
+    JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame(), debuggerWorld());
     return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), toJS(exec, deprecatedGlobalObjectForPrototype(inspectedWindow->globalExec()), node));
 }
 
index 0d6cb57..6d75f4f 100644 (file)
@@ -35,8 +35,8 @@ namespace WebCore {
 static WTF::RefCountedLeakCounter eventListenerCounter("JSLazyEventListener");
 #endif
 
-JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber)
-    : JSEventListener(0, true)
+JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld)
+    : JSEventListener(0, true, isolatedWorld)
     , m_functionName(functionName)
     , m_eventParameterName(eventParameterName)
     , m_code(code)
@@ -92,7 +92,7 @@ void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) co
     if (!scriptController->isEnabled())
         return;
 
-    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext);
+    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, m_isolatedWorld.get());
     if (!globalObject)
         return;
 
index e3137b8..ba26ef6 100644 (file)
@@ -29,14 +29,14 @@ namespace WebCore {
 
     class JSLazyEventListener : public JSEventListener {
     public:
-        static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber)
+        static PassRefPtr<JSLazyEventListener> create(const String& functionName, const String& eventParameterName, const String& code, Node* node, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld)
         {
-            return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, node, sourceURL, lineNumber));
+            return adoptRef(new JSLazyEventListener(functionName, eventParameterName, code, node, sourceURL, lineNumber, isolatedWorld));
         }
         virtual ~JSLazyEventListener();
 
     private:
-        JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node*, const String& sourceURL, int lineNumber);
+        JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, Node*, const String& sourceURL, int lineNumber, DOMWrapperWorld* isolatedWorld);
 
         virtual JSC::JSObject* jsFunction(ScriptExecutionContext*) const;
         virtual bool wasCreatedFromMarkup() const { return true; }
index 574e28a..d28d494 100644 (file)
@@ -36,17 +36,11 @@ void JSMessageChannel::markChildren(MarkStack& markStack)
 {
     Base::markChildren(markStack);
 
-    if (MessagePort* port = m_impl->port1()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), port);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (MessagePort* port = m_impl->port1())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), port);
 
-    if (MessagePort* port = m_impl->port2()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), port);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (MessagePort* port = m_impl->port2())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), port);
 }
 
 } // namespace WebCore
index a0a92be..2c09620 100644 (file)
@@ -46,11 +46,8 @@ void JSMessagePort::markChildren(MarkStack& markStack)
     Base::markChildren(markStack);
 
     // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext().
-    if (MessagePort* entangledPort = m_impl->locallyEntangledPort()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), entangledPort);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (MessagePort* entangledPort = m_impl->locallyEntangledPort())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), entangledPort);
 
     m_impl->markEventListeners(markStack);
 }
@@ -61,7 +58,7 @@ JSValue JSMessagePort::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -71,7 +68,7 @@ JSValue JSMessagePort::removeEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 4e7d622..2a4aa80 100644 (file)
@@ -114,7 +114,7 @@ JSValue JSNode::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -124,7 +124,7 @@ JSValue JSNode::removeEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -143,10 +143,8 @@ void JSNode::markChildren(MarkStack& markStack)
     // the document, we need to mark the document, but we don't need to explicitly
     // mark any other nodes.
     if (node->inDocument()) {
-        if (Document* doc = node->ownerDocument()) {
-            if (DOMObject* docWrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), doc))
-                markStack.append(docWrapper);
-        }
+        if (Document* doc = node->ownerDocument())
+            markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), doc);
         return;
     }
 
index a199417..54dc020 100644 (file)
@@ -66,7 +66,7 @@ short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode)
     if (exec->hadException())
         return NodeFilter::FILTER_REJECT;
 
-    JSValue result = call(exec, m_filter, callType, callData, m_filter, args);
+    JSValue result = callInWorld(exec, m_filter, callType, callData, m_filter, args, currentWorld(exec));
     if (exec->hadException())
         return NodeFilter::FILTER_REJECT;
 
index a0551a1..2ab2c00 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "JSQuarantinedObjectWrapper.h"
 
+#include "JSDOMBinding.h"
+
 #include <runtime/JSGlobalObject.h>
 
 using namespace JSC;
@@ -243,7 +245,8 @@ JSObject* JSQuarantinedObjectWrapper::construct(ExecState* exec, JSObject* const
     ConstructType unwrappedConstructType = wrapper->m_unwrappedObject->getConstructData(unwrappedConstructData);
     ASSERT(unwrappedConstructType != ConstructTypeNone);
 
-    JSValue unwrappedResult = JSC::construct(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedConstructType, unwrappedConstructData, preparedArgs);
+    // FIXME: Quarantined objects are all in the debuggerWorld(), for now. Instead, we should remove the quarantined objects, & replace them with an isolated world?
+    JSValue unwrappedResult = constructInWorld(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedConstructType, unwrappedConstructData, preparedArgs, debuggerWorld());
 
     JSValue resultValue = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
     ASSERT(resultValue.isObject());
@@ -293,7 +296,8 @@ JSValue JSQuarantinedObjectWrapper::call(ExecState* exec, JSObject* function, JS
     CallType unwrappedCallType = wrapper->m_unwrappedObject->getCallData(unwrappedCallData);
     ASSERT(unwrappedCallType != CallTypeNone);
 
-    JSValue unwrappedResult = JSC::call(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedCallType, unwrappedCallData, preparedThisValue, preparedArgs);
+    // FIXME: Quarantined objects are all in the debuggerWorld(), for now. Instead, we should remove the quarantined objects, & replace them with an isolated world?
+    JSValue unwrappedResult = callInWorld(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedCallType, unwrappedCallData, preparedThisValue, preparedArgs, debuggerWorld());
 
     JSValue result = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
 
index fd3742d..ba1cf22 100644 (file)
@@ -54,7 +54,7 @@ JSValue JSSVGElementInstance::addEventListener(ExecState* exec, const ArgList& a
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -64,7 +64,7 @@ JSValue JSSVGElementInstance::removeEventListener(ExecState* exec, const ArgList
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index f21f50c..4617087 100644 (file)
@@ -45,11 +45,8 @@ void JSSharedWorker::markChildren(MarkStack& markStack)
 {
     Base::markChildren(markStack);
 
-    if (MessagePort* port = impl()->port()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), port);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (MessagePort* port = impl()->port())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), port);
 }
 
 } // namespace WebCore
index bea3563..33c3fcd 100644 (file)
@@ -66,7 +66,7 @@ JSValue JSWebSocket::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -76,7 +76,7 @@ JSValue JSWebSocket::removeEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index e1c8a8c..490d9b1 100644 (file)
@@ -122,7 +122,7 @@ JSValue JSWorkerContext::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -132,13 +132,13 @@ JSValue JSWorkerContext::removeEventListener(ExecState* exec, const ArgList& arg
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
 JSValue JSWorkerContext::setTimeout(ExecState* exec, const ArgList& args)
 {
-    ScheduledAction* action = ScheduledAction::create(exec, args);
+    ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
     if (exec->hadException())
         return jsUndefined();
     int delay = args.at(1).toInt32(exec);
@@ -147,7 +147,7 @@ JSValue JSWorkerContext::setTimeout(ExecState* exec, const ArgList& args)
 
 JSValue JSWorkerContext::setInterval(ExecState* exec, const ArgList& args)
 {
-    ScheduledAction* action = ScheduledAction::create(exec, args);
+    ScheduledAction* action = ScheduledAction::create(exec, args, currentWorld(exec));
     if (exec->hadException())
         return jsUndefined();
     int delay = args.at(1).toInt32(exec);
index 7d3f8af..7ee2720 100644 (file)
@@ -53,11 +53,8 @@ void JSXMLHttpRequest::markChildren(MarkStack& markStack)
 {
     Base::markChildren(markStack);
 
-    if (XMLHttpRequestUpload* upload = m_impl->optionalUpload()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), upload);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (XMLHttpRequestUpload* upload = m_impl->optionalUpload())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), upload);
 
     m_impl->markEventListeners(markStack);
 }
@@ -156,7 +153,7 @@ JSValue JSXMLHttpRequest::addEventListener(ExecState* exec, const ArgList& args)
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -166,7 +163,7 @@ JSValue JSXMLHttpRequest::removeEventListener(ExecState* exec, const ArgList& ar
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 275d1fb..fa7cfec 100644 (file)
@@ -45,11 +45,8 @@ void JSXMLHttpRequestUpload::markChildren(MarkStack& markStack)
 {
     Base::markChildren(markStack);
 
-    if (XMLHttpRequest* xmlHttpRequest = m_impl->associatedXMLHttpRequest()) {
-        DOMObject* wrapper = getCachedDOMObjectWrapper(*Heap::heap(this)->globalData(), xmlHttpRequest);
-        if (wrapper)
-            markStack.append(wrapper);
-    }
+    if (XMLHttpRequest* xmlHttpRequest = m_impl->associatedXMLHttpRequest())
+        markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), xmlHttpRequest);
 
     m_impl->markEventListeners(markStack);
 }
@@ -60,7 +57,7 @@ JSValue JSXMLHttpRequestUpload::addEventListener(ExecState* exec, const ArgList&
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false), args.at(2).toBoolean(exec));
+    impl()->addEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
@@ -70,7 +67,7 @@ JSValue JSXMLHttpRequestUpload::removeEventListener(ExecState* exec, const ArgLi
     if (!listener.isObject())
         return jsUndefined();
 
-    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false).get(), args.at(2).toBoolean(exec));
+    impl()->removeEventListener(args.at(0).toString(exec), JSEventListener::create(asObject(listener), false, currentWorld(exec)).get(), args.at(2).toBoolean(exec));
     return jsUndefined();
 }
 
index 93155e1..9a21b6b 100644 (file)
@@ -47,7 +47,7 @@ using namespace JSC;
 
 namespace WebCore {
 
-ScheduledAction* ScheduledAction::create(ExecState* exec, const ArgList& args)
+ScheduledAction* ScheduledAction::create(ExecState* exec, const ArgList& args, DOMWrapperWorld* isolatedWorld)
 {
     JSValue v = args.at(0);
     CallData callData;
@@ -55,15 +55,16 @@ ScheduledAction* ScheduledAction::create(ExecState* exec, const ArgList& args)
         UString string = v.toString(exec);
         if (exec->hadException())
             return 0;
-        return new ScheduledAction(string);
+        return new ScheduledAction(string, isolatedWorld);
     }
     ArgList argsTail;
     args.getSlice(2, argsTail);
-    return new ScheduledAction(v, argsTail);
+    return new ScheduledAction(v, argsTail, isolatedWorld);
 }
 
-ScheduledAction::ScheduledAction(JSValue function, const ArgList& args)
+ScheduledAction::ScheduledAction(JSValue function, const ArgList& args, DOMWrapperWorld* isolatedWorld)
     : m_function(function)
+    , m_isolatedWorld(isolatedWorld)
 {
     ArgList::const_iterator end = args.end();
     for (ArgList::const_iterator it = args.begin(); it != end; ++it)
@@ -102,7 +103,7 @@ void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSV
         args.append(m_args[i]);
 
     globalObject->globalData()->timeoutChecker.start();
-    call(exec, m_function, callType, callData, thisValue, args);
+    callInWorld(exec, m_function, callType, callData, thisValue, args, m_isolatedWorld.get());
     globalObject->globalData()->timeoutChecker.stop();
 
     if (exec->hadException())
@@ -111,7 +112,7 @@ void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSV
 
 void ScheduledAction::execute(Document* document)
 {
-    JSDOMWindow* window = toJSDOMWindow(document->frame());
+    JSDOMWindow* window = toJSDOMWindow(document->frame(), m_isolatedWorld.get());
     if (!window)
         return;
 
@@ -125,7 +126,7 @@ void ScheduledAction::execute(Document* document)
         executeFunctionInContext(window, window->shell());
         Document::updateStyleForAllDocuments();
     } else
-        frame->script()->executeScript(m_code);
+        frame->script()->executeScriptInIsolatedWorld(m_isolatedWorld.get(), m_code);
 
     frame->script()->setProcessingTimerCallback(false);
 }
index 2cd36ed..4ea727d 100644 (file)
@@ -21,6 +21,7 @@
 #define ScheduledAction_h
 
 #include "PlatformString.h"
+#include <JSDOMBinding.h>
 #include <runtime/JSCell.h>
 #include <runtime/Protect.h>
 #include <wtf/Vector.h>
@@ -41,14 +42,15 @@ namespace WebCore {
     */
     class ScheduledAction {
     public:
-        static ScheduledAction* create(JSC::ExecState*, const JSC::ArgList&);
+        static ScheduledAction* create(JSC::ExecState*, const JSC::ArgList&, DOMWrapperWorld* isolatedWorld);
 
         void execute(ScriptExecutionContext*);
 
     private:
-        ScheduledAction(JSC::JSValue function, const JSC::ArgList&);
-        ScheduledAction(const String& code)
+        ScheduledAction(JSC::JSValue function, const JSC::ArgList&, DOMWrapperWorld* isolatedWorld);
+        ScheduledAction(const String& code, DOMWrapperWorld* isolatedWorld)
             : m_code(code)
+            , m_isolatedWorld(isolatedWorld)
         {
         }
 
@@ -61,6 +63,7 @@ namespace WebCore {
         JSC::ProtectedJSValue m_function;
         Vector<JSC::ProtectedJSValue> m_args;
         String m_code;
+        RefPtr<DOMWrapperWorld> m_isolatedWorld;
     };
 
 } // namespace WebCore
index 77b8ca4..e01324e 100644 (file)
@@ -48,8 +48,9 @@ ScriptCachedFrameData::ScriptCachedFrameData(Frame* frame)
     JSLock lock(SilenceAssertionsOnly);
 
     ScriptController* scriptController = frame->script();
-    if (scriptController->haveWindowShell()) {
-        m_window = scriptController->windowShell()->window();
+    // FIXME: explicitly save and restore isolated worlds' global objects when using the back/forward cache. <rdar://problem/7328111>
+    if (JSDOMWindowShell* windowShell = scriptController->existingWindowShell(mainThreadNormalWorld())) {
+        m_window = windowShell->window();
         scriptController->attachDebugger(0);
     }
 }
@@ -70,11 +71,11 @@ void ScriptCachedFrameData::restore(Frame* frame)
     JSLock lock(SilenceAssertionsOnly);
 
     ScriptController* scriptController = frame->script();
-    if (scriptController->haveWindowShell()) {
-        JSDOMWindowShell* windowShell = scriptController->windowShell();
-        if (m_window) {
+    // FIXME: explicitly save and restore isolated worlds' global objects when using the back/forward cache. <rdar://problem/7328111>
+    if (JSDOMWindowShell* windowShell = scriptController->existingWindowShell(mainThreadNormalWorld())) {
+        if (m_window)
             windowShell->setWindow(m_window.get());
-        else {
+        else {
             windowShell->setWindow(frame->domWindow());
             scriptController->attachDebugger(page->debugger());
             windowShell->window()->setProfileGroup(page->group().identifier());
index 54acc90..5d65c11 100644 (file)
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "ScriptController.h"
 
+#include "CString.h"
 #include "Event.h"
 #include "EventNames.h"
 #include "Frame.h"
@@ -71,8 +72,11 @@ ScriptController::ScriptController(Frame* frame)
 
 ScriptController::~ScriptController()
 {
-    if (m_windowShell) {
-        m_windowShell = 0;
+    if (!m_windowShells.isEmpty()) {
+        for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter)
+            iter->first->forgetScriptController(this);
+
+        m_windowShells.clear();
     
         // It's likely that releasing the global object has created a lot of garbage.
         gcController().garbageCollectSoon();
@@ -81,7 +85,7 @@ ScriptController::~ScriptController()
     disconnectPlatformScriptObjects();
 }
 
-ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) 
+ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld* world)
 {
     const SourceCode& jsSourceCode = sourceCode.jsSourceCode();
     String sourceURL = jsSourceCode.provider()->url();
@@ -94,12 +98,12 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)
     // evaluate code. Returns the JS return value or 0
     // if there was none, an error occured or the type couldn't be converted.
 
-    initScriptIfNeeded();
     // inlineCode is true for <a href="javascript:doSomething()">
     // and false for <script>doSomething()</script>. Check if it has the
     // expected value in all cases.
     // See smart window.open policy for where this is used.
-    ExecState* exec = m_windowShell->window()->globalExec();
+    JSDOMWindowShell* shell = windowShell(world);
+    ExecState* exec = shell->window()->globalExec();
     const String* savedSourceURL = m_sourceURL;
     m_sourceURL = &sourceURL;
 
@@ -107,9 +111,9 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)
 
     RefPtr<Frame> protect = m_frame;
 
-    m_windowShell->window()->globalData()->timeoutChecker.start();
-    Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, m_windowShell);
-    m_windowShell->window()->globalData()->timeoutChecker.stop();
+    exec->globalData().timeoutChecker.start();
+    Completion comp = WebCore::evaluateInWorld(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, shell, world);
+    exec->globalData().timeoutChecker.stop();
 
     // Evaluating the JavaScript could cause the frame to be deallocated
     // so we start the keep alive timer here.
@@ -127,52 +131,108 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)
     return JSValue();
 }
 
-void ScriptController::evaluateInIsolatedWorld(unsigned /* worldID */, const Vector<ScriptSourceCode>& sourceCode) 
+ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) 
+{
+    return evaluateInWorld(sourceCode, mainThreadNormalWorld());
+}
+
+// An DOMWrapperWorld other than the thread's normal world.
+class IsolatedWorld : public DOMWrapperWorld {
+public:
+    IsolatedWorld(JSGlobalData* globalData)
+        : DOMWrapperWorld(globalData)
+    {
+        JSGlobalData::ClientData* clientData = globalData->clientData;
+        ASSERT(clientData);
+        static_cast<WebCoreJSClientData*>(clientData)->rememberWorld(this);
+    }
+
+    static PassRefPtr<IsolatedWorld> create(JSGlobalData* globalData) { return adoptRef(new IsolatedWorld(globalData)); }
+};
+
+static PassRefPtr<IsolatedWorld> findWorld(unsigned worldID)
+{
+    if (!worldID)
+        return IsolatedWorld::create(JSDOMWindow::commonJSGlobalData());
+
+    typedef HashMap<unsigned, RefPtr<IsolatedWorld> > WorldMap;
+    DEFINE_STATIC_LOCAL(WorldMap, isolatedWorlds, ());
+
+    WorldMap::iterator iter = isolatedWorlds.find(worldID);
+    if (iter != isolatedWorlds.end())
+        return iter->second;
+
+    RefPtr<IsolatedWorld> newWorld = IsolatedWorld::create(JSDOMWindow::commonJSGlobalData());
+    isolatedWorlds.add(worldID, newWorld);
+    return newWorld;
+}
+
+ScriptValue ScriptController::evaluateInIsolatedWorld(unsigned worldID, const ScriptSourceCode& sourceCode) 
+{
+    RefPtr<DOMWrapperWorld> world = findWorld(worldID);
+    return evaluateInWorld(sourceCode, world.get());
+}
+
+void ScriptController::evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>& sourceCode) 
 {
-    // FIXME: Actually support isolated worlds!
+    RefPtr<DOMWrapperWorld> world = findWorld(worldID);
+
     unsigned size = sourceCode.size();
     for (unsigned i = 0; i < size; ++i)
-        evaluate(sourceCode[i]);
+        evaluateInWorld(sourceCode[i], world.get());
 }
 
 void ScriptController::clearWindowShell()
 {
-    if (!m_windowShell)
+    if (m_windowShells.isEmpty())
         return;
 
     JSLock lock(SilenceAssertionsOnly);
 
     // Clear the debugger from the current window before setting the new window.
+    DOMWrapperWorld* debugWorld = debuggerWorld();
     attachDebugger(0);
 
-    m_windowShell->window()->willRemoveFromWindowShell();
-    m_windowShell->setWindow(m_frame->domWindow());
+    for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) {
+        DOMWrapperWorld* world = iter->first;
+        JSDOMWindowShell* windowShell = iter->second;
+        windowShell->window()->willRemoveFromWindowShell();
+        windowShell->setWindow(m_frame->domWindow());
 
-    if (Page* page = m_frame->page()) {
-        attachDebugger(page->debugger());
-        m_windowShell->window()->setProfileGroup(page->group().identifier());
+        if (Page* page = m_frame->page()) {
+            if (world == debugWorld)
+                attachDebugger(page->debugger());
+            windowShell->window()->setProfileGroup(page->group().identifier());
+        }
     }
 
     // There is likely to be a lot of garbage now.
     gcController().garbageCollectSoon();
 }
 
-void ScriptController::initScript()
+JSDOMWindowShell* ScriptController::initScript(DOMWrapperWorld* world)
 {
-    if (m_windowShell)
-        return;
+    ASSERT(!m_windowShells.contains(world));
 
     JSLock lock(SilenceAssertionsOnly);
 
-    m_windowShell = new JSDOMWindowShell(m_frame->domWindow());
-    m_windowShell->window()->updateDocument();
+    JSDOMWindowShell* windowShell = new JSDOMWindowShell(m_frame->domWindow());
+    m_windowShells.add(world, windowShell);
+    world->rememberScriptController(this);
+    windowShell->window()->updateDocument(world);
 
     if (Page* page = m_frame->page()) {
-        attachDebugger(page->debugger());
-        m_windowShell->window()->setProfileGroup(page->group().identifier());
+        if (world == debuggerWorld())
+            attachDebugger(page->debugger());
+        windowShell->window()->setProfileGroup(page->group().identifier());
+    }
+
+    {
+        EnterDOMWrapperWorld worldEntry(*JSDOMWindow::commonJSGlobalData(), world);
+        m_frame->loader()->dispatchWindowObjectAvailable();
     }
 
-    m_frame->loader()->dispatchWindowObjectAvailable();
+    return windowShell;
 }
 
 bool ScriptController::processingUserGesture() const
@@ -182,10 +242,11 @@ bool ScriptController::processingUserGesture() const
 
 bool ScriptController::processingUserGestureEvent() const
 {
-    if (!m_windowShell)
+    JSDOMWindowShell* shell = existingWindowShell(mainThreadNormalWorld());
+    if (!shell)
         return false;
 
-    if (Event* event = m_windowShell->window()->currentEvent()) {
+    if (Event* event = shell->window()->currentEvent()) {
         if (event->createdByDOM())
             return false;
 
@@ -243,13 +304,16 @@ bool ScriptController::isEnabled()
 
 void ScriptController::attachDebugger(JSC::Debugger* debugger)
 {
-    if (!m_windowShell)
+    // FIXME: Should be able to debug isolated worlds.
+    JSDOMWindowShell* shell = existingWindowShell(debuggerWorld());
+    if (!shell)
         return;
 
+    JSDOMWindow* globalObject = shell->window();
     if (debugger)
-        debugger->attach(m_windowShell->window());
-    else if (JSC::Debugger* currentDebugger = m_windowShell->window()->debugger())
-        currentDebugger->detach(m_windowShell->window());
+        debugger->attach(globalObject);
+    else if (JSC::Debugger* currentDebugger = globalObject->debugger())
+        currentDebugger->detach(globalObject);
 }
 
 void ScriptController::updateDocument()
@@ -258,8 +322,8 @@ void ScriptController::updateDocument()
         return;
 
     JSLock lock(SilenceAssertionsOnly);
-    if (m_windowShell)
-        m_windowShell->window()->updateDocument();
+    for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter)
+        iter->second->window()->updateDocument(iter->first);
 }
 
 void ScriptController::updateSecurityOrigin()
@@ -274,7 +338,7 @@ Bindings::RootObject* ScriptController::bindingRootObject()
 
     if (!m_bindingRootObject) {
         JSLock lock(SilenceAssertionsOnly);
-        m_bindingRootObject = Bindings::RootObject::create(0, globalObject());
+        m_bindingRootObject = Bindings::RootObject::create(0, globalObject(pluginWorld()));
     }
     return m_bindingRootObject.get();
 }
@@ -285,7 +349,7 @@ PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* native
     if (it != m_rootObjects.end())
         return it->second;
 
-    RefPtr<Bindings::RootObject> rootObject = Bindings::RootObject::create(nativeHandle, globalObject());
+    RefPtr<Bindings::RootObject> rootObject = Bindings::RootObject::create(nativeHandle, globalObject(pluginWorld()));
 
     m_rootObjects.set(nativeHandle, rootObject);
     return rootObject.release();
@@ -300,7 +364,7 @@ NPObject* ScriptController::windowScriptNPObject()
             // JavaScript is enabled, so there is a JavaScript window object.
             // Return an NPObject bound to the window object.
             JSC::JSLock lock(SilenceAssertionsOnly);
-            JSObject* win = windowShell()->window();
+            JSObject* win = windowShell(pluginWorld())->window();
             ASSERT(win);
             Bindings::RootObject* root = bindingRootObject();
             m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root);
@@ -334,8 +398,9 @@ JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin)
 
     // Create a JSObject bound to this element
     JSLock lock(SilenceAssertionsOnly);
-    ExecState* exec = globalObject()->globalExec();
-    JSValue jsElementValue = toJS(exec, globalObject(), plugin);
+    JSDOMWindow* globalObj = globalObject(pluginWorld());
+    // FIXME: is normal okay? - used for NP plugins?
+    JSValue jsElementValue = toJS(globalObj->globalExec(), globalObj, plugin);
     if (!jsElementValue || !jsElementValue.isObject())
         return 0;
     
index bd4b65e..9bab6df 100644 (file)
@@ -63,31 +63,43 @@ class XSSAuditor;
 typedef HashMap<void*, RefPtr<JSC::Bindings::RootObject> > RootObjectMap;
 
 class ScriptController {
+    typedef WTF::HashMap<DOMWrapperWorld*, JSC::ProtectedPtr<JSDOMWindowShell> > ShellMap;
+
 public:
     ScriptController(Frame*);
     ~ScriptController();
 
-    bool haveWindowShell() const { return m_windowShell; }
-    JSDOMWindowShell* windowShell()
+    JSDOMWindowShell* windowShell(DOMWrapperWorld* world)
     {
-        initScriptIfNeeded();
-        return m_windowShell;
+        ShellMap::iterator iter = m_windowShells.find(world);
+        return (iter != m_windowShells.end()) ? iter->second.get() : initScript(world);
     }
-
-    JSDOMWindow* globalObject()
+    JSDOMWindowShell* existingWindowShell(DOMWrapperWorld* world) const
+    {
+        ShellMap::const_iterator iter = m_windowShells.find(world);
+        return (iter != m_windowShells.end()) ? iter->second.get() : 0;
+    }
+    JSDOMWindow* globalObject(DOMWrapperWorld* world)
     {
-        initScriptIfNeeded();
-        return m_windowShell->window();
+        return windowShell(world)->window();
+    }
+    void forgetWorld(DOMWrapperWorld* world)
+    {
+        m_windowShells.remove(world);
     }
 
     ScriptValue executeScript(const ScriptSourceCode&);
     ScriptValue executeScript(const String& script, bool forceUserGesture = false);
+    ScriptValue executeScriptInIsolatedWorld(unsigned worldID, const String& script, bool forceUserGesture = false);
+    ScriptValue executeScriptInIsolatedWorld(DOMWrapperWorld* world, const String& script, bool forceUserGesture = false);
 
     // Returns true if argument is a JavaScript URL.
     bool executeIfJavaScriptURL(const KURL&, bool userGesture = false, bool replaceDocument = true);
 
     ScriptValue evaluate(const ScriptSourceCode&);
-    void evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>&);
+    ScriptValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld*);
+    ScriptValue evaluateInIsolatedWorld(unsigned /*worldID*/, const ScriptSourceCode&);
+    void evaluateInIsolatedWorld(unsigned /*worldID*/, const Vector<ScriptSourceCode>&);
 
     void setEventHandlerLineNumber(int lineno) { m_handlerLineNumber = lineno; }
     int eventHandlerLineNumber() { return m_handlerLineNumber; }
@@ -144,19 +156,14 @@ public:
     XSSAuditor* xssAuditor() { return m_XSSAuditor.get(); }
 
 private:
-    void initScriptIfNeeded()
-    {
-        if (!m_windowShell)
-            initScript();
-    }
-    void initScript();
+    JSDOMWindowShell* initScript(DOMWrapperWorld* world);
 
     void disconnectPlatformScriptObjects();
 
     bool processingUserGestureEvent() const;
     bool isJavaScriptAnchorNavigation() const;
 
-    JSC::ProtectedPtr<JSDOMWindowShell> m_windowShell;
+    ShellMap m_windowShells;
     Frame* m_frame;
     int m_handlerLineNumber;
     const String* m_sourceURL;
index e6a654f..21ec0f2 100644 (file)
@@ -114,7 +114,7 @@ WebScriptObject* ScriptController::windowScriptObject()
     if (!m_windowScriptObject) {
         JSC::JSLock lock(JSC::SilenceAssertionsOnly);
         JSC::Bindings::RootObject* root = bindingRootObject();
-        m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(windowShell()) originRootObject:root rootObject:root];
+        m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(windowShell(pluginWorld())) originRootObject:root rootObject:root];
     }
 
     ASSERT([m_windowScriptObject.get() isKindOfClass:[DOMAbstractView class]]);
index 0b0047b..8399c7a 100644 (file)
@@ -71,7 +71,7 @@ PassRefPtr<JSLazyEventListener> createAttributeEventListener(Node* node, Attribu
         sourceURL = node->document()->url().string();
     }
 
-    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber);
+    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(node->isSVGElement()), attr->value(), node, sourceURL, lineNumber, mainThreadNormalWorld());
 }
 
 PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame* frame, Attribute* attr)
@@ -93,7 +93,7 @@ PassRefPtr<JSLazyEventListener> createAttributeEventListener(Frame* frame, Attri
 
     lineNumber = scriptController->eventHandlerLineNumber();
     sourceURL = frame->document()->url().string();
-    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), 0, sourceURL, lineNumber);
+    return JSLazyEventListener::create(attr->localName().string(), eventParameterName(frame->document()->isSVGDocument()), attr->value(), 0, sourceURL, lineNumber, mainThreadNormalWorld());
 }
 
 String getEventListenerHandlerBody(ScriptExecutionContext* context, ScriptState* scriptState, EventListener* eventListener)
index 46e80ac..91b2a57 100644 (file)
@@ -123,7 +123,8 @@ ScriptValue ScriptFunctionCall::call(bool& hadException, bool reportExceptions)
     if (callType == CallTypeNone)
         return ScriptValue();
 
-    JSValue result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments);
+    // FIXME: Should this function take a worldID? - only used by inspector?
+    JSValue result = callInWorld(m_exec, function, callType, callData, thisObject, m_arguments, debuggerWorld());
     if (m_exec->hadException()) {
         if (reportExceptions)
             reportException(m_exec, m_exec->exception());
@@ -161,7 +162,8 @@ ScriptObject ScriptFunctionCall::construct(bool& hadException, bool reportExcept
     if (constructType == ConstructTypeNone)
         return ScriptObject();
 
-    JSValue result = JSC::construct(m_exec, constructor, constructType, constructData, m_arguments);
+    // FIXME: Currently this method constructs objects in debuggerWorld().  We could use the current world, or pass a worldID to this function?
+    JSValue result = constructInWorld(m_exec, constructor, constructType, constructData, m_arguments, debuggerWorld());
     if (m_exec->hadException()) {
         if (reportExceptions)
             reportException(m_exec, m_exec->exception());
index b48556e..313530f 100644 (file)
@@ -72,7 +72,7 @@ bool getQuarantinedScriptObject(Database* database, ScriptObject& quarantinedObj
     if (!frame)
         return false;
 
-    JSDOMGlobalObject* globalObject = toJSDOMWindow(frame);
+    JSDOMGlobalObject* globalObject = toJSDOMWindow(frame, debuggerWorld());
     ExecState* exec = globalObject->globalExec();
 
     JSLock lock(SilenceAssertionsOnly);
@@ -89,7 +89,7 @@ bool getQuarantinedScriptObject(Storage* storage, ScriptObject& quarantinedObjec
     Frame* frame = storage->frame();
     ASSERT(frame);
 
-    JSDOMGlobalObject* globalObject = toJSDOMWindow(frame);
+    JSDOMGlobalObject* globalObject = toJSDOMWindow(frame, debuggerWorld());
     ExecState* exec = globalObject->globalExec();
 
     JSLock lock(SilenceAssertionsOnly);
@@ -116,7 +116,7 @@ bool getQuarantinedScriptObject(DOMWindow* domWindow, ScriptObject& quarantinedO
 {
     ASSERT(domWindow);
 
-    JSDOMWindow* window = toJSDOMWindow(domWindow->frame());
+    JSDOMWindow* window = toJSDOMWindow(domWindow->frame(), debuggerWorld());
     ExecState* exec = window->globalExec();
 
     JSLock lock(SilenceAssertionsOnly);
index 8bfa33d..60ba2a0 100644 (file)
@@ -32,6 +32,7 @@
 #include "ScriptState.h"
 
 #include "Frame.h"
+#include "JSDOMWindowBase.h"
 #include "Node.h"
 #include "Page.h"
 
@@ -49,12 +50,12 @@ ScriptState* scriptStateFromNode(Node* node)
         return 0;
     if (!frame->script()->isEnabled())
         return 0;
-    return frame->script()->globalObject()->globalExec();
+    return frame->script()->globalObject(mainThreadCurrentWorld())->globalExec();
 }
 
 ScriptState* scriptStateFromPage(Page* page)
 {
-    return page->mainFrame()->script()->globalObject()->globalExec();
+    return page->mainFrame()->script()->globalObject(mainThreadCurrentWorld())->globalExec();
 }
 
 }
index fa5c4a8..279234e 100644 (file)
@@ -35,6 +35,7 @@
 #include "JSDOMBinding.h"
 
 namespace WebCore {
+    class DOMWrapperWorld;
     class Node;
     class Page;
 
index 3590dad..b66b0e8 100644 (file)
@@ -52,6 +52,7 @@ WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
     , m_workerContext(workerContext)
     , m_executionForbidden(false)
 {
+    m_globalData->clientData = new WebCoreJSClientData(m_globalData.get());
 }
 
 WorkerScriptController::~WorkerScriptController()
@@ -122,7 +123,7 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode,
 
     ExecState* exec = m_workerContextWrapper->globalExec();
     m_workerContextWrapper->globalData()->timeoutChecker.start();
-    Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper);
+    Completion comp = evaluateInWorld(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper, currentWorld(exec));
     m_workerContextWrapper->globalData()->timeoutChecker.stop();
 
     if (comp.complType() == Normal || comp.complType() == ReturnValue)
index bb33f60..c820cd9 100644 (file)
@@ -62,6 +62,9 @@ namespace WebCore {
         void setException(ScriptValue);
 
         void forbidExecution();
+
+        JSC::JSGlobalData* globalData() { return m_globalData.get(); }
+
     private:
         void initScriptIfNeeded()
         {
index 993a3ad..590d653 100644 (file)
@@ -112,8 +112,8 @@ void removeDOMWrapper(DOMObjectInternal* impl)
     if (!frame)
         return;
 
-    // The global object which should own this node.
-    WebCore::JSDOMGlobalObject* globalObject = frame->script()->globalObject();
+    // The global object which should own this node - FIXME: does this need to be isolated-world aware?
+    WebCore::JSDOMGlobalObject* globalObject = frame->script()->globalObject(WebCore::mainThreadNormalWorld());
     JSC::ExecState *exec = globalObject->globalExec();
 
     // Get (or create) a cached JS object for the DOM node.
index 1086204..6d86001 100644 (file)
@@ -299,7 +299,7 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
         return nil;
 
     [self _rootObject]->globalObject()->globalData()->timeoutChecker.start();
-    JSValue result = call(exec, function, callType, callData, [self _imp], argList);
+    JSValue result = callInWorld(exec, function, callType, callData, [self _imp], argList, pluginWorld());
     [self _rootObject]->globalObject()->globalData()->timeoutChecker.stop();
 
     if (exec->hadException()) {
@@ -328,7 +328,7 @@ static void getListFromNSArray(ExecState *exec, NSArray *array, RootObject* root
     JSLock lock(SilenceAssertionsOnly);
     
     [self _rootObject]->globalObject()->globalData()->timeoutChecker.start();
-    Completion completion = JSC::evaluate([self _rootObject]->globalObject()->globalExec(), [self _rootObject]->globalObject()->globalScopeChain(), makeSource(String(script)));
+    Completion completion = evaluateInWorld([self _rootObject]->globalObject()->globalExec(), [self _rootObject]->globalObject()->globalScopeChain(), makeSource(String(script)), JSC::JSValue(), pluginWorld());
     [self _rootObject]->globalObject()->globalData()->timeoutChecker.stop();
     ComplType type = completion.complType();
     
index ff7b52f..b846d10 100644 (file)
@@ -1188,19 +1188,21 @@ sub GenerateImplementation
             push(@implContent, "    impl()->invalidateEventListeners();\n");
         }
 
-        if ($interfaceName eq "Node") {
-             push(@implContent, "    forgetDOMNode(impl()->document(), impl());\n");
-        } else {
-            if ($podType) {
-                my $animatedType = $implClassName;
-                $animatedType =~ s/SVG/SVGAnimated/;
+        if (!$dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"}) {
+            if ($interfaceName eq "Node") {
+                 push(@implContent, "    forgetDOMNode(this, impl(), impl()->document());\n");
+            } else {
+                if ($podType) {
+                    my $animatedType = $implClassName;
+                    $animatedType =~ s/SVG/SVGAnimated/;
 
-                # Special case for JSSVGNumber
-                if ($codeGenerator->IsSVGAnimatedType($animatedType) and $podType ne "float") {
-                    push(@implContent, "    JSSVGDynamicPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n");
+                    # Special case for JSSVGNumber
+                    if ($codeGenerator->IsSVGAnimatedType($animatedType) and $podType ne "float") {
+                        push(@implContent, "    JSSVGDynamicPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n");
+                    }
                 }
+                push(@implContent, "    forgetDOMObject(this, impl());\n");
             }
-            push(@implContent, "    forgetDOMObject(*Heap::heap(this)->globalData(), impl());\n");
         }
 
         push(@implContent, "}\n\n");
@@ -1210,7 +1212,7 @@ sub GenerateImplementation
     # its own special handling rather than relying on the caching that Node normally does.
     if ($interfaceName eq "Document") {
         push(@implContent, "${className}::~$className()\n");
-        push(@implContent, "{\n    forgetDOMObject(*Heap::heap(this)->globalData(), static_cast<${implClassName}*>(impl()));\n}\n\n");
+        push(@implContent, "{\n    forgetDOMObject(this, static_cast<${implClassName}*>(impl()));\n}\n\n");
     }
 
     if ($needsMarkChildren && !$dataNode->extendedAttributes->{"CustomMarkFunction"}) {
@@ -1476,7 +1478,7 @@ sub GenerateImplementation
                             } else {
                                 $implIncludes{"Frame.h"} = 1;
                                 $implIncludes{"JSDOMGlobalObject.h"} = 1;
-                                push(@implContent, "    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(imp->scriptExecutionContext());\n");
+                                push(@implContent, "    JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(imp->scriptExecutionContext(), exec);\n");
                                 push(@implContent, "    if (!globalObject)\n");
                                 push(@implContent, "        return;\n");
                             }
index 006f17f..6a89652 100644 (file)
@@ -34,6 +34,7 @@
 #include "c_utility.h"
 #include "c_instance.h"
 #include "IdentifierRep.h"
+#include "JSDOMBinding.h"
 #include "npruntime_impl.h"
 #include "npruntime_priv.h"
 #include "runtime_root.h"
@@ -123,7 +124,7 @@ bool _NPN_InvokeDefault(NPP, NPObject* o, const NPVariant* args, uint32_t argCou
         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
         ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
         globalObject->globalData()->timeoutChecker.start();
-        JSValue resultV = call(exec, function, callType, callData, function, argList);
+        JSValue resultV = callInWorld(exec, function, callType, callData, function, argList, pluginWorld());
         globalObject->globalData()->timeoutChecker.stop();
 
         // Convert and return the result of the function call.
@@ -173,7 +174,7 @@ bool _NPN_Invoke(NPP npp, NPObject* o, NPIdentifier methodName, const NPVariant*
         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
         ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
         globalObject->globalData()->timeoutChecker.start();
-        JSValue resultV = call(exec, function, callType, callData, obj->imp, argList);
+        JSValue resultV = callInWorld(exec, function, callType, callData, obj->imp, argList, pluginWorld());
         globalObject->globalData()->timeoutChecker.stop();
 
         // Convert and return the result of the function call.
@@ -203,7 +204,7 @@ bool _NPN_Evaluate(NPP, NPObject* o, NPString* s, NPVariant* variant)
         String scriptString = convertNPStringToUTF16(s);
         ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
         globalObject->globalData()->timeoutChecker.start();
-        Completion completion = JSC::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(scriptString));
+        Completion completion = evaluateInWorld(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(scriptString), JSC::JSValue(), pluginWorld());
         globalObject->globalData()->timeoutChecker.stop();
         ComplType type = completion.complType();
         
@@ -443,7 +444,7 @@ bool _NPN_Construct(NPP, NPObject* o, const NPVariant* args, uint32_t argCount,
         getListFromVariantArgs(exec, args, argCount, rootObject, argList);
         ProtectedPtr<JSGlobalObject> globalObject = rootObject->globalObject();
         globalObject->globalData()->timeoutChecker.start();
-        JSValue resultV = construct(exec, constructor, constructType, constructData, argList);
+        JSValue resultV = constructInWorld(exec, constructor, constructType, constructData, argList, pluginWorld());
         globalObject->globalData()->timeoutChecker.stop();
         
         // Convert and return the result.
index eb4a6bd..cc28a75 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(MAC_JAVA_BRIDGE)
 
 #include "Frame.h"
+#include "JSDOMBinding.h"
 #include "ScriptController.h"
 #include "StringSourceProvider.h"
 #include "WebCoreFrameView.h"
@@ -302,7 +303,7 @@ jobject JavaJSObject::call(jstring methodName, jobjectArray args) const
     MarkedArgumentBuffer argList;
     getListFromJArray(exec, args, argList);
     rootObject->globalObject()->globalData()->timeoutChecker.start();
-    JSValue result = JSC::call(exec, function, callType, callData, _imp, argList);
+    JSValue result = WebCore::callInWorld(exec, function, callType, callData, _imp, argList, WebCore::pluginWorld());
     rootObject->globalObject()->globalData()->timeoutChecker.stop();
 
     return convertValueToJObject(result);
@@ -321,7 +322,7 @@ jobject JavaJSObject::eval(jstring script) const
         return 0;
 
     rootObject->globalObject()->globalData()->timeoutChecker.start();
-    Completion completion = JSC::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), makeSource(JavaString(script)));
+    Completion completion = WebCore::evaluateInWorld(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), makeSource(JavaString(script)), JSC::JSValue(), WebCore::pluginWorld());
     rootObject->globalObject()->globalData()->timeoutChecker.stop();
     ComplType type = completion.complType();
     
index 475a8c1..5505871 100644 (file)
@@ -511,6 +511,14 @@ Document::~Document()
         m_styleSheets->documentDestroyed();
 }
 
+Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world)
+{
+    JSWrapperCache* wrapperCache = new JSWrapperCache();
+    m_wrapperCacheMap.set(world, wrapperCache);
+    world->rememberDocument(this);
+    return wrapperCache;
+}
+
 void Document::resetLinkColor()
 {
     m_linkColor = Color(0, 0, 238);
index 09bba58..61eea7b 100644 (file)
@@ -79,6 +79,7 @@ namespace WebCore {
     class HTMLMapElement;
     class InspectorTimelineAgent;
     class IntPoint;
+    class DOMWrapperWorld;
     class JSNode;
     class MouseEventWithHitTestResults;
     class NodeFilter;
@@ -819,7 +820,15 @@ public:
     virtual void postTask(PassRefPtr<Task>); // Executes the task on context's thread asynchronously.
 
     typedef HashMap<WebCore::Node*, JSNode*> JSWrapperCache;
-    JSWrapperCache& wrapperCache() { return m_wrapperCache; }
+    typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap;
+    JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; }
+    JSWrapperCache* getWrapperCache(DOMWrapperWorld* world)
+    {
+        if (JSWrapperCache* wrapperCache = m_wrapperCacheMap.get(world))
+            return wrapperCache;
+        return createWrapperCache(world);
+    }
+    JSWrapperCache* createWrapperCache(DOMWrapperWorld*);
 
     virtual void finishedParsing();
 
@@ -1137,7 +1146,7 @@ private:
 
     unsigned m_numNodeListCaches;
 
-    JSWrapperCache m_wrapperCache;
+    JSWrapperCacheMap m_wrapperCacheMap;
 
 #if ENABLE(DATABASE)
     RefPtr<DatabaseThread> m_databaseThread;
index 45d4e23..db3f1bf 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ActiveDOMObject.h"
 #include "Document.h"
+#include "JSDOMWindow.h"
 #include "MessagePort.h"
 #include "SecurityOrigin.h"
 #include "WorkerContext.h"
@@ -195,4 +196,18 @@ ScriptExecutionContext::Task::~Task()
 {
 }
 
+JSC::JSGlobalData* ScriptExecutionContext::globalData()
+{
+     if (isDocument())
+        return JSDOMWindow::commonJSGlobalData();
+
+#if ENABLE(WORKERS)
+    if (isWorkerContext())
+        return static_cast<WorkerContext*>(this)->script()->globalData();
+#endif
+
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
 } // namespace WebCore
index bb78b6f..c6f0302 100644 (file)
@@ -104,6 +104,8 @@ namespace WebCore {
         void removeTimeout(int timeoutId);
         DOMTimer* findTimeout(int timeoutId);
 
+        JSC::JSGlobalData* globalData();
+
     protected:
         // Explicitly override the security origin for this script context.
         // Note: It is dangerous to change the security origin of a script context
index f6b9765..af34e82 100644 (file)
@@ -1444,7 +1444,7 @@ void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>
 
     UString title = getCurrentUserInitiatedProfileName(true);
 
-    ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
+    ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
     Profiler::profiler()->startProfiling(scriptState, title);
 
     addStartProfilingMessageToConsole(title, 0, UString());
@@ -1461,7 +1461,7 @@ void InspectorController::stopUserInitiatedProfiling()
 
     UString title = getCurrentUserInitiatedProfileName();
 
-    ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
+    ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
     RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(scriptState, title);
     if (profile)
         addProfile(profile, 0, UString());
index 9225a03..1559d82 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "config.h"
 #include "JavaScriptCallFrame.h"
+#include "JSDOMBinding.h"
 
 #if ENABLE(JAVASCRIPT_DEBUGGER)
 
@@ -105,7 +106,7 @@ JSValue JavaScriptCallFrame::evaluate(const UString& script, JSValue& exception)
         return jsNull();
 
     JSLock lock(SilenceAssertionsOnly);
-    return m_debuggerCallFrame.evaluate(script, exception);
+    return DebuggerCallFrame_evaluateInWorld(m_debuggerCallFrame, script, exception);
 }
 
 } // namespace WebCore
index df46397..9e7bc67 100644 (file)
@@ -3845,7 +3845,8 @@ void FrameLoader::dispatchDocumentElementAvailable()
 
 void FrameLoader::dispatchWindowObjectAvailable()
 {
-    if (!m_frame->script()->isEnabled() || !m_frame->script()->haveWindowShell())
+    // FIXME: should this be isolated-worlds-aware?
+    if (!m_frame->script()->isEnabled() || !m_frame->script()->existingWindowShell(mainThreadNormalWorld()))
         return;
 
     m_client->windowObjectCleared();
index 8320bc4..d69f8a7 100644 (file)
@@ -394,7 +394,7 @@ static bool getString(ScriptController* proxy, JSValue result, String& string)
         return false;
     JSLock lock(JSC::SilenceAssertionsOnly);
 
-    ExecState* exec = proxy->globalObject()->globalExec();
+    ExecState* exec = proxy->globalObject(pluginWorld())->globalExec();
     UString ustring = result.toString(exec);
     exec->clearException();
 
index ca48d8d..7536726 100644 (file)
@@ -604,10 +604,8 @@ void XMLHttpRequest::dropProtection()
     // out. But it is protected from GC while loading, so this
     // can't be recouped until the load is done, so only
     // report the extra cost at that point.
-
-    if (JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext()))
-        if (DOMObject* wrapper = getCachedDOMObjectWrapper(*globalObject->globalData(), this))
-            JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
+    if (DOMObject* wrapper = getCachedDOMObjectWrapper(*scriptExecutionContext()->globalData(), this))
+        JSC::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
 #endif
 
     unsetPendingActivity(this);
index 30744a0..078abb7 100644 (file)
 #include "EventNames.h"
 #include "EventTarget.h"
 #include "FormData.h"
+#include "JSDOMBinding.h"
 #include "ResourceResponse.h"
 #include "ScriptString.h"
 #include "ThreadableLoaderClient.h"
 #include <wtf/OwnPtr.h>
+#include <runtime/Protect.h>
 
 namespace WebCore {
 
@@ -182,7 +184,7 @@ private:
     unsigned m_lastSendLineNumber;
     String m_lastSendURL;
     ExceptionCode m_exceptionCode;
-    
+
     EventTargetData m_eventTargetData;
 };
 
index 16fd3e4..232b947 100644 (file)
@@ -1,3 +1,19 @@
+2009-10-16  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig & Geoff Garen.
+
+        https://bugs.webkit.org/show_bug.cgi?id=30696
+        Update to incorporate support for IsolatedWorlds in JSC bindings.
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _attachScriptDebugger]):
+        (-[WebFrame _stringByEvaluatingJavaScriptFromString:forceUserGesture:]):
+        (-[WebFrame globalContext]):
+        * WebView/WebScriptDebugDelegate.mm:
+        (-[WebScriptCallFrame evaluateWebScript:]):
+        * WebView/WebView.mm:
+        (-[WebView aeDescByEvaluatingJavaScriptFromString:]):
+
 2009-10-22  Eric Carlson  <eric.carlson@apple.com>
 
         Reviewed by Dan Bernstein & Simon Fraser.
index d59774a..b05f425 100644 (file)
@@ -85,6 +85,7 @@
 #import <WebCore/markup.h>
 #import <WebCore/visible_units.h>
 #import <runtime/JSLock.h>
+#import <runtime/JSObject.h>
 #import <runtime/JSValue.h>
 #import <wtf/CurrentTime.h>
 
@@ -270,11 +271,12 @@ WebView *getWebView(WebFrame *webFrame)
     ScriptController* scriptController = _private->coreFrame->script();
 
     // Calling ScriptController::globalObject() would create a window shell, and dispatch corresponding callbacks, which may be premature
-    //  if the script debugger is attached before a document is created.
-    if (!scriptController->haveWindowShell())
+    // if the script debugger is attached before a document is created.  These calls use the debuggerWorld(), we will need to pass a world
+    // to be able to debug isolated worlds.
+    if (!scriptController->existingWindowShell(debuggerWorld()))
         return;
 
-    JSGlobalObject* globalObject = scriptController->globalObject();
+    JSGlobalObject* globalObject = scriptController->globalObject(debuggerWorld());
     if (!globalObject)
         return;
 
@@ -607,7 +609,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
         return @"";
 
     JSLock lock(SilenceAssertionsOnly);
-    return String(result.toString(_private->coreFrame->script()->globalObject()->globalExec()));
+    return String(result.toString(_private->coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()));
 }
 
 - (NSRect)_caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity
@@ -1202,6 +1204,34 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
     return SecurityOrigin::canLoad(URL, String(), _private->coreFrame->document());
 }
 
+- (NSString *)_stringByEvaluatingJavaScriptInIsolatedWorld:(unsigned)worldID WithGlobalObject:(JSObjectRef)globalObjectRef FromString:(NSString *)string
+{
+    // Start off with some guess at a frame and a global object, we'll try to do better...!
+    JSDOMWindow* anyWorldGlobalObject = _private->coreFrame->script()->globalObject(mainThreadNormalWorld());
+
+    // The global object is probably a shell object? - if so, we know how to use this!
+    JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
+    if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
+        anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
+
+    // Get the frame frome the global object we've settled on.
+    Frame* frame = anyWorldGlobalObject->impl()->frame();
+    ASSERT(frame->document());
+    JSValue result = frame->script()->executeScriptInIsolatedWorld(worldID, string, true).jsValue();
+
+    if (!frame) // In case the script removed our frame from the page.
+        return @"";
+
+    // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
+    // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
+    // JSEvaluateScript instead, since they have less surprising semantics.
+    if (!result || !result.isBoolean() && !result.isString() && !result.isNumber())
+        return @"";
+
+    JSLock lock(SilenceAssertionsOnly);
+    return String(result.toString(anyWorldGlobalObject->globalExec()));
+}
+
 @end
 
 @implementation WebFrame
@@ -1433,7 +1463,7 @@ static NSURL *createUniqueWebDataURL()
     Frame* coreFrame = _private->coreFrame;
     if (!coreFrame)
         return 0;
-    return toGlobalRef(coreFrame->script()->globalObject()->globalExec());
+    return toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
 }
 
 @end
index 7446584..046898c 100644 (file)
@@ -96,6 +96,8 @@ typedef enum {
 - (void)_recursive_pauseNullEventsForAllNetscapePlugins;
 #endif
 
+- (NSString *)_stringByEvaluatingJavaScriptInIsolatedWorld:(unsigned)worldID WithGlobalObject:(JSObjectRef)globalObject FromString:(NSString *)string;
+
 // Pause a given CSS animation or transition on the target node at a specific time.
 // If the animation or transition is already paused, it will update its pause time.
 // This method is only intended to be used for testing the CSS animation and transition system.
index 8489c9b..ef2cb67 100644 (file)
@@ -249,7 +249,7 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
     }
 
     JSValue exception;
-    JSValue result = _private->debuggerCallFrame->evaluate(String(script), exception);
+    JSValue result = DebuggerCallFrame_evaluateInWorld(*_private->debuggerCallFrame, String(script), exception);
     if (exception)
         return [self _convertValueToObjcValue:exception];
     return result ? [self _convertValueToObjcValue:result] : nil;
index fbe876f..942d8b5 100644 (file)
@@ -4167,7 +4167,7 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValu
     if (!result) // FIXME: pass errors
         return 0;
     JSLock lock(SilenceAssertionsOnly);
-    return aeDescFromJSValue(coreFrame->script()->globalObject()->globalExec(), result);
+    return aeDescFromJSValue(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(), result);
 }
 
 - (BOOL)canMarkAllTextMatches
index 8afd331..68c21e0 100644 (file)
@@ -1,3 +1,17 @@
+2009-10-22  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig & Geoff Garen.
+
+        https://bugs.webkit.org/show_bug.cgi?id=30696
+        Update to incorporate support for IsolatedWorlds in JSC bindings.
+
+        * Interfaces/IWebFramePrivate.idl:
+        * WebFrame.cpp:
+        (WebFrame::globalContext):
+        (WebFrame::windowObjectCleared):
+        (WebFrame::stringByEvaluatingJavaScriptInIsolatedWorld):
+        * WebFrame.h:
+
 2009-10-20  Fumitoshi Ukai  <ukai@chromium.org>
 
         Reviewed by David Levin.
index a3366da..a140138 100644 (file)
@@ -93,4 +93,6 @@ interface IWebFramePrivate : IUnknown
     HRESULT isDisplayingStandaloneImage([out, retval] BOOL* result);
 
     HRESULT allowsFollowingLink([in] BSTR url, [out, retval] BOOL* result);
+
+    HRESULT stringByEvaluatingJavaScriptInIsolatedWorld([in] unsigned worldID, [in] OLE_HANDLE jsGlobalObject, [in] BSTR script, [out, retval] BSTR* result);
 }
index 6bdf51e..dafa658 100644 (file)
@@ -96,6 +96,9 @@
 #include <WebCore/ScriptController.h>
 #include <WebCore/SecurityOrigin.h>
 #include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/JSLock.h>
+#include <JavaScriptCore/JSObject.h>
+#include <JavaScriptCore/JSValue.h>
 #include <wtf/MathExtras.h>
 #pragma warning(pop)
 
@@ -116,6 +119,11 @@ extern "C" {
 using namespace WebCore;
 using namespace HTMLNames;
 
+using JSC::JSGlobalObject;
+using JSC::JSLock;
+using JSC::JSValue;
+using JSC::SilenceAssertionsOnly;
+
 #define FLASH_REDRAW 0
 
 
@@ -479,7 +487,7 @@ JSGlobalContextRef STDMETHODCALLTYPE WebFrame::globalContext()
     if (!coreFrame)
         return 0;
 
-    return toGlobalRef(coreFrame->script()->globalObject()->globalExec());
+    return toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
 }
 
 HRESULT STDMETHODCALLTYPE WebFrame::loadRequest( 
@@ -1702,8 +1710,8 @@ void WebFrame::windowObjectCleared()
 
     COMPtr<IWebFrameLoadDelegate> frameLoadDelegate;
     if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) {
-        JSContextRef context = toRef(coreFrame->script()->globalObject()->globalExec());
-        JSObjectRef windowObject = toRef(coreFrame->script()->globalObject());
+        JSContextRef context = toRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
+        JSObjectRef windowObject = toRef(coreFrame->script()->globalObject(mainThreadNormalWorld()));
         ASSERT(windowObject);
 
         if (FAILED(frameLoadDelegate->didClearWindowObject(d->webView, context, windowObject, this)))
@@ -2148,6 +2156,49 @@ HRESULT STDMETHODCALLTYPE WebFrame::isDescendantOfFrame(
     return S_OK;
 }
 
+HRESULT STDMETHODCALLTYPE WebFrame::stringByEvaluatingJavaScriptInIsolatedWorld(
+    /* [in] */ unsigned int worldID,
+    /* [in] */ OLE_HANDLE jsGlobalObject,
+    /* [in] */ BSTR script,
+    /* [retval][out] */ BSTR* evaluationResult)
+{
+    if (!evaluationResult)
+        return E_POINTER;
+    *evaluationResult = 0;
+
+    Frame* coreFrame = core(this);
+    JSObjectRef globalObjectRef = reinterpret_cast<JSObjectRef>(jsGlobalObject);
+    String string = String(script, SysStringLen(script));
+
+    // Start off with some guess at a frame and a global object, we'll try to do better...!
+    JSDOMWindow* anyWorldGlobalObject = coreFrame->script()->globalObject(mainThreadNormalWorld());
+
+    // The global object is probably a shell object? - if so, we know how to use this!
+    JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
+    if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
+        anyWorldGlobalObject = static_cast<JSDOMWindowShell*>(globalObjectObj)->window();
+
+    // Get the frame frome the global object we've settled on.
+    Frame* frame = anyWorldGlobalObject->impl()->frame();
+    ASSERT(frame->document());
+    JSValue result = frame->script()->executeScriptInIsolatedWorld(worldID, string, true).jsValue();
+
+    if (!frame) // In case the script removed our frame from the page.
+        return S_OK;
+
+    // This bizarre set of rules matches behavior from WebKit for Safari 2.0.
+    // If you don't like it, use -[WebScriptObject evaluateWebScript:] or 
+    // JSEvaluateScript instead, since they have less surprising semantics.
+    if (!result || !result.isBoolean() && !result.isString() && !result.isNumber())
+        return S_OK;
+
+    JSLock lock(SilenceAssertionsOnly);
+    String resultString = String(result.toString(anyWorldGlobalObject->globalExec()));
+    *evaluationResult = BString(resultString).release();
+
+    return S_OK;
+}
+
 void WebFrame::unmarkAllMisspellings()
 {
     Frame* coreFrame = core(this);
index 8edc81a..d84653c 100644 (file)
@@ -244,6 +244,12 @@ public:
         /* [in] */ BSTR url,
         /* [retval][out] */ BOOL* result);
 
+    virtual HRESULT STDMETHODCALLTYPE stringByEvaluatingJavaScriptInIsolatedWorld( 
+        /* [in] */ unsigned int worldID,
+        /* [in] */ OLE_HANDLE jsGlobalObject,
+        /* [in] */ BSTR script,
+        /* [retval][out] */ BSTR* evaluationResult);
+
     // IWebDocumentText
     virtual HRESULT STDMETHODCALLTYPE supportsTextEncoding( 
         /* [retval][out] */ BOOL* result);
index a2d415e..b181976 100644 (file)
@@ -1,3 +1,21 @@
+2009-10-22  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig & Geoff Garen.
+
+        https://bugs.webkit.org/show_bug.cgi?id=30696
+        Enable isolated-worlds tests on mac.
+
+        Add private interface for DRT to invoke execution in a given world.
+
+        * DumpRenderTree/LayoutTestController.cpp:
+        (evaluateScriptInIsolatedWorldCallback):
+        (LayoutTestController::staticFunctions):
+        * DumpRenderTree/LayoutTestController.h:
+        * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+        (LayoutTestController::evaluateScriptInIsolatedWorld):
+        * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+        (LayoutTestController::evaluateScriptInIsolatedWorld):
+
 2009-10-21  Eric Seidel  <eric@webkit.org>
 
         Reviewed by Adam Barth.
index 4b8f43e..e3fe727 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "WorkQueue.h"
 #include "WorkQueueItem.h"
+#include <JavaScriptCore/JSContextRef.h>
 #include <JavaScriptCore/JSObjectRef.h>
 #include <JavaScriptCore/JSRetainPtr.h>
 #include <stdio.h>
@@ -978,6 +979,18 @@ static JSValueRef evaluateInWebInspectorCallback(JSContextRef context, JSObjectR
     return JSValueMakeUndefined(context);
 }
 
+static JSValueRef evaluateScriptInIsolatedWorldCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+    double worldID = JSValueToNumber(context, arguments[0], exception);
+    ASSERT(!*exception);
+    JSRetainPtr<JSStringRef> script(Adopt, JSValueToStringCopy(context, arguments[1], exception));
+    ASSERT(!*exception);
+
+    controller->evaluateScriptInIsolatedWorld(static_cast<unsigned>(worldID), JSContextGetGlobalObject(context), script.get());
+    return JSValueMakeUndefined(context);
+}
+
 static JSValueRef elementDoesAutoCompleteForElementWithIdCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
     LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
@@ -1186,6 +1199,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
         { "elementDoesAutoCompleteForElementWithId", elementDoesAutoCompleteForElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "encodeHostName", encodeHostNameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "evaluateInWebInspector", evaluateInWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "evaluateScriptInIsolatedWorld", evaluateScriptInIsolatedWorldCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "execCommand", execCommandCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "grantDesktopNotificationPermission", grantDesktopNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, 
         { "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
index e73215b..6c34b1b 100644 (file)
@@ -213,6 +213,7 @@ public:
     void showWebInspector();
     void closeWebInspector();
     void evaluateInWebInspector(long callId, JSStringRef script);
+    void evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script);
 
     void setPOSIXLocale(JSStringRef locale);
 
index 0370b89..cb944e9 100644 (file)
@@ -515,3 +515,10 @@ void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef scrip
     NSString *scriptNS = (NSString *)scriptCF.get();
     [[[mainFrame webView] inspector] evaluateInFrontend:nil callId:callId script:scriptNS];
 }
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
+{
+    RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script));
+    NSString *scriptNS = (NSString *)scriptCF.get();
+    [mainFrame _stringByEvaluatingJavaScriptInIsolatedWorld:worldID WithGlobalObject:globalObject FromString:scriptNS];
+}
index 79eb6cd..b5ee2de 100644 (file)
@@ -947,6 +947,18 @@ void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef scrip
     inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR());
 }
 
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script)
+{
+    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+    if (!framePrivate)
+        return;
+
+    BSTR result;
+    if (FAILED(framePrivate->stringByEvaluatingJavaScriptInIsolatedWorld(worldId, reinterpret_cast<OLE_HANDLE>(globalObject), bstrT(script).GetBSTR(), &result)))
+        return;
+    SysFreeString(result);
+}
+
 void LayoutTestController::removeAllVisitedLinks()
 {
     COMPtr<IWebHistory> history;