summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/js/ScriptController.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/bindings/js/ScriptController.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/bindings/js/ScriptController.cpp')
-rw-r--r--Source/WebCore/bindings/js/ScriptController.cpp444
1 files changed, 309 insertions, 135 deletions
diff --git a/Source/WebCore/bindings/js/ScriptController.cpp b/Source/WebCore/bindings/js/ScriptController.cpp
index c0135ae8d..68eb91bed 100644
--- a/Source/WebCore/bindings/js/ScriptController.cpp
+++ b/Source/WebCore/bindings/js/ScriptController.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,36 +22,48 @@
#include "ScriptController.h"
#include "BridgeJSC.h"
+#include "CachedScriptFetcher.h"
+#include "CommonVM.h"
#include "ContentSecurityPolicy.h"
#include "DocumentLoader.h"
#include "Event.h"
-#include "EventNames.h"
#include "Frame.h"
#include "FrameLoaderClient.h"
#include "GCController.h"
#include "HTMLPlugInElement.h"
#include "InspectorInstrumentation.h"
+#include "JSDOMBindingSecurity.h"
+#include "JSDOMExceptionHandling.h"
#include "JSDOMWindow.h"
#include "JSDocument.h"
#include "JSMainThreadExecState.h"
+#include "LoadableModuleScript.h"
+#include "MainFrame.h"
+#include "MemoryPressureHandler.h"
+#include "ModuleFetchFailureKind.h"
#include "NP_jsobject.h"
#include "Page.h"
+#include "PageConsoleClient.h"
#include "PageGroup.h"
-#include "PluginView.h"
-#include "ScriptCallStack.h"
+#include "PluginViewBase.h"
#include "ScriptSourceCode.h"
#include "ScriptableDocumentParser.h"
#include "Settings.h"
-#include "StorageNamespace.h"
#include "UserGestureIndicator.h"
#include "WebCoreJSClientData.h"
#include "npruntime_impl.h"
#include "runtime_root.h"
-#include <bindings/ScriptValue.h>
#include <debugger/Debugger.h>
#include <heap/StrongInlines.h>
+#include <inspector/ScriptCallStack.h>
#include <runtime/InitializeThreading.h>
+#include <runtime/JSFunction.h>
+#include <runtime/JSInternalPromise.h>
#include <runtime/JSLock.h>
+#include <runtime/JSModuleRecord.h>
+#include <runtime/JSNativeStdFunction.h>
+#include <runtime/JSScriptFetcher.h>
+#include <wtf/SetForScope.h>
#include <wtf/Threading.h>
#include <wtf/text/TextPosition.h>
@@ -59,6 +71,18 @@ using namespace JSC;
namespace WebCore {
+static void collectGarbageAfterWindowShellDestruction()
+{
+ // Make sure to GC Extra Soon(tm) during memory pressure conditions
+ // to soften high peaks of memory usage during navigation.
+ if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
+ // NOTE: We do the collection on next runloop to ensure that there's no pointer
+ // to the window object on the stack.
+ GCController::singleton().garbageCollectOnNextRunLoop();
+ } else
+ GCController::singleton().garbageCollectSoon();
+}
+
void ScriptController::initializeThreading()
{
#if !PLATFORM(IOS)
@@ -74,7 +98,7 @@ ScriptController::ScriptController(Frame& frame)
#if ENABLE(NETSCAPE_PLUGIN_API)
, m_windowScriptNPObject(0)
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
, m_windowScriptObject(0)
#endif
{
@@ -85,16 +109,19 @@ ScriptController::~ScriptController()
disconnectPlatformScriptObjects();
if (m_cacheableBindingRootObject) {
- JSLockHolder lock(JSDOMWindowBase::commonVM());
+ JSLockHolder lock(commonVM());
m_cacheableBindingRootObject->invalidate();
- m_cacheableBindingRootObject = 0;
+ m_cacheableBindingRootObject = nullptr;
}
// It's likely that destroying m_windowShells will create a lot of garbage.
if (!m_windowShells.isEmpty()) {
- while (!m_windowShells.isEmpty())
- destroyWindowShell(*m_windowShells.begin()->key);
- gcController().garbageCollectSoon();
+ while (!m_windowShells.isEmpty()) {
+ ShellMap::iterator iter = m_windowShells.begin();
+ iter->value->window()->setConsoleClient(nullptr);
+ destroyWindowShell(*iter->key);
+ }
+ collectGarbageAfterWindowShellDestruction();
}
}
@@ -105,22 +132,24 @@ void ScriptController::destroyWindowShell(DOMWrapperWorld& world)
world.didDestroyWindowShell(this);
}
-JSDOMWindowShell* ScriptController::createWindowShell(DOMWrapperWorld& world)
+JSDOMWindowShell& ScriptController::createWindowShell(DOMWrapperWorld& world)
{
ASSERT(!m_windowShells.contains(&world));
- VM& vm = *world.vm();
+ VM& vm = world.vm();
Structure* structure = JSDOMWindowShell::createStructure(vm, jsNull());
Strong<JSDOMWindowShell> windowShell(vm, JSDOMWindowShell::create(vm, m_frame.document()->domWindow(), structure, world));
Strong<JSDOMWindowShell> windowShell2(windowShell);
m_windowShells.add(&world, windowShell);
world.didCreateWindowShell(this);
- return windowShell.get();
+ return *windowShell.get();
}
-Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world)
+JSValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world, ExceptionDetails* exceptionDetails)
{
+ JSLockHolder lock(world.vm());
+
const SourceCode& jsSourceCode = sourceCode.jsSourceCode();
String sourceURL = jsSourceCode.provider()->url();
@@ -136,77 +165,178 @@ Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode
const String* savedSourceURL = m_sourceURL;
m_sourceURL = &sourceURL;
- JSLockHolder lock(exec);
-
- Ref<Frame> protect(m_frame);
-
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(&m_frame, sourceURL, sourceCode.startLine());
+ Ref<Frame> protector(m_frame);
- JSValue evaluationException;
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, sourceCode.startLine());
- JSValue returnValue = JSMainThreadExecState::evaluate(exec, jsSourceCode, shell, &evaluationException);
+ NakedPtr<JSC::Exception> evaluationException;
+ JSValue returnValue = JSMainThreadExecState::profiledEvaluate(exec, JSC::ProfilingReason::Other, jsSourceCode, shell, evaluationException);
- InspectorInstrumentation::didEvaluateScript(cookie);
+ InspectorInstrumentation::didEvaluateScript(cookie, m_frame);
if (evaluationException) {
- reportException(exec, evaluationException, sourceCode.cachedScript());
+ reportException(exec, evaluationException, sourceCode.cachedScript(), exceptionDetails);
m_sourceURL = savedSourceURL;
- return Deprecated::ScriptValue();
+ return { };
}
m_sourceURL = savedSourceURL;
- return Deprecated::ScriptValue(exec->vm(), returnValue);
+ return returnValue;
+}
+
+JSValue ScriptController::evaluate(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails)
+{
+ return evaluateInWorld(sourceCode, mainThreadNormalWorld(), exceptionDetails);
+}
+
+void ScriptController::loadModuleScriptInWorld(LoadableModuleScript& moduleScript, const String& moduleName, DOMWrapperWorld& world)
+{
+ JSLockHolder lock(world.vm());
+
+ auto& shell = *windowShell(world);
+ auto& state = *shell.window()->globalExec();
+
+ auto& promise = JSMainThreadExecState::loadModule(state, moduleName, JSC::JSScriptFetcher::create(state.vm(), { &moduleScript }));
+ setupModuleScriptHandlers(moduleScript, promise, world);
+}
+
+void ScriptController::loadModuleScript(LoadableModuleScript& moduleScript, const String& moduleName)
+{
+ loadModuleScriptInWorld(moduleScript, moduleName, mainThreadNormalWorld());
+}
+
+void ScriptController::loadModuleScriptInWorld(LoadableModuleScript& moduleScript, const ScriptSourceCode& sourceCode, DOMWrapperWorld& world)
+{
+ JSLockHolder lock(world.vm());
+
+ auto& shell = *windowShell(world);
+ auto& state = *shell.window()->globalExec();
+
+ auto& promise = JSMainThreadExecState::loadModule(state, sourceCode.jsSourceCode(), JSC::JSScriptFetcher::create(state.vm(), { &moduleScript }));
+ setupModuleScriptHandlers(moduleScript, promise, world);
+}
+
+void ScriptController::loadModuleScript(LoadableModuleScript& moduleScript, const ScriptSourceCode& sourceCode)
+{
+ loadModuleScriptInWorld(moduleScript, sourceCode, mainThreadNormalWorld());
+}
+
+JSC::JSValue ScriptController::linkAndEvaluateModuleScriptInWorld(LoadableModuleScript& moduleScript, DOMWrapperWorld& world)
+{
+ JSLockHolder lock(world.vm());
+
+ auto& shell = *windowShell(world);
+ auto& state = *shell.window()->globalExec();
+
+ // FIXME: Preventing Frame from being destroyed is essentially unnecessary.
+ // https://bugs.webkit.org/show_bug.cgi?id=164763
+ Ref<Frame> protector(m_frame);
+
+ NakedPtr<JSC::Exception> evaluationException;
+ auto returnValue = JSMainThreadExecState::linkAndEvaluateModule(state, Identifier::fromUid(&state.vm(), moduleScript.moduleKey()), jsUndefined(), evaluationException);
+ if (evaluationException) {
+ // FIXME: Give a chance to dump the stack trace if the "crossorigin" attribute allows.
+ // https://bugs.webkit.org/show_bug.cgi?id=164539
+ reportException(&state, evaluationException, nullptr);
+ return jsUndefined();
+ }
+ return returnValue;
+}
+
+JSC::JSValue ScriptController::linkAndEvaluateModuleScript(LoadableModuleScript& moduleScript)
+{
+ return linkAndEvaluateModuleScriptInWorld(moduleScript, mainThreadNormalWorld());
+}
+
+JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord, DOMWrapperWorld& world)
+{
+ JSLockHolder lock(world.vm());
+
+ const auto& jsSourceCode = moduleRecord.sourceCode();
+
+ auto& shell = *windowShell(world);
+ auto& state = *shell.window()->globalExec();
+ SetForScope<const String*> sourceURLScope(m_sourceURL, &sourceURL.string());
+
+ Ref<Frame> protector(m_frame);
+
+ auto cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, jsSourceCode.firstLine().oneBasedInt());
+
+ auto returnValue = moduleRecord.evaluate(&state);
+ InspectorInstrumentation::didEvaluateScript(cookie, m_frame);
+
+ return returnValue;
+}
+
+JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord)
+{
+ return evaluateModule(sourceURL, moduleRecord, mainThreadNormalWorld());
}
-Deprecated::ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)
+Ref<DOMWrapperWorld> ScriptController::createWorld()
{
- return evaluateInWorld(sourceCode, mainThreadNormalWorld());
+ return DOMWrapperWorld::create(commonVM());
}
-PassRefPtr<DOMWrapperWorld> ScriptController::createWorld()
+Vector<JSC::Strong<JSDOMWindowShell>> ScriptController::windowShells()
{
- return DOMWrapperWorld::create(JSDOMWindow::commonVM());
+ Vector<JSC::Strong<JSDOMWindowShell>> windowShells;
+ copyValuesToVector(m_windowShells, windowShells);
+ return windowShells;
}
void ScriptController::getAllWorlds(Vector<Ref<DOMWrapperWorld>>& worlds)
{
- static_cast<WebCoreJSClientData*>(JSDOMWindow::commonVM()->clientData)->getAllWorlds(worlds);
+ static_cast<JSVMClientData*>(commonVM().clientData)->getAllWorlds(worlds);
}
-void ScriptController::clearWindowShell(DOMWindow* newDOMWindow, bool goingIntoPageCache)
+void ScriptController::clearWindowShellsNotMatchingDOMWindow(DOMWindow* newDOMWindow, bool goingIntoPageCache)
{
if (m_windowShells.isEmpty())
return;
- JSLockHolder lock(JSDOMWindowBase::commonVM());
+ JSLockHolder lock(commonVM());
- for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) {
- JSDOMWindowShell* windowShell = iter->value.get();
-
- if (&windowShell->window()->impl() == newDOMWindow)
+ for (auto& windowShell : windowShells()) {
+ if (&windowShell->window()->wrapped() == newDOMWindow)
continue;
- // Clear the debugger from the current window before setting the new window.
- attachDebugger(windowShell, 0);
-
+ // Clear the debugger and console from the current window before setting the new window.
+ attachDebugger(windowShell.get(), nullptr);
+ windowShell->window()->setConsoleClient(nullptr);
windowShell->window()->willRemoveFromWindowShell();
- windowShell->setWindow(newDOMWindow);
+ }
+ // It's likely that resetting our windows created a lot of garbage, unless
+ // it went in a back/forward cache.
+ if (!goingIntoPageCache)
+ collectGarbageAfterWindowShellDestruction();
+}
+
+void ScriptController::setDOMWindowForWindowShell(DOMWindow* newDOMWindow)
+{
+ if (m_windowShells.isEmpty())
+ return;
+
+ JSLockHolder lock(commonVM());
+
+ for (auto& windowShell : windowShells()) {
+ if (&windowShell->window()->wrapped() == newDOMWindow)
+ continue;
+
+ windowShell->setWindow(newDOMWindow);
+
// An m_cacheableBindingRootObject persists between page navigations
// so needs to know about the new JSDOMWindow.
if (m_cacheableBindingRootObject)
m_cacheableBindingRootObject->updateGlobalObject(windowShell->window());
if (Page* page = m_frame.page()) {
- attachDebugger(windowShell, page->debugger());
+ attachDebugger(windowShell.get(), page->debugger());
windowShell->window()->setProfileGroup(page->group().identifier());
+ windowShell->window()->setConsoleClient(&page->console());
}
}
-
- // It's likely that resetting our windows created a lot of garbage, unless
- // it went in a back/forward cache.
- if (!goingIntoPageCache)
- gcController().garbageCollectSoon();
}
JSDOMWindowShell* ScriptController::initScript(DOMWrapperWorld& world)
@@ -215,29 +345,97 @@ JSDOMWindowShell* ScriptController::initScript(DOMWrapperWorld& world)
JSLockHolder lock(world.vm());
- JSDOMWindowShell* windowShell = createWindowShell(world);
+ JSDOMWindowShell& windowShell = createWindowShell(world);
- windowShell->window()->updateDocument();
+ windowShell.window()->updateDocument();
- if (m_frame.document())
- windowShell->window()->setEvalEnabled(m_frame.document()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport), m_frame.document()->contentSecurityPolicy()->evalDisabledErrorMessage());
+ if (Document* document = m_frame.document())
+ document->contentSecurityPolicy()->didCreateWindowShell(windowShell);
if (Page* page = m_frame.page()) {
- attachDebugger(windowShell, page->debugger());
- windowShell->window()->setProfileGroup(page->group().identifier());
+ attachDebugger(&windowShell, page->debugger());
+ windowShell.window()->setProfileGroup(page->group().identifier());
+ windowShell.window()->setConsoleClient(&page->console());
}
m_frame.loader().dispatchDidClearWindowObjectInWorld(world);
- return windowShell;
+ return &windowShell;
+}
+
+static Identifier jsValueToModuleKey(ExecState* exec, JSValue value)
+{
+ if (value.isSymbol())
+ return Identifier::fromUid(jsCast<Symbol*>(value)->privateName());
+ ASSERT(value.isString());
+ return asString(value)->toIdentifier(exec);
+}
+
+void ScriptController::setupModuleScriptHandlers(LoadableModuleScript& moduleScriptRef, JSInternalPromise& promise, DOMWrapperWorld& world)
+{
+ auto& shell = *windowShell(world);
+ auto& state = *shell.window()->globalExec();
+
+ // It is not guaranteed that either fulfillHandler or rejectHandler is eventually called.
+ // For example, if the page load is canceled, the DeferredPromise used in the module loader pipeline will stop executing JS code.
+ // Thus the promise returned from this function could remain unresolved.
+
+ RefPtr<LoadableModuleScript> moduleScript(&moduleScriptRef);
+
+ auto& fulfillHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) {
+ Identifier moduleKey = jsValueToModuleKey(exec, exec->argument(0));
+ moduleScript->notifyLoadCompleted(*moduleKey.impl());
+ return JSValue::encode(jsUndefined());
+ });
+
+ auto& rejectHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) {
+ VM& vm = exec->vm();
+ JSValue errorValue = exec->argument(0);
+ if (errorValue.isObject()) {
+ auto* object = JSC::asObject(errorValue);
+ if (JSValue failureKindValue = object->getDirect(vm, static_cast<JSVMClientData&>(*vm.clientData).builtinNames().failureKindPrivateName())) {
+ // This is host propagated error in the module loader pipeline.
+ switch (static_cast<ModuleFetchFailureKind>(failureKindValue.asInt32())) {
+ case ModuleFetchFailureKind::WasErrored:
+ moduleScript->notifyLoadFailed(LoadableScript::Error {
+ LoadableScript::ErrorType::CachedScript,
+ std::nullopt
+ });
+ break;
+ case ModuleFetchFailureKind::WasCanceled:
+ moduleScript->notifyLoadWasCanceled();
+ break;
+ }
+ return JSValue::encode(jsUndefined());
+ }
+ }
+
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+ moduleScript->notifyLoadFailed(LoadableScript::Error {
+ LoadableScript::ErrorType::CachedScript,
+ LoadableScript::ConsoleMessage {
+ MessageSource::JS,
+ MessageLevel::Error,
+ retrieveErrorMessage(*exec, vm, errorValue, scope),
+ }
+ });
+ return JSValue::encode(jsUndefined());
+ });
+
+ promise.then(&state, &fulfillHandler, &rejectHandler);
}
TextPosition ScriptController::eventHandlerPosition() const
{
+ // FIXME: If we are not currently parsing, we should use our current location
+ // in JavaScript, to cover cases like "element.setAttribute('click', ...)".
+
+ // FIXME: This location maps to the end of the HTML tag, and not to the
+ // exact column number belonging to the event handler attribute.
ScriptableDocumentParser* parser = m_frame.document()->scriptableDocumentParser();
if (parser)
return parser->textPosition();
- return TextPosition::minimumPosition();
+ return TextPosition();
}
void ScriptController::enableEval()
@@ -261,20 +459,27 @@ bool ScriptController::processingUserGesture()
return UserGestureIndicator::processingUserGesture();
}
-bool ScriptController::canAccessFromCurrentOrigin(Frame *frame)
+bool ScriptController::processingUserGestureForMedia()
{
- ExecState* exec = JSMainThreadExecState::currentState();
- if (exec)
- return shouldAllowAccessToFrame(exec, frame);
- // If the current state is 0 we're in a call path where the DOM security
- // check doesn't apply (eg. parser).
- return true;
+ return UserGestureIndicator::processingUserGestureForMedia();
+}
+
+bool ScriptController::canAccessFromCurrentOrigin(Frame* frame)
+{
+ ExecState* state = JSMainThreadExecState::currentState();
+
+ // If the current state is null we're in a call path where the DOM security check doesn't apply (eg. parser).
+ if (!state)
+ return true;
+
+ return BindingSecurity::shouldAllowAccessToFrame(state, frame);
}
void ScriptController::attachDebugger(JSC::Debugger* debugger)
{
- for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter)
- attachDebugger(iter->value.get(), debugger);
+ Vector<JSC::Strong<JSDOMWindowShell>> windowShells = this->windowShells();
+ for (size_t i = 0; i < windowShells.size(); ++i)
+ attachDebugger(windowShells[i].get(), debugger);
}
void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* debugger)
@@ -283,6 +488,7 @@ void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* de
return;
JSDOMWindow* globalObject = shell->window();
+ JSLockHolder lock(globalObject->vm());
if (debugger)
debugger->attach(globalObject);
else if (JSC::Debugger* currentDebugger = globalObject->debugger())
@@ -291,9 +497,11 @@ void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* de
void ScriptController::updateDocument()
{
- for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) {
- JSLockHolder lock(iter->key->vm());
- iter->value->window()->updateDocument();
+ Vector<JSC::Strong<JSDOMWindowShell>> windowShells = this->windowShells();
+ for (size_t i = 0; i < windowShells.size(); ++i) {
+ JSDOMWindowShell* windowShell = windowShells[i].get();
+ JSLockHolder lock(windowShell->world().vm());
+ windowShell->window()->updateDocument();
}
}
@@ -303,7 +511,7 @@ Bindings::RootObject* ScriptController::cacheableBindingRootObject()
return 0;
if (!m_cacheableBindingRootObject) {
- JSLockHolder lock(JSDOMWindowBase::commonVM());
+ JSLockHolder lock(commonVM());
m_cacheableBindingRootObject = Bindings::RootObject::create(0, globalObject(pluginWorld()));
}
return m_cacheableBindingRootObject.get();
@@ -315,13 +523,13 @@ Bindings::RootObject* ScriptController::bindingRootObject()
return 0;
if (!m_bindingRootObject) {
- JSLockHolder lock(JSDOMWindowBase::commonVM());
+ JSLockHolder lock(commonVM());
m_bindingRootObject = Bindings::RootObject::create(0, globalObject(pluginWorld()));
}
return m_bindingRootObject.get();
}
-PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* nativeHandle)
+RefPtr<Bindings::RootObject> ScriptController::createRootObject(void* nativeHandle)
{
RootObjectMap::iterator it = m_rootObjects.find(nativeHandle);
if (it != m_rootObjects.end())
@@ -330,36 +538,28 @@ PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* native
RefPtr<Bindings::RootObject> rootObject = Bindings::RootObject::create(nativeHandle, globalObject(pluginWorld()));
m_rootObjects.set(nativeHandle, rootObject);
- return rootObject.release();
-}
-
-#if ENABLE(INSPECTOR)
-void ScriptController::setCaptureCallStackForUncaughtExceptions(bool)
-{
+ return rootObject;
}
void ScriptController::collectIsolatedContexts(Vector<std::pair<JSC::ExecState*, SecurityOrigin*>>& result)
{
for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) {
JSC::ExecState* exec = iter->value->window()->globalExec();
- SecurityOrigin* origin = iter->value->window()->impl().document()->securityOrigin();
+ SecurityOrigin* origin = &iter->value->window()->wrapped().document()->securityOrigin();
result.append(std::pair<JSC::ExecState*, SecurityOrigin*>(exec, origin));
}
}
-#endif
-
#if ENABLE(NETSCAPE_PLUGIN_API)
-
NPObject* ScriptController::windowScriptNPObject()
{
if (!m_windowScriptNPObject) {
+ JSLockHolder lock(commonVM());
if (canExecuteScripts(NotAboutToExecuteScript)) {
// JavaScript is enabled, so there is a JavaScript window object.
// Return an NPObject bound to the window object.
JSDOMWindow* win = windowShell(pluginWorld())->window();
ASSERT(win);
- JSC::JSLockHolder lock(win->globalExec());
Bindings::RootObject* root = bindingRootObject();
m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root);
} else {
@@ -371,26 +571,15 @@ NPObject* ScriptController::windowScriptNPObject()
return m_windowScriptNPObject;
}
-
-NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin)
-{
- JSObject* object = jsObjectForPluginElement(plugin);
- if (!object)
- return _NPN_CreateNoScriptObject();
-
- // Wrap the JSObject in an NPObject
- return _NPN_CreateScriptObject(0, object, bindingRootObject());
-}
-
#endif
-#if !PLATFORM(MAC)
-PassRefPtr<JSC::Bindings::Instance> ScriptController::createScriptInstanceForWidget(Widget* widget)
+#if !PLATFORM(COCOA)
+RefPtr<JSC::Bindings::Instance> ScriptController::createScriptInstanceForWidget(Widget* widget)
{
- if (!widget->isPluginView())
- return 0;
+ if (!is<PluginViewBase>(*widget))
+ return nullptr;
- return toPluginView(widget)->bindingInstance();
+ return downcast<PluginViewBase>(*widget).bindingInstance();
}
#endif
@@ -400,9 +589,10 @@ JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin)
if (!canExecuteScripts(NotAboutToExecuteScript))
return 0;
+ JSLockHolder lock(commonVM());
+
// Create a JSObject bound to this element
JSDOMWindow* globalObj = globalObject(pluginWorld());
- JSLockHolder lock(globalObj->globalExec());
// FIXME: is normal okay? - used for NP plugins?
JSValue jsElementValue = toJS(globalObj->globalExec(), globalObj, plugin);
if (!jsElementValue || !jsElementValue.isObject())
@@ -411,7 +601,7 @@ JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin)
return jsElementValue.getObject();
}
-#if !PLATFORM(MAC)
+#if !PLATFORM(COCOA)
void ScriptController::updatePlatformScriptObjects()
{
@@ -436,7 +626,7 @@ void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle)
void ScriptController::clearScriptObjects()
{
- JSLockHolder lock(JSDOMWindowBase::commonVM());
+ JSLockHolder lock(commonVM());
RootObjectMap::const_iterator end = m_rootObjects.end();
for (RootObjectMap::const_iterator it = m_rootObjects.begin(); it != end; ++it)
@@ -446,7 +636,7 @@ void ScriptController::clearScriptObjects()
if (m_bindingRootObject) {
m_bindingRootObject->invalidate();
- m_bindingRootObject = 0;
+ m_bindingRootObject = nullptr;
}
#if ENABLE(NETSCAPE_PLUGIN_API)
@@ -455,67 +645,53 @@ void ScriptController::clearScriptObjects()
// script object properly.
// This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
_NPN_DeallocateObject(m_windowScriptNPObject);
- m_windowScriptNPObject = 0;
+ m_windowScriptNPObject = nullptr;
}
#endif
}
-Deprecated::ScriptValue ScriptController::executeScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
+JSValue ScriptController::executeScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture)
{
- UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
- ScriptSourceCode sourceCode(script, m_frame.document()->url());
+ UserGestureIndicator gestureIndicator(forceUserGesture ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt);
+ ScriptSourceCode sourceCode(script, m_frame.document()->url(), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset()));
if (!canExecuteScripts(AboutToExecuteScript) || isPaused())
- return Deprecated::ScriptValue();
+ return { };
return evaluateInWorld(sourceCode, world);
}
-bool ScriptController::shouldBypassMainWorldContentSecurityPolicy()
-{
- CallFrame* callFrame = JSDOMWindow::commonVM()->topCallFrame;
- if (callFrame == CallFrame::noCaller())
- return false;
- DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame);
- if (domWrapperWorld.isNormal())
- return false;
- return true;
-}
-
bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reason)
{
if (m_frame.document() && m_frame.document()->isSandboxed(SandboxScripts)) {
// FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
if (reason == AboutToExecuteScript)
- m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked script execution in '" + m_frame.document()->url().stringCenterEllipsizedToLength() + "' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.");
+ m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked script execution in '" + m_frame.document()->url().stringCenterEllipsizedToLength() + "' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.");
return false;
}
- if (m_frame.document() && m_frame.document()->isViewSource()) {
- ASSERT(m_frame.document()->securityOrigin()->isUnique());
- return true;
- }
-
if (!m_frame.page())
return false;
return m_frame.loader().client().allowScript(m_frame.settings().isScriptEnabled());
}
-Deprecated::ScriptValue ScriptController::executeScript(const String& script, bool forceUserGesture)
+JSValue ScriptController::executeScript(const String& script, bool forceUserGesture, ExceptionDetails* exceptionDetails)
{
- UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
- return executeScript(ScriptSourceCode(script, m_frame.document()->url()));
+ UserGestureIndicator gestureIndicator(forceUserGesture ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt);
+ return executeScript(ScriptSourceCode(script, m_frame.document()->url(), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset())), exceptionDetails);
}
-Deprecated::ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode)
+JSValue ScriptController::executeScript(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails)
{
if (!canExecuteScripts(AboutToExecuteScript) || isPaused())
- return Deprecated::ScriptValue();
+ return { }; // FIXME: Would jsNull be better?
- Ref<Frame> protect(m_frame); // Script execution can destroy the frame, and thus the ScriptController.
+ // FIXME: Preventing Frame from being destroyed is essentially unnecessary.
+ // https://bugs.webkit.org/show_bug.cgi?id=164763
+ Ref<Frame> protector(m_frame); // Script execution can destroy the frame, and thus the ScriptController.
- return evaluate(sourceCode);
+ return evaluate(sourceCode, exceptionDetails);
}
bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
@@ -534,7 +710,7 @@ bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocum
const int javascriptSchemeLength = sizeof("javascript:") - 1;
String decodedURL = decodeURLEscapeSequences(url.string());
- Deprecated::ScriptValue result = executeScript(decodedURL.substring(javascriptSchemeLength));
+ auto result = executeScript(decodedURL.substring(javascriptSchemeLength));
// If executing script caused this frame to be removed from the page, we
// don't want to try to replace its document!
@@ -542,9 +718,7 @@ bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocum
return true;
String scriptResult;
- JSDOMWindowShell* shell = windowShell(mainThreadNormalWorld());
- JSC::ExecState* exec = shell->window()->globalExec();
- if (!result.getString(exec, scriptResult))
+ if (!result || !result.getString(windowShell(mainThreadNormalWorld())->window()->globalExec(), scriptResult))
return true;
// FIXME: We should always replace the document, but doing so