summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/js/JSDOMWindowBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/bindings/js/JSDOMWindowBase.cpp')
-rw-r--r--Source/WebCore/bindings/js/JSDOMWindowBase.cpp335
1 files changed, 222 insertions, 113 deletions
diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp
index c6739780b..45df5a8e0 100644
--- a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp
+++ b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp
@@ -1,8 +1,9 @@
/*
* Copyright (C) 2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reseved.
+ * Copyright (C) 2003-2009, 2014, 2016 Apple Inc. All rights reseved.
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (c) 2015 Canon 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
@@ -23,45 +24,60 @@
#include "config.h"
#include "JSDOMWindowBase.h"
+#include "ActiveDOMCallbackMicrotask.h"
#include "Chrome.h"
-#include "Console.h"
+#include "CommonVM.h"
#include "DOMWindow.h"
#include "Frame.h"
#include "InspectorController.h"
+#include "JSDOMBindingSecurity.h"
#include "JSDOMGlobalObjectTask.h"
#include "JSDOMWindowCustom.h"
+#include "JSMainThreadExecState.h"
#include "JSNode.h"
+#include "Language.h"
#include "Logging.h"
#include "Page.h"
+#include "RuntimeApplicationChecks.h"
#include "ScriptController.h"
+#include "ScriptModuleLoader.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include "WebCoreJSClientData.h"
+#include <bytecode/CodeBlock.h>
+#include <heap/StrongInlines.h>
+#include <runtime/JSInternalPromiseDeferred.h>
#include <runtime/Microtask.h>
#include <wtf/MainThread.h>
#if PLATFORM(IOS)
#include "ChromeClient.h"
-#include "WebSafeGCActivityCallbackIOS.h"
-#include "WebSafeIncrementalSweeperIOS.h"
#endif
using namespace JSC;
namespace WebCore {
-static bool shouldAllowAccessFrom(const JSGlobalObject* thisObject, ExecState* exec)
-{
- return BindingSecurity::shouldAllowAccessToDOMWindow(exec, asJSDOMWindow(thisObject)->impl());
-}
-
-const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) };
-
-const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &shouldAllowAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout };
-
-JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
- : JSDOMGlobalObject(vm, structure, &shell->world(), &s_globalObjectMethodTable)
- , m_impl(window)
+const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) };
+
+const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = {
+ &supportsRichSourceInfo,
+ &shouldInterruptScript,
+ &javaScriptRuntimeFlags,
+ &queueTaskToEventLoop,
+ &shouldInterruptScriptBeforeTimeout,
+ &moduleLoaderImportModule,
+ &moduleLoaderResolve,
+ &moduleLoaderFetch,
+ nullptr,
+ &moduleLoaderEvaluate,
+ &defaultLanguage
+};
+
+JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, RefPtr<DOMWindow>&& window, JSDOMWindowShell* shell)
+ : JSDOMGlobalObject(vm, structure, shell->world(), &s_globalObjectMethodTable)
+ , m_windowCloseWatchpoints((window && window->frame()) ? IsWatched : IsInvalidated)
+ , m_wrapped(WTFMove(window))
, m_shell(shell)
{
}
@@ -69,14 +85,24 @@ JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, PassRefPtr<DOMWin
void JSDOMWindowBase::finishCreation(VM& vm, JSDOMWindowShell* shell)
{
Base::finishCreation(vm, shell);
- ASSERT(inherits(info()));
+ ASSERT(inherits(vm, info()));
GlobalPropertyInfo staticGlobals[] = {
GlobalPropertyInfo(vm.propertyNames->document, jsNull(), DontDelete | ReadOnly),
- GlobalPropertyInfo(vm.propertyNames->window, m_shell, DontDelete | ReadOnly)
+ GlobalPropertyInfo(vm.propertyNames->window, m_shell, DontDelete | ReadOnly),
};
-
+
addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
+
+ if (m_wrapped && m_wrapped->frame() && m_wrapped->frame()->settings().needsSiteSpecificQuirks())
+ setNeedsSiteSpecificQuirks(true);
+}
+
+void JSDOMWindowBase::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSDOMWindowBase* thisObject = jsCast<JSDOMWindowBase*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
}
void JSDOMWindowBase::destroy(JSCell* cell)
@@ -86,48 +112,31 @@ void JSDOMWindowBase::destroy(JSCell* cell)
void JSDOMWindowBase::updateDocument()
{
- ASSERT(m_impl->document());
+ // Since "document" property is defined as { configurable: false, writable: false, enumerable: true },
+ // users cannot change its attributes further.
+ // Reaching here, the attributes of "document" property should be never changed.
+ ASSERT(m_wrapped->document());
ExecState* exec = globalExec();
- symbolTablePutWithAttributes(this, exec->vm(), exec->vm().propertyNames->document, toJS(exec, this, m_impl->document()), DontDelete | ReadOnly);
+ bool shouldThrowReadOnlyError = false;
+ bool ignoreReadOnlyErrors = true;
+ bool putResult = false;
+ symbolTablePutTouchWatchpointSet(this, exec, exec->vm().propertyNames->document, toJS(exec, this, m_wrapped->document()), shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
}
ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
{
- return m_impl->document();
+ return m_wrapped->document();
}
void JSDOMWindowBase::printErrorMessage(const String& message) const
{
- printErrorMessageForFrame(impl().frame(), message);
-}
-
-bool JSDOMWindowBase::supportsProfiling(const JSGlobalObject* object)
-{
-#if !ENABLE(INSPECTOR)
- UNUSED_PARAM(object);
- return false;
-#else
- const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- Frame* frame = thisObject->impl().frame();
- if (!frame)
- return false;
-
- Page* page = frame->page();
- if (!page)
- return false;
-
- return page->inspectorController().profilerEnabled();
-#endif // ENABLE(INSPECTOR)
+ printErrorMessageForFrame(wrapped().frame(), message);
}
bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object)
{
-#if !ENABLE(INSPECTOR)
- UNUSED_PARAM(object);
- return false;
-#else
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- Frame* frame = thisObject->impl().frame();
+ Frame* frame = thisObject->wrapped().frame();
if (!frame)
return false;
@@ -137,9 +146,7 @@ bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object)
bool enabled = page->inspectorController().enabled();
ASSERT(enabled || !thisObject->debugger());
- ASSERT(enabled || !supportsProfiling(thisObject));
return enabled;
-#endif
}
static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(Page* page)
@@ -157,16 +164,16 @@ static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPag
bool JSDOMWindowBase::shouldInterruptScript(const JSGlobalObject* object)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- ASSERT(thisObject->impl().frame());
- Page* page = thisObject->impl().frame()->page();
- return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page) || page->chrome().shouldInterruptJavaScript();
+ ASSERT(thisObject->wrapped().frame());
+ Page* page = thisObject->wrapped().frame()->page();
+ return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page);
}
bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* object)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- ASSERT(thisObject->impl().frame());
- Page* page = thisObject->impl().frame()->page();
+ ASSERT(thisObject->wrapped().frame());
+ Page* page = thisObject->wrapped().frame()->page();
if (shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page))
return true;
@@ -179,85 +186,79 @@ bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* o
return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object);
}
-bool JSDOMWindowBase::javaScriptExperimentsEnabled(const JSGlobalObject* object)
+RuntimeFlags JSDOMWindowBase::javaScriptRuntimeFlags(const JSGlobalObject* object)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- Frame* frame = thisObject->impl().frame();
+ Frame* frame = thisObject->wrapped().frame();
if (!frame)
- return false;
- return frame->settings().javaScriptExperimentsEnabled();
+ return RuntimeFlags();
+ return frame->settings().javaScriptRuntimeFlags();
}
-void JSDOMWindowBase::queueTaskToEventLoop(const JSGlobalObject* object, PassRefPtr<Microtask> task)
-{
- const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
- thisObject->scriptExecutionContext()->postTask(JSGlobalObjectTask::create((JSDOMWindowBase*)thisObject, task));
-}
+class JSDOMWindowMicrotaskCallback : public RefCounted<JSDOMWindowMicrotaskCallback> {
+public:
+ static Ref<JSDOMWindowMicrotaskCallback> create(JSDOMWindowBase* globalObject, Ref<JSC::Microtask>&& task)
+ {
+ return adoptRef(*new JSDOMWindowMicrotaskCallback(globalObject, WTFMove(task)));
+ }
-void JSDOMWindowBase::willRemoveFromWindowShell()
-{
- setCurrentEvent(0);
-}
+ void call()
+ {
+ Ref<JSDOMWindowMicrotaskCallback> protectedThis(*this);
+ VM& vm = m_globalObject->vm();
+ JSLockHolder lock(vm);
+ auto scope = DECLARE_THROW_SCOPE(vm);
-JSDOMWindowShell* JSDOMWindowBase::shell() const
-{
- return m_shell;
-}
+ ExecState* exec = m_globalObject->globalExec();
-VM* JSDOMWindowBase::commonVM()
-{
- ASSERT(isMainThread());
+ JSMainThreadExecState::runTask(exec, m_task);
-#if !PLATFORM(IOS)
- static VM* vm = 0;
-#else
- VM*& vm = commonVMInternal();
-#endif
- if (!vm) {
- ScriptController::initializeThreading();
- vm = VM::createLeaked(LargeHeap).leakRef();
-#if PLATFORM(IOS)
- PassOwnPtr<WebSafeGCActivityCallback> activityCallback = WebSafeGCActivityCallback::create(&vm->heap);
- vm->heap.setActivityCallback(activityCallback);
- PassOwnPtr<WebSafeIncrementalSweeper> incrementalSweeper = WebSafeIncrementalSweeper::create(&vm->heap);
- vm->heap.setIncrementalSweeper(incrementalSweeper);
- vm->makeUsableFromMultipleThreads();
- vm->heap.machineThreads().addCurrentThread();
-#else
- vm->exclusiveThread = currentThread();
-#endif // !PLATFORM(IOS)
- initNormalWorldClientData(vm);
+ ASSERT_UNUSED(scope, !scope.exception());
}
- return vm;
+private:
+ JSDOMWindowMicrotaskCallback(JSDOMWindowBase* globalObject, Ref<JSC::Microtask>&& task)
+ : m_globalObject(globalObject->vm(), globalObject)
+ , m_task(WTFMove(task))
+ {
+ }
+
+ Strong<JSDOMWindowBase> m_globalObject;
+ Ref<JSC::Microtask> m_task;
+};
+
+void JSDOMWindowBase::queueTaskToEventLoop(const JSGlobalObject* object, Ref<JSC::Microtask>&& task)
+{
+ const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
+
+ RefPtr<JSDOMWindowMicrotaskCallback> callback = JSDOMWindowMicrotaskCallback::create((JSDOMWindowBase*)thisObject, WTFMove(task));
+ auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *thisObject->scriptExecutionContext(), [callback]() mutable {
+ callback->call();
+ });
+
+ MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask));
}
-#if PLATFORM(IOS)
-bool JSDOMWindowBase::commonVMExists()
+void JSDOMWindowBase::willRemoveFromWindowShell()
{
- return commonVMInternal();
+ setCurrentEvent(0);
}
-VM*& JSDOMWindowBase::commonVMInternal()
+JSDOMWindowShell* JSDOMWindowBase::shell() const
{
- ASSERT(isMainThread());
- static VM* commonVM;
- return commonVM;
+ return m_shell;
}
-#endif
// JSDOMGlobalObject* is ignored, accessing a window in any context will
// use that DOMWindow's prototype chain.
-JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
+JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow& domWindow)
{
return toJS(exec, domWindow);
}
-JSValue toJS(ExecState* exec, DOMWindow* domWindow)
+JSValue toJS(ExecState* exec, DOMWindow& domWindow)
{
- if (!domWindow)
- return jsNull();
- Frame* frame = domWindow->frame();
+ Frame* frame = domWindow.frame();
if (!frame)
return jsNull();
return frame->script().windowShell(currentWorld(exec));
@@ -270,16 +271,124 @@ JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld& world)
return frame->script().windowShell(world)->window();
}
-JSDOMWindow* toJSDOMWindow(JSValue value)
+JSDOMWindow* toJSDOMWindow(JSC::VM& vm, JSValue value)
{
if (!value.isObject())
return 0;
- const ClassInfo* classInfo = asObject(value)->classInfo();
- if (classInfo == JSDOMWindow::info())
- return jsCast<JSDOMWindow*>(asObject(value));
- if (classInfo == JSDOMWindowShell::info())
- return jsCast<JSDOMWindowShell*>(asObject(value))->window();
+
+ while (!value.isNull()) {
+ JSObject* object = asObject(value);
+ const ClassInfo* classInfo = object->classInfo(vm);
+ if (classInfo == JSDOMWindow::info())
+ return jsCast<JSDOMWindow*>(object);
+ if (classInfo == JSDOMWindowShell::info())
+ return jsCast<JSDOMWindowShell*>(object)->window();
+ value = object->getPrototypeDirect();
+ }
return 0;
}
+DOMWindow& callerDOMWindow(ExecState* exec)
+{
+ class GetCallerGlobalObjectFunctor {
+ public:
+ GetCallerGlobalObjectFunctor() = default;
+
+ StackVisitor::Status operator()(StackVisitor& visitor) const
+ {
+ if (!m_hasSkippedFirstFrame) {
+ m_hasSkippedFirstFrame = true;
+ return StackVisitor::Continue;
+ }
+
+ if (auto* codeBlock = visitor->codeBlock())
+ m_globalObject = codeBlock->globalObject();
+ else {
+ ASSERT(visitor->callee());
+ // FIXME: Callee is not an object if the caller is Web Assembly.
+ // Figure out what to do here. We can probably get the global object
+ // from the top-most Wasm Instance. https://bugs.webkit.org/show_bug.cgi?id=165721
+ if (visitor->callee()->isObject())
+ m_globalObject = jsCast<JSObject*>(visitor->callee())->globalObject();
+ }
+ return StackVisitor::Done;
+ }
+
+ JSGlobalObject* globalObject() const { return m_globalObject; }
+
+ private:
+ mutable bool m_hasSkippedFirstFrame { false };
+ mutable JSGlobalObject* m_globalObject { nullptr };
+ };
+
+ GetCallerGlobalObjectFunctor iter;
+ exec->iterate(iter);
+ return iter.globalObject() ? asJSDOMWindow(iter.globalObject())->wrapped() : firstDOMWindow(exec);
+}
+
+DOMWindow& activeDOMWindow(ExecState* exec)
+{
+ return asJSDOMWindow(exec->lexicalGlobalObject())->wrapped();
+}
+
+DOMWindow& firstDOMWindow(ExecState* exec)
+{
+ return asJSDOMWindow(exec->vmEntryGlobalObject())->wrapped();
+}
+
+void JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(DOMWindow* window)
+{
+ JSC::VM& vm = commonVM();
+ JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData);
+ Vector<Ref<DOMWrapperWorld>> wrapperWorlds;
+ clientData->getAllWorlds(wrapperWorlds);
+ for (unsigned i = 0; i < wrapperWorlds.size(); ++i) {
+ DOMObjectWrapperMap& wrappers = wrapperWorlds[i]->m_wrappers;
+ auto result = wrappers.find(window);
+ if (result == wrappers.end())
+ continue;
+ JSC::JSObject* wrapper = result->value.get();
+ if (!wrapper)
+ continue;
+ JSDOMWindowBase* jsWindow = JSC::jsCast<JSDOMWindowBase*>(wrapper);
+ jsWindow->m_windowCloseWatchpoints.fireAll(vm, "Frame cleared");
+ }
+}
+
+
+JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderResolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher)
+{
+ JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
+ if (RefPtr<Document> document = thisObject->wrapped().document())
+ return document->moduleLoader()->resolve(globalObject, exec, moduleLoader, moduleName, importerModuleKey, scriptFetcher);
+ JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
+ return deferred->reject(exec, jsUndefined());
+}
+
+JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderFetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue scriptFetcher)
+{
+ JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
+ if (RefPtr<Document> document = thisObject->wrapped().document())
+ return document->moduleLoader()->fetch(globalObject, exec, moduleLoader, moduleKey, scriptFetcher);
+ JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
+ return deferred->reject(exec, jsUndefined());
+}
+
+JSC::JSValue JSDOMWindowBase::moduleLoaderEvaluate(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher)
+{
+ JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
+ if (RefPtr<Document> document = thisObject->wrapped().document())
+ return document->moduleLoader()->evaluate(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher);
+ return JSC::jsUndefined();
+}
+
+JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderImportModule(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSString* moduleName, const JSC::SourceOrigin& sourceOrigin)
+{
+ JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
+ if (RefPtr<Document> document = thisObject->wrapped().document())
+ return document->moduleLoader()->importModule(globalObject, exec, moduleLoader, moduleName, sourceOrigin);
+ JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
+ return deferred->reject(exec, jsUndefined());
+}
+
} // namespace WebCore