#include "config.h"
#include "WindowProxy.h"
#include "CommonVM.h"
#include "Frame.h"
#include "GCController.h"
#include "JSWindowProxy.h"
#include "Page.h"
#include "PageConsoleClient.h"
#include "PageGroup.h"
#include "RemoteFrame.h"
#include "ScriptController.h"
#include "runtime_root.h"
#include <JavaScriptCore/JSLock.h>
#include <wtf/MemoryPressureHandler.h>
namespace WebCore {
static void collectGarbageAfterWindowProxyDestruction()
{
if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
GCController::singleton().garbageCollectOnNextRunLoop();
} else
GCController::singleton().garbageCollectSoon();
}
WindowProxy::WindowProxy(AbstractFrame& frame)
: m_frame(&frame)
{
}
WindowProxy::~WindowProxy()
{
ASSERT(!m_frame);
ASSERT(m_jsWindowProxies.isEmpty());
}
void WindowProxy::detachFromFrame()
{
ASSERT(m_frame);
m_frame = nullptr;
if (!m_jsWindowProxies.isEmpty()) {
while (!m_jsWindowProxies.isEmpty()) {
auto it = m_jsWindowProxies.begin();
it->value->window()->setConsoleClient(nullptr);
destroyJSWindowProxy(*it->key);
}
collectGarbageAfterWindowProxyDestruction();
}
}
void WindowProxy::destroyJSWindowProxy(DOMWrapperWorld& world)
{
ASSERT(m_jsWindowProxies.contains(&world));
m_jsWindowProxies.remove(&world);
world.didDestroyWindowProxy(this);
}
JSWindowProxy& WindowProxy::createJSWindowProxy(DOMWrapperWorld& world)
{
ASSERT(m_frame);
ASSERT(!m_jsWindowProxies.contains(&world));
ASSERT(m_frame->window());
VM& vm = world.vm();
Strong<JSWindowProxy> jsWindowProxy(vm, &JSWindowProxy::create(vm, *m_frame->window(), world));
Strong<JSWindowProxy> jsWindowProxy2(jsWindowProxy);
m_jsWindowProxies.add(&world, jsWindowProxy);
world.didCreateWindowProxy(this);
return *jsWindowProxy.get();
}
Vector<JSC::Strong<JSWindowProxy>> WindowProxy::jsWindowProxiesAsVector() const
{
return copyToVector(m_jsWindowProxies.values());
}
JSDOMGlobalObject* WindowProxy::globalObject(DOMWrapperWorld& world)
{
if (auto* windowProxy = jsWindowProxy(world))
return windowProxy->window();
return nullptr;
}
JSWindowProxy& WindowProxy::createJSWindowProxyWithInitializedScript(DOMWrapperWorld& world)
{
ASSERT(m_frame);
JSLockHolder lock(world.vm());
auto& windowProxy = createJSWindowProxy(world);
if (is<Frame>(*m_frame))
downcast<Frame>(*m_frame).script().initScriptForWindowProxy(windowProxy);
return windowProxy;
}
void WindowProxy::clearJSWindowProxiesNotMatchingDOMWindow(AbstractDOMWindow* newDOMWindow, bool goingIntoPageCache)
{
if (m_jsWindowProxies.isEmpty())
return;
JSLockHolder lock(commonVM());
for (auto& windowProxy : jsWindowProxiesAsVector()) {
if (&windowProxy->wrapped() == newDOMWindow)
continue;
windowProxy->attachDebugger(nullptr);
windowProxy->window()->setConsoleClient(nullptr);
if (auto* jsDOMWindow = jsDynamicCast<JSDOMWindowBase*>(*windowProxy->vm(), windowProxy->window()))
jsDOMWindow->willRemoveFromWindowProxy();
}
if (!goingIntoPageCache)
collectGarbageAfterWindowProxyDestruction();
}
void WindowProxy::setDOMWindow(AbstractDOMWindow* newDOMWindow)
{
ASSERT(newDOMWindow);
if (m_jsWindowProxies.isEmpty())
return;
ASSERT(m_frame);
JSLockHolder lock(commonVM());
for (auto& windowProxy : jsWindowProxiesAsVector()) {
if (&windowProxy->wrapped() == newDOMWindow)
continue;
windowProxy->setWindow(*newDOMWindow);
ScriptController* scriptController = nullptr;
Page* page = nullptr;
if (is<Frame>(*m_frame)) {
auto& frame = downcast<Frame>(*m_frame);
scriptController = &frame.script();
page = frame.page();
}
if (auto* cacheableBindingRootObject = scriptController ? scriptController->existingCacheableBindingRootObject() : nullptr)
cacheableBindingRootObject->updateGlobalObject(windowProxy->window());
windowProxy->attachDebugger(page ? page->debugger() : nullptr);
if (page)
windowProxy->window()->setProfileGroup(page->group().identifier());
windowProxy->window()->setConsoleClient(page ? &page->console() : nullptr);
}
}
void WindowProxy::attachDebugger(JSC::Debugger* debugger)
{
for (auto& windowProxy : m_jsWindowProxies.values())
windowProxy->attachDebugger(debugger);
}
AbstractDOMWindow* WindowProxy::window() const
{
return m_frame ? m_frame->window() : nullptr;
}
}