JSDOMWindowBase.cpp [plain text]
#include "config.h"
#include "JSDOMWindowBase.h"
#include "Chrome.h"
#include "DOMWindow.h"
#include "Frame.h"
#include "InspectorController.h"
#include "JSDOMGlobalObjectTask.h"
#include "JSDOMWindowCustom.h"
#include "JSNode.h"
#include "Logging.h"
#include "Page.h"
#include "ScriptController.h"
#include "SecurityOrigin.h"
#include "Settings.h"
#include "WebCoreJSClientData.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_windowCloseWatchpoints((window && window->frame()) ? IsWatched : IsInvalidated)
, m_impl(window)
, m_shell(shell)
{
}
void JSDOMWindowBase::finishCreation(VM& vm, JSDOMWindowShell* shell)
{
Base::finishCreation(vm, shell);
ASSERT(inherits(info()));
GlobalPropertyInfo staticGlobals[] = {
GlobalPropertyInfo(vm.propertyNames->document, jsNull(), DontDelete | ReadOnly),
GlobalPropertyInfo(vm.propertyNames->window, m_shell, DontDelete | ReadOnly)
};
addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
}
void JSDOMWindowBase::destroy(JSCell* cell)
{
static_cast<JSDOMWindowBase*>(cell)->JSDOMWindowBase::~JSDOMWindowBase();
}
void JSDOMWindowBase::updateDocument()
{
ASSERT(m_impl->document());
ExecState* exec = globalExec();
symbolTablePutWithAttributes(this, exec->vm(), exec->vm().propertyNames->document, toJS(exec, this, m_impl->document()), DontDelete | ReadOnly);
}
ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
{
return m_impl->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)
}
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();
if (!frame)
return false;
Page* page = frame->page();
if (!page)
return false;
bool enabled = page->inspectorController().enabled();
ASSERT(enabled || !thisObject->debugger());
ASSERT(enabled || !supportsProfiling(thisObject));
return enabled;
#endif
}
static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(Page* page)
{
ASSERT(page);
return !page;
}
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();
}
bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* object)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
ASSERT(thisObject->impl().frame());
Page* page = thisObject->impl().frame()->page();
if (shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page))
return true;
#if PLATFORM(IOS)
if (page->chrome().client().isStopping())
return true;
#endif
return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object);
}
bool JSDOMWindowBase::javaScriptExperimentsEnabled(const JSGlobalObject* object)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
Frame* frame = thisObject->impl().frame();
if (!frame)
return false;
return frame->settings().javaScriptExperimentsEnabled();
}
void JSDOMWindowBase::queueTaskToEventLoop(const JSGlobalObject* object, PassRefPtr<Microtask> task)
{
const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
thisObject->scriptExecutionContext()->postTask(JSGlobalObjectTask((JSDOMWindowBase*)thisObject, task));
}
void JSDOMWindowBase::willRemoveFromWindowShell()
{
setCurrentEvent(0);
}
JSDOMWindowShell* JSDOMWindowBase::shell() const
{
return m_shell;
}
VM& JSDOMWindowBase::commonVM()
{
ASSERT(isMainThread());
static VM* vm = nullptr;
if (!vm) {
ScriptController::initializeThreading();
vm = VM::createLeaked(LargeHeap).leakRef();
#if !PLATFORM(IOS)
vm->setExclusiveThread(std::this_thread::get_id());
#else
vm->heap.setFullActivityCallback(WebSafeFullGCActivityCallback::create(&vm->heap));
#if ENABLE(GGC)
vm->heap.setEdenActivityCallback(WebSafeEdenGCActivityCallback::create(&vm->heap));
#else
vm->heap.setEdenActivityCallback(vm->heap.fullActivityCallback());
#endif
vm->heap.setIncrementalSweeper(WebSafeIncrementalSweeper::create(&vm->heap));
vm->makeUsableFromMultipleThreads();
vm->heap.machineThreads().addCurrentThread();
#endif
initNormalWorldClientData(vm);
}
return *vm;
}
JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow)
{
return toJS(exec, domWindow);
}
JSValue toJS(ExecState* exec, DOMWindow* domWindow)
{
if (!domWindow)
return jsNull();
Frame* frame = domWindow->frame();
if (!frame)
return jsNull();
return frame->script().windowShell(currentWorld(exec));
}
JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld& world)
{
if (!frame)
return 0;
return frame->script().windowShell(world)->window();
}
JSDOMWindow* toJSDOMWindow(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();
return 0;
}
void JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(DOMWindow* window)
{
JSC::VM& vm = JSDOMWindowBase::commonVM();
WebCoreJSClientData* clientData = static_cast<WebCoreJSClientData*>(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();
}
}
}