void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) { if (!isContextInitialized()) return; v8::HandleScope handleScope(m_isolate); v8::Local<v8::Context> context = m_scriptState->context(); if (m_frame->isLocalFrame()) { LocalFrame* frame = toLocalFrame(m_frame); // The embedder could run arbitrary code in response to the willReleaseScriptContext callback, so all disposing should happen after it returns. frame->loader().client()->willReleaseScriptContext(context, m_world->worldId()); InspectorInstrumentation::willReleaseScriptContext(frame, m_scriptState.get()); } m_document.clear(); if (behavior == DetachGlobal) m_scriptState->detachGlobalObject(); m_scriptState->disposePerContextData(); // It's likely that disposing the context has created a lot of // garbage. Notify V8 about this so it'll have a chance of cleaning // it up when idle. V8GCForContextDispose::instance().notifyContextDisposed(m_frame->isMainFrame()); }
v8::Local<v8::Object> WindowProxy::globalIfNotDetached() { if (!isContextInitialized()) return v8::Local<v8::Object>(); ASSERT(m_scriptState->contextIsValid()); ASSERT(m_global == m_scriptState->context()->Global()); return m_global.newLocal(m_isolate); }
bool WorkerScriptController::initializeContextIfNeeded() { v8::HandleScope handleScope(isolate()); if (isContextInitialized()) return true; v8::Local<v8::Context> context = v8::Context::New(isolate()); if (context.IsEmpty()) return false; m_scriptState = ScriptState::create(context, m_world); ScriptState::Scope scope(m_scriptState.get()); // Name new context for debugging. WorkerScriptDebugServer::setContextDebugData(context); // Create a new JS object and use it as the prototype for the shadow global object. const WrapperTypeInfo* wrapperTypeInfo = m_workerGlobalScope.wrapperTypeInfo(); v8::Local<v8::Function> workerGlobalScopeConstructor = m_scriptState->perContextData()->constructorForType(wrapperTypeInfo); v8::Local<v8::Object> jsWorkerGlobalScope = V8ObjectConstructor::newInstance(isolate(), workerGlobalScopeConstructor); if (jsWorkerGlobalScope.IsEmpty()) { m_scriptState->disposePerContextData(); return false; } V8DOMWrapper::associateObjectWithWrapper(isolate(), &m_workerGlobalScope, wrapperTypeInfo, jsWorkerGlobalScope); // Insert the object instance as the prototype of the shadow object. v8::Local<v8::Object> globalObject = v8::Local<v8::Object>::Cast(m_scriptState->context()->Global()->GetPrototype()); return v8CallBoolean(globalObject->SetPrototype(context, jsWorkerGlobalScope)); }
void WindowProxy::clearForClose() { if (!isContextInitialized()) return; disposeContext(DoNotDetachGlobal); }
bool WindowProxy::initialize() { TRACE_EVENT0("v8", "WindowProxy::initialize"); TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "InitializeWindow"); ScriptForbiddenScope::AllowUserAgentScript allowScript; v8::HandleScope handleScope(m_isolate); createContext(); if (!isContextInitialized()) return false; ScriptState::Scope scope(m_scriptState.get()); v8::Handle<v8::Context> context = m_scriptState->context(); if (m_global.isEmpty()) { m_global.set(m_isolate, context->Global()); if (m_global.isEmpty()) { disposeContext(DoNotDetachGlobal); return false; } } if (!installDOMWindow()) { disposeContext(DoNotDetachGlobal); return false; } updateDocument(); m_frame->loaderClient()->didCreateScriptContext(context, m_world->extensionGroup(), m_world->worldId()); return true; }
void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) { ASSERT(m_world->isMainWorld()); if (!isContextInitialized()) return; setSecurityToken(origin); }
bool WindowProxy::initialize() { TRACE_EVENT0("v8", "WindowProxy::initialize"); SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Blink.Binding.InitializeWindowProxy"); ScriptForbiddenScope::AllowUserAgentScript allowScript; v8::HandleScope handleScope(m_isolate); createContext(); if (!isContextInitialized()) return false; ScriptState::Scope scope(m_scriptState.get()); v8::Local<v8::Context> context = m_scriptState->context(); if (m_global.isEmpty()) { m_global.set(m_isolate, context->Global()); if (m_global.isEmpty()) { disposeContext(DoNotDetachGlobal); return false; } } if (!setupWindowPrototypeChain()) { disposeContext(DoNotDetachGlobal); return false; } SecurityOrigin* origin = 0; if (m_world->isMainWorld()) { // ActivityLogger for main world is updated within updateDocument(). updateDocument(); origin = m_frame->securityContext()->getSecurityOrigin(); // FIXME: Can this be removed when CSP moves to browser? ContentSecurityPolicy* csp = m_frame->securityContext()->contentSecurityPolicy(); context->AllowCodeGenerationFromStrings( csp->allowEval(0, ContentSecurityPolicy::SuppressReport)); context->SetErrorMessageForCodeGenerationFromStrings( v8String(m_isolate, csp->evalDisabledErrorMessage())); } else { updateActivityLogger(); origin = m_world->isolatedWorldSecurityOrigin(); setSecurityToken(origin); } // All interfaces must be registered to V8PerContextData. // So we explicitly call constructorForType for the global object. V8PerContextData::from(context)->constructorForType( &V8Window::wrapperTypeInfo); if (m_frame->isLocalFrame()) { LocalFrame* frame = toLocalFrame(m_frame); MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame, origin); frame->loader().client()->didCreateScriptContext( context, m_world->extensionGroup(), m_world->worldId()); } return true; }
// Create a new environment and setup the global object. // // The global object corresponds to a DOMWindow instance. However, to // allow properties of the JS DOMWindow instance to be shadowed, we // use a shadow object as the global object and use the JS DOMWindow // instance as the prototype for that shadow object. The JS DOMWindow // instance is undetectable from JavaScript code because the __proto__ // accessors skip that object. // // The shadow object and the DOMWindow instance are seen as one object // from JavaScript. The JavaScript object that corresponds to a // DOMWindow instance is the shadow object. When mapping a DOMWindow // instance to a V8 object, we return the shadow object. // // To implement split-window, see // 1) https://bugs.webkit.org/show_bug.cgi?id=17249 // 2) https://wiki.mozilla.org/Gecko:SplitWindow // 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 // we need to split the shadow object further into two objects: // an outer window and an inner window. The inner window is the hidden // prototype of the outer window. The inner window is the default // global object of the context. A variable declared in the global // scope is a property of the inner window. // // The outer window sticks to a LocalFrame, it is exposed to JavaScript // via window.window, window.self, window.parent, etc. The outer window // has a security token which is the domain. The outer window cannot // have its own properties. window.foo = 'x' is delegated to the // inner window. // // When a frame navigates to a new page, the inner window is cut off // the outer window, and the outer window identify is preserved for // the frame. However, a new inner window is created for the new page. // If there are JS code holds a closure to the old inner window, // it won't be able to reach the outer window via its global object. bool WindowProxy::initializeIfNeeded() { if (isContextInitialized()) return true; return initialize(); }
bool WindowProxy::initialize() { TRACE_EVENT0("v8", "WindowProxy::initialize"); TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "InitializeWindow"); SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Blink.Binding.InitializeWindowProxy"); ScriptForbiddenScope::AllowUserAgentScript allowScript; v8::HandleScope handleScope(m_isolate); createContext(); if (!isContextInitialized()) return false; ScriptState::Scope scope(m_scriptState.get()); v8::Local<v8::Context> context = m_scriptState->context(); if (m_global.isEmpty()) { m_global.set(m_isolate, context->Global()); if (m_global.isEmpty()) { disposeContext(DoNotDetachGlobal); return false; } } if (!setupWindowPrototypeChain()) { disposeContext(DoNotDetachGlobal); return false; } SecurityOrigin* origin = 0; if (m_world->isMainWorld()) { // ActivityLogger for main world is updated within updateDocument(). updateDocument(); origin = m_frame->securityContext()->getSecurityOrigin(); // FIXME: Can this be removed when CSP moves to browser? ContentSecurityPolicy* csp = m_frame->securityContext()->contentSecurityPolicy(); context->AllowCodeGenerationFromStrings(csp->allowEval(0, ContentSecurityPolicy::SuppressReport)); context->SetErrorMessageForCodeGenerationFromStrings(v8String(m_isolate, csp->evalDisabledErrorMessage())); } else { updateActivityLogger(); origin = m_world->isolatedWorldSecurityOrigin(); setSecurityToken(origin); } if (m_frame->isLocalFrame()) { LocalFrame* frame = toLocalFrame(m_frame); MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame, origin); frame->loader().client()->didCreateScriptContext(context, m_world->extensionGroup(), m_world->worldId()); } // If Origin Trials have been registered before the V8 context was ready, // then inject them into the context now ExecutionContext* executionContext = m_scriptState->getExecutionContext(); if (executionContext) { OriginTrialContext* originTrialContext = OriginTrialContext::from(executionContext); if (originTrialContext) originTrialContext->initializePendingFeatures(); } return true; }
void WindowProxy::clearDocumentProperty() { ASSERT(isContextInitialized()); if (!m_world->isMainWorld()) return; v8::HandleScope handleScope(m_isolate); m_scriptState->context()->Global()->ForceDelete(v8AtomicString(m_isolate, "document")); }
void WindowProxy::clearForNavigation() { if (!isContextInitialized()) return; ScriptState::Scope scope(m_scriptState.get()); disposeContext(DetachGlobal); }
void WindowProxy::updateDocument() { ASSERT(m_world->isMainWorld()); if (!isGlobalInitialized()) return; if (!isContextInitialized()) return; updateDocumentProperty(); }
void WorkerScriptController::dispose() { m_rejectedPromises->dispose(); m_rejectedPromises.release(); m_world->dispose(); if (isContextInitialized()) m_scriptState->disposePerContextData(); }
// Create a new environment and setup the global object. // // The global object corresponds to a DOMWindow instance. However, to // allow properties of the JS DOMWindow instance to be shadowed, we // use a shadow object as the global object and use the JS DOMWindow // instance as the prototype for that shadow object. The JS DOMWindow // instance is undetectable from JavaScript code because the __proto__ // accessors skip that object. // // The shadow object and the DOMWindow instance are seen as one object // from JavaScript. The JavaScript object that corresponds to a // DOMWindow instance is the shadow object. When mapping a DOMWindow // instance to a V8 object, we return the shadow object. // // To implement split-window, see // 1) https://bugs.webkit.org/show_bug.cgi?id=17249 // 2) https://wiki.mozilla.org/Gecko:SplitWindow // 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 // we need to split the shadow object further into two objects: // an outer window and an inner window. The inner window is the hidden // prototype of the outer window. The inner window is the default // global object of the context. A variable declared in the global // scope is a property of the inner window. // // The outer window sticks to a LocalFrame, it is exposed to JavaScript // via window.window, window.self, window.parent, etc. The outer window // has a security token which is the domain. The outer window cannot // have its own properties. window.foo = 'x' is delegated to the // inner window. // // When a frame navigates to a new page, the inner window is cut off // the outer window, and the outer window identify is preserved for // the frame. However, a new inner window is created for the new page. // If there are JS code holds a closure to the old inner window, // it won't be able to reach the outer window via its global object. bool WindowProxy::initializeIfNeeded() { if (isContextInitialized()) return true; DOMWrapperWorld::setWorldOfInitializingWindow(m_world.get()); bool result = initialize(); DOMWrapperWorld::setWorldOfInitializingWindow(0); return result; }
void WindowProxy::updateDocument() { ASSERT(m_world->isMainWorld()); if (!isGlobalInitialized()) return; if (!isContextInitialized()) return; updateActivityLogger(); updateDocumentProperty(); updateSecurityOrigin(m_frame->securityContext()->getSecurityOrigin()); }
v8::Local<v8::Object> WindowProxy::releaseGlobal() { ASSERT(!isContextInitialized()); // If a ScriptState was created, the context was initialized at some point. // Make sure the global object was detached from the proxy by calling clearForNavigation(). if (m_scriptState) ASSERT(m_scriptState->isGlobalObjectDetached()); v8::Local<v8::Object> global = m_global.newLocal(m_isolate); m_global.clear(); return global; }
void WorkerOrWorkletScriptController::disposeContextIfNeeded() { if (!isContextInitialized()) return; if (m_globalScope->isWorkerGlobalScope() || m_globalScope->isThreadedWorkletGlobalScope()) { ScriptState::Scope scope(m_scriptState.get()); WorkerThreadDebugger* debugger = WorkerThreadDebugger::from(m_isolate); debugger->contextWillBeDestroyed(m_globalScope->thread(), m_scriptState->context()); } m_scriptState->disposePerContextData(); }
bool WindowProxy::initialize() { TRACE_EVENT0("v8", "WindowProxy::initialize"); TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "InitializeWindow"); ScriptForbiddenScope::AllowUserAgentScript allowScript; v8::HandleScope handleScope(m_isolate); createContext(); if (!isContextInitialized()) return false; ScriptState::Scope scope(m_scriptState.get()); v8::Local<v8::Context> context = m_scriptState->context(); if (m_global.isEmpty()) { m_global.set(m_isolate, context->Global()); if (m_global.isEmpty()) { disposeContext(DoNotDetachGlobal); return false; } } if (!installDOMWindow()) { disposeContext(DoNotDetachGlobal); return false; } SecurityOrigin* origin = 0; if (m_world->isMainWorld()) { // ActivityLogger for main world is updated within updateDocument(). updateDocument(); origin = m_frame->securityContext()->securityOrigin(); // FIXME: Can this be removed when CSP moves to browser? ContentSecurityPolicy* csp = m_frame->securityContext()->contentSecurityPolicy(); context->AllowCodeGenerationFromStrings(csp->allowEval(0, ContentSecurityPolicy::SuppressReport)); context->SetErrorMessageForCodeGenerationFromStrings(v8String(m_isolate, csp->evalDisabledErrorMessage())); } else { updateActivityLogger(); origin = m_world->isolatedWorldSecurityOrigin(); setSecurityToken(origin); } if (m_frame->isLocalFrame()) { LocalFrame* frame = toLocalFrame(m_frame); MainThreadDebugger::initializeContext(context, m_world->worldId()); InspectorInstrumentation::didCreateScriptContext(frame, m_scriptState.get(), origin, m_world->worldId()); frame->loader().client()->didCreateScriptContext(context, m_world->extensionGroup(), m_world->worldId()); } return true; }
void WindowProxy::namedItemAdded(HTMLDocument* document, const AtomicString& name) { ASSERT(m_world->isMainWorld()); if (!isContextInitialized() || !m_scriptState->contextIsValid()) return; ScriptState::Scope scope(m_scriptState.get()); ASSERT(!m_document.isEmpty()); v8::Local<v8::Context> context = m_scriptState->context(); v8::Local<v8::Object> documentHandle = m_document.newLocal(m_isolate); checkDocumentWrapper(documentHandle, document); documentHandle->SetAccessor(context, v8String(m_isolate, name), getter); }
WorkerScriptController::~WorkerScriptController() { m_rejectedPromises->dispose(); m_rejectedPromises.clear(); m_world->dispose(); // The corresponding call to didStartRunLoop() is in WorkerThread::initialize(). // See http://webkit.org/b/83104#c14 for why this is here. m_workerGlobalScope.thread()->didStopRunLoop(); if (isContextInitialized()) m_scriptState->disposePerContextData(); }
void WindowProxy::namedItemRemoved(HTMLDocument* document, const AtomicString& name) { ASSERT(m_world->isMainWorld()); if (!isContextInitialized()) return; if (document->hasNamedItem(name) || document->hasExtraNamedItem(name)) return; ScriptState::Scope scope(m_scriptState.get()); ASSERT(!m_document.isEmpty()); v8::Local<v8::Object> documentHandle = m_document.newLocal(m_isolate); checkDocumentWrapper(documentHandle, document); documentHandle->Delete(m_isolate->GetCurrentContext(), v8String(m_isolate, name)); }
WorkerScriptController::~WorkerScriptController() { ThreadState::current()->removeInterruptor(m_interruptor.get()); m_world->dispose(); // The corresponding call to didStartWorkerRunLoop is in // WorkerThread::workerThread(). // See http://webkit.org/b/83104#c14 for why this is here. blink::Platform::current()->didStopWorkerRunLoop(blink::WebWorkerRunLoop(&m_workerGlobalScope.thread()->runLoop())); if (isContextInitialized()) m_scriptState->disposePerContextData(); ThreadState::current()->addCleanupTask(IsolateCleanupTask::create(m_isolate)); }
void WindowProxy::clearForNavigation() { if (!isContextInitialized()) return; ScriptState::Scope scope(m_scriptState.get()); m_document.clear(); // Clear the document wrapper cache before turning on access checks on // the old LocalDOMWindow wrapper. This way, access to the document wrapper // will be protected by the security checks on the LocalDOMWindow wrapper. clearDocumentProperty(); v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(m_global.newLocal(m_isolate), m_isolate); ASSERT(!windowWrapper.IsEmpty()); windowWrapper->TurnOnAccessCheck(); disposeContext(DetachGlobal); }
void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) { if (!isContextInitialized()) return; v8::HandleScope handleScope(m_isolate); v8::Handle<v8::Context> context = m_scriptState->context(); m_frame->loaderClient()->willReleaseScriptContext(context, m_world->worldId()); if (behavior == DetachGlobal) context->DetachGlobal(); m_scriptState->disposePerContextData(); // It's likely that disposing the context has created a lot of // garbage. Notify V8 about this so it'll have a chance of cleaning // it up when idle. V8GCForContextDispose::instanceTemplate().notifyContextDisposed(); }
bool WorkerScriptController::initializeContextIfNeeded() { v8::HandleScope handleScope(m_isolate); if (isContextInitialized()) return true; v8::Handle<v8::Context> context = v8::Context::New(m_isolate); if (context.IsEmpty()) return false; m_scriptState = ScriptState::create(context, m_world); ScriptState::Scope scope(m_scriptState.get()); // Set DebugId for the new context. context->SetEmbedderData(0, v8AtomicString(m_isolate, "worker")); // Create a new JS object and use it as the prototype for the shadow global object. const WrapperTypeInfo* contextType = &V8DedicatedWorkerGlobalScope::wrapperTypeInfo; if (m_workerGlobalScope.isServiceWorkerGlobalScope()) contextType = &V8ServiceWorkerGlobalScope::wrapperTypeInfo; else if (!m_workerGlobalScope.isDedicatedWorkerGlobalScope()) contextType = &V8SharedWorkerGlobalScope::wrapperTypeInfo; v8::Handle<v8::Function> workerGlobalScopeConstructor = m_scriptState->perContextData()->constructorForType(contextType); v8::Local<v8::Object> jsWorkerGlobalScope = V8ObjectConstructor::newInstance(m_isolate, workerGlobalScopeConstructor); if (jsWorkerGlobalScope.IsEmpty()) { m_scriptState->disposePerContextData(); return false; } V8DOMWrapper::associateObjectWithWrapper<V8WorkerGlobalScope>(PassRefPtrWillBeRawPtr<WorkerGlobalScope>(&m_workerGlobalScope), contextType, jsWorkerGlobalScope, m_isolate, WrapperConfiguration::Dependent); // Insert the object instance as the prototype of the shadow object. v8::Handle<v8::Object> globalObject = v8::Handle<v8::Object>::Cast(m_scriptState->context()->Global()->GetPrototype()); globalObject->SetPrototype(jsWorkerGlobalScope); return true; }
WindowProxy::~WindowProxy() { // clearForClose() or clearForNavigation() must be invoked before destruction starts. ASSERT(!isContextInitialized()); }
void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) { if (!isContextInitialized()) return; setSecurityToken(origin); }
bool WorkerOrWorkletScriptController::initializeContextIfNeeded() { v8::HandleScope handleScope(m_isolate); if (isContextInitialized()) return true; // Create a new v8::Context with the worker/worklet as the global object // (aka the inner global). ScriptWrappable* scriptWrappable = m_globalScope->getScriptWrappable(); const WrapperTypeInfo* wrapperTypeInfo = scriptWrappable->wrapperTypeInfo(); v8::Local<v8::FunctionTemplate> globalInterfaceTemplate = wrapperTypeInfo->domTemplate(m_isolate, *m_world); if (globalInterfaceTemplate.IsEmpty()) return false; v8::Local<v8::ObjectTemplate> globalTemplate = globalInterfaceTemplate->InstanceTemplate(); v8::Local<v8::Context> context; { // Initialize V8 extensions before creating the context. Vector<const char*> extensionNames; if (m_globalScope->isServiceWorkerGlobalScope() && Platform::current()->allowScriptExtensionForServiceWorker( toWorkerGlobalScope(m_globalScope.get())->url())) { const V8Extensions& extensions = ScriptController::registeredExtensions(); extensionNames.reserveInitialCapacity(extensions.size()); for (const auto* extension : extensions) extensionNames.push_back(extension->name()); } v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(), extensionNames.data()); V8PerIsolateData::UseCounterDisabledScope useCounterDisabled( V8PerIsolateData::from(m_isolate)); context = v8::Context::New(m_isolate, &extensionConfiguration, globalTemplate); } if (context.IsEmpty()) return false; m_scriptState = ScriptState::create(context, m_world); ScriptState::Scope scope(m_scriptState.get()); // The global proxy object. Note this is not the global object. v8::Local<v8::Object> globalProxy = context->Global(); V8DOMWrapper::setNativeInfo(m_isolate, globalProxy, wrapperTypeInfo, scriptWrappable); // The global object, aka worker/worklet wrapper object. v8::Local<v8::Object> globalObject = globalProxy->GetPrototype().As<v8::Object>(); globalObject = V8DOMWrapper::associateObjectWithWrapper( m_isolate, scriptWrappable, wrapperTypeInfo, globalObject); // All interfaces must be registered to V8PerContextData. // So we explicitly call constructorForType for the global object. V8PerContextData::from(context)->constructorForType(wrapperTypeInfo); // Name new context for debugging. For main thread worklet global scopes // this is done once the context is initialized. if (m_globalScope->isWorkerGlobalScope() || m_globalScope->isThreadedWorkletGlobalScope()) { WorkerThreadDebugger* debugger = WorkerThreadDebugger::from(m_isolate); debugger->contextCreated(m_globalScope->thread(), context); } return true; }