void V8WorkerGlobalScopeEventListener::handleEvent(ExecutionContext* context, Event* event) { if (!context) return; // The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it. // See issue 889829. RefPtr<V8AbstractEventListener> protect(this); v8::Isolate* isolate = toIsolate(context); v8::HandleScope handleScope(isolate); WorkerScriptController* script = toWorkerGlobalScope(context)->script(); if (!script) return; v8::Handle<v8::Context> v8Context = script->context(); if (v8Context.IsEmpty()) return; // Enter the V8 context in which to perform the event handling. v8::Context::Scope scope(v8Context); // Get the V8 wrapper for the event object. v8::Handle<v8::Value> jsEvent = toV8(event, v8::Handle<v8::Object>(), isolate); invokeEventHandler(context, event, v8::Local<v8::Value>::New(isolate, jsEvent)); }
// static WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy(Worker* worker) { // Special behavior for multiple workers per process. // FIXME: v8 doesn't support more than one workers per process. // if (!worker->scriptExecutionContext()->isDocument()) // return new WorkerMessagingProxy(worker); WebWorker* webWorker = 0; WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker); if (worker->scriptExecutionContext()->isDocument()) { Document* document = static_cast<Document*>( worker->scriptExecutionContext()); WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); webWorker = webFrame->client()->createWorker(webFrame, proxy); } else { WorkerScriptController* controller = WorkerScriptController::controllerForContext(); if (!controller) { ASSERT_NOT_REACHED(); return 0; } DedicatedWorkerThread* thread = static_cast<DedicatedWorkerThread*>(controller->workerContext()->thread()); WorkerObjectProxy* workerObjectProxy = &thread->workerObjectProxy(); WebWorkerImpl* impl = reinterpret_cast<WebWorkerImpl*>(workerObjectProxy); webWorker = impl->client()->createWorker(proxy); } proxy->setWebWorker(webWorker); return proxy; }
void V8WorkerContextEventListener::handleEvent(ScriptExecutionContext* context, Event* event) { if (!context) return; // The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it. // See issue 889829. RefPtr<V8AbstractEventListener> protect(this); v8::HandleScope handleScope; ASSERT(context->isWorkerContext()); WorkerScriptController* script = static_cast<WorkerContext*>(context)->script(); if (!script) return; v8::Handle<v8::Context> v8Context = script->context(); if (v8Context.IsEmpty()) return; // Enter the V8 context in which to perform the event handling. v8::Context::Scope scope(v8Context); // Get the V8 wrapper for the event object. v8::Handle<v8::Value> jsEvent = toV8(event); invokeEventHandler(context, event, jsEvent); }
void* WorkerThread::workerThread() { { MutexLocker lock(m_threadCreationMutex); m_workerContext = createWorkerContext(m_startupData->m_scriptURL, m_startupData->m_userAgent); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerContext->script()->forbidExecution(); } } WorkerScriptController* script = m_workerContext->script(); script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData.clear(); runEventLoop(); ThreadIdentifier threadID = m_threadID; ASSERT(m_workerContext->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerContext = 0; // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); return 0; }
void executeScriptInWorker(WorkerThread* worker, WebWaitableEvent* waitEvent) { WorkerScriptController* scriptController = worker->workerGlobalScope()->script(); bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;")); ASSERT_UNUSED(evaluateResult, evaluateResult); waitEvent->signal(); }
bool ActiveDOMCallback::isScriptControllerTerminating() const { ExecutionContext* context = executionContext(); if (context && context->isWorkerGlobalScope()) { WorkerScriptController* scriptController = toWorkerGlobalScope(context)->script(); if (!scriptController || scriptController->isExecutionForbidden() || scriptController->isExecutionTerminating()) return true; } return false; }
JSValue toJS(ExecState*, WorkerContext* workerContext) { if (!workerContext) return jsNull(); WorkerScriptController* script = workerContext->script(); if (!script) return jsNull(); JSWorkerContext* contextWrapper = script->workerContextWrapper(); ASSERT(contextWrapper); return contextWrapper; }
v8::Local<v8::Function> V8DOMWrapper::getConstructor(WrapperTypeInfo* type, WorkerContext*) { WorkerScriptController* controller = WorkerScriptController::controllerForContext(); WorkerContextExecutionProxy* proxy = controller ? controller->proxy() : 0; if (!proxy) return v8::Local<v8::Function>(); v8::Handle<v8::Context> context = proxy->context(); if (context.IsEmpty()) return v8::Local<v8::Function>(); return getConstructorForContext(type, context); }
void WorkerThread::workerThread() { // Propagate the mainThread's fenv to workers. #if PLATFORM(IOS) FloatingPointEnvironment::singleton().propagateMainThreadEnvironment(); #endif #if PLATFORM(GTK) GRefPtr<GMainContext> mainContext = adoptGRef(g_main_context_new()); g_main_context_push_thread_default(mainContext.get()); #endif { LockHolder lock(m_threadCreationMutex); m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_shouldBypassMainWorldContentSecurityPolicy, WTFMove(m_startupData->m_topOrigin)); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerGlobalScope->script()->forbidExecution(); } } WorkerScriptController* script = m_workerGlobalScope->script(); script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData = nullptr; runEventLoop(); #if PLATFORM(GTK) g_main_context_pop_thread_default(mainContext.get()); #endif ThreadIdentifier threadID = m_threadID; ASSERT(m_workerGlobalScope->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerGlobalScope = nullptr; // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! threadGlobalData().destroy(); // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); }
v8::Handle<v8::Value> toV8(WorkerContext* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) { // Notice that we explicitly ignore creationContext because the WorkerContext is its own creationContext. if (!impl) return v8NullWithCheck(isolate); WorkerScriptController* script = impl->script(); if (!script) return v8NullWithCheck(isolate); v8::Handle<v8::Object> global = script->context()->Global(); ASSERT(!global.IsEmpty()); return global; }
void ScheduledAction::execute(WorkerContext* workerContext) { // In a Worker, the execution should always happen on a worker thread. ASSERT(workerContext->thread()->threadID() == currentThread()); WorkerScriptController* scriptController = workerContext->script(); if (m_function) { JSWorkerContext* contextWrapper = scriptController->workerContextWrapper(); executeFunctionInContext(contextWrapper, contextWrapper, workerContext); } else { ScriptSourceCode code(m_code, workerContext->url()); scriptController->evaluate(code); } }
void ScheduledAction::execute(WorkerContext* workerContext) { // In a Worker, the execution should always happen on a worker thread. ASSERT(workerContext->thread()->threadID() == currentThread()); WorkerScriptController* scriptController = workerContext->script(); if (!m_function.IsEmpty() && m_function->IsFunction()) { v8::HandleScope handleScope; v8::Handle<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context.get()); ASSERT(!v8Context.IsEmpty()); v8::Context::Scope scope(v8Context); m_function->Call(v8Context->Global(), m_argc, m_argv); } else scriptController->evaluate(m_code); }
void WebWorkerBase::openFileSystem(WebFileSystem::Type type, long long size, WebFileSystemCallbacks* callbacks, bool synchronous) { WorkerRunLoop& runLoop = m_workerThread->runLoop(); WorkerScriptController* controller = WorkerScriptController::controllerForContext(); WorkerContext* workerContext = controller->workerContext(); // Create a unique mode for this openFileSystem call. String mode = openFileSystemMode; mode.append(String::number(runLoop.createUniqueId())); RefPtr<WorkerFileSystemCallbacksBridge> bridge = WorkerFileSystemCallbacksBridge::create(this, workerContext, callbacks); bridge->postOpenFileSystemToMainThread(commonClient(), type, size, mode); if (synchronous) { if (runLoop.runInMode(workerContext, mode) == MessageQueueTerminated) bridge->stop(); } }
void WorkerThread::workerThread() { // Propagate the mainThread's fenv to workers. #if PLATFORM(IOS) fesetenv(&mainThreadFEnv); #endif { MutexLocker lock(m_threadCreationMutex); m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, std::move(m_startupData->m_groupSettings), m_startupData->m_contentSecurityPolicy, m_startupData->m_contentSecurityPolicyType, m_startupData->m_topOrigin.release()); if (m_runLoop.terminated()) { // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, // forbidExecution() couldn't be called from stop(). m_workerGlobalScope->script()->forbidExecution(); } } WorkerScriptController* script = m_workerGlobalScope->script(); #if ENABLE(INSPECTOR) InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), m_startupData->m_startMode); #endif script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); // Free the startup data to cause its member variable deref's happen on the worker's thread (since // all ref/derefs of these objects are happening on the thread at this point). Note that // WorkerThread::~WorkerThread happens on a different thread where it was created. m_startupData.clear(); runEventLoop(); ThreadIdentifier threadID = m_threadID; ASSERT(m_workerGlobalScope->hasOneRef()); // The below assignment will destroy the context, which will in turn notify messaging proxy. // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. m_workerGlobalScope = 0; // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! threadGlobalData().destroy(); // The thread object may be already destroyed from notification now, don't try to access "this". detachThread(threadID); }
static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data) { v8::Local<v8::Promise> promise = data.GetPromise(); // Bail out if called during context initialization. v8::Isolate* isolate = promise->GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; ExecutionContext* executionContext = scriptState->executionContext(); if (!executionContext) return; ASSERT(executionContext->isWorkerGlobalScope()); WorkerScriptController* scriptController = toWorkerGlobalScope(executionContext)->script(); ASSERT(scriptController); if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) { scriptController->rejectedPromises()->handlerAdded(data); return; } ASSERT(data.GetEvent() == v8::kPromiseRejectWithNoHandler); int scriptId = 0; int lineNumber = 0; int columnNumber = 0; String resourceName; String errorMessage; v8::Local<v8::Message> message = v8::Exception::CreateMessage(data.GetValue()); if (!message.IsEmpty()) { TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin().ResourceName()); scriptId = message->GetScriptOrigin().ScriptID()->Value(); if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber) && v8Call(message->GetStartColumn(scriptState->context()), columnNumber)) ++columnNumber; // message->Get() can be empty here. https://crbug.com/450330 errorMessage = toCoreStringWithNullCheck(message->Get()); } scriptController->rejectedPromises()->rejectedWithNoHandler(scriptState, data, errorMessage, resourceName, scriptId, lineNumber, columnNumber, nullptr); }
v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, bool singleShot) { WorkerContext* workerContext = V8WorkerContext::toNative(args.Holder()); int argumentCount = args.Length(); if (argumentCount < 1) return v8::Undefined(); v8::Handle<v8::Value> function = args[0]; int32_t timeout = argumentCount >= 2 ? args[1]->Int32Value() : 0; int timerId; WorkerScriptController* script = workerContext->script(); if (!script) return v8::Undefined(); v8::Handle<v8::Context> v8Context = script->context(); if (function->IsString()) { if (ContentSecurityPolicy* policy = workerContext->contentSecurityPolicy()) { if (!policy->allowEval()) return v8Integer(0, args.GetIsolate()); } WTF::String stringFunction = toWebCoreString(function); timerId = DOMTimer::install(workerContext, adoptPtr(new ScheduledAction(v8Context, stringFunction, workerContext->url())), timeout, singleShot); } else if (function->IsFunction()) { size_t paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; v8::Local<v8::Value>* params = 0; if (paramCount > 0) { params = new v8::Local<v8::Value>[paramCount]; for (size_t i = 0; i < paramCount; ++i) params[i] = args[i+2]; } // ScheduledAction takes ownership of actual params and releases them in its destructor. OwnPtr<ScheduledAction> action = adoptPtr(new ScheduledAction(v8Context, v8::Handle<v8::Function>::Cast(function), paramCount, params)); // FIXME: We should use a OwnArrayPtr for params. delete [] params; timerId = DOMTimer::install(workerContext, action.release(), timeout, singleShot); } else return v8::Undefined(); return v8Integer(timerId, args.GetIsolate()); }
bool WebWorkerBase::allowDatabase(WebFrame*, const WebString& name, const WebString& displayName, unsigned long estimatedSize) { WorkerRunLoop& runLoop = m_workerThread->runLoop(); WorkerScriptController* controller = WorkerScriptController::controllerForContext(); WorkerContext* workerContext = controller->workerContext(); // Create a unique mode just for this synchronous call. String mode = allowDatabaseMode; mode.append(String::number(runLoop.createUniqueId())); RefPtr<AllowDatabaseMainThreadBridge> bridge = AllowDatabaseMainThreadBridge::create(this, mode, commonClient(), m_webView->mainFrame(), String(name), String(displayName), estimatedSize); // Either the bridge returns, or the queue gets terminated. if (runLoop.runInMode(workerContext, mode) == MessageQueueTerminated) { bridge->cancel(); return false; } return bridge->result(); }
v8::Local<v8::Function> V8DOMWrapper::constructorForType(WrapperTypeInfo* type, WorkerContext*) { WorkerScriptController* controller = WorkerScriptController::controllerForContext(); WorkerContextExecutionProxy* proxy = controller ? controller->proxy() : 0; return proxy ? proxy->perContextData()->constructorForType(type) : v8::Local<v8::Function>(); }
V8BindingPerContextData* V8DOMWrapper::perContextData(WorkerContext*) { WorkerScriptController* controller = WorkerScriptController::controllerForContext(); WorkerContextExecutionProxy* proxy = controller ? controller->proxy() : 0; return proxy ? proxy->perContextData() : 0; }