diff options
Diffstat (limited to 'WebCore/bindings/v8/WorkerContextExecutionProxy.cpp')
-rw-r--r-- | WebCore/bindings/v8/WorkerContextExecutionProxy.cpp | 205 |
1 files changed, 112 insertions, 93 deletions
diff --git a/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp b/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp index c87cdea..f80d88f 100644 --- a/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp +++ b/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp @@ -35,9 +35,16 @@ #include "WorkerContextExecutionProxy.h" +#include "DOMCoreException.h" +#include "DedicatedWorkerContext.h" +#include "Event.h" +#include "EventException.h" +#include "MessagePort.h" +#include "RangeException.h" #include "V8Binding.h" +#include "V8DOMMap.h" +#include "V8Index.h" #include "V8Proxy.h" -#include "Event.h" #include "V8WorkerContextEventListener.h" #include "V8WorkerContextObjectEventListener.h" #include "Worker.h" @@ -45,48 +52,17 @@ #include "WorkerLocation.h" #include "WorkerNavigator.h" #include "WorkerScriptController.h" +#include "XMLHttpRequest.h" +#include "XMLHttpRequestException.h" namespace WebCore { -static bool isWorkersEnabled = false; - static void reportFatalErrorInV8(const char* location, const char* message) { // FIXME: We temporarily deal with V8 internal error situations such as out-of-memory by crashing the worker. CRASH(); } -static void handleConsoleMessage(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) -{ - WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); - if (!proxy) - return; - - WorkerContext* workerContext = proxy->workerContext(); - if (!workerContext) - return; - - v8::Handle<v8::String> errorMessageString = message->Get(); - ASSERT(!errorMessageString.IsEmpty()); - String errorMessage = ToWebCoreString(errorMessageString); - - v8::Handle<v8::Value> resourceName = message->GetScriptResourceName(); - bool useURL = (resourceName.IsEmpty() || !resourceName->IsString()); - String resourceNameString = useURL ? workerContext->url() : ToWebCoreString(resourceName); - - workerContext->addMessage(ConsoleDestination, JSMessageSource, ErrorMessageLevel, errorMessage, message->GetLineNumber(), resourceNameString); -} - -bool WorkerContextExecutionProxy::isWebWorkersEnabled() -{ - return isWorkersEnabled; -} - -void WorkerContextExecutionProxy::setIsWebWorkersEnabled(bool value) -{ - isWorkersEnabled = value; -} - WorkerContextExecutionProxy::WorkerContextExecutionProxy(WorkerContext* workerContext) : m_workerContext(workerContext) , m_recursion(0) @@ -102,8 +78,7 @@ WorkerContextExecutionProxy::~WorkerContextExecutionProxy() void WorkerContextExecutionProxy::dispose() { // Disconnect all event listeners. - if (m_listeners.get()) - { + if (m_listeners.get()) { for (V8EventListenerList::iterator iterator(m_listeners->begin()); iterator != m_listeners->end(); ++iterator) static_cast<V8WorkerContextEventListener*>(*iterator)->disconnect(); @@ -127,13 +102,16 @@ void WorkerContextExecutionProxy::dispose() WorkerContextExecutionProxy* WorkerContextExecutionProxy::retrieve() { + // Happens on frame destruction, check otherwise GetCurrent() will crash. + if (!v8::Context::InContext()) + return 0; v8::Handle<v8::Context> context = v8::Context::GetCurrent(); v8::Handle<v8::Object> global = context->Global(); - global = V8Proxy::LookupDOMWrapper(V8ClassIndex::WORKERCONTEXT, global); + global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::WORKERCONTEXT, global); // Return 0 if the current executing context is not the worker context. if (global.IsEmpty()) return 0; - WorkerContext* workerContext = V8Proxy::ToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, global); + WorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, global); return workerContext->script()->proxy(); } @@ -149,6 +127,7 @@ void WorkerContextExecutionProxy::initV8IfNeeded() v8::V8::IgnoreOutOfMemoryException(); v8::V8::SetFatalErrorHandler(reportFatalErrorInV8); +#ifdef MANUAL_MERGE_REQUIRED // Set up the handler for V8 error message. v8::V8::AddMessageListener(handleConsoleMessage); @@ -156,6 +135,8 @@ void WorkerContextExecutionProxy::initV8IfNeeded() const int workerThreadPreemptionIntervalMs = 5; v8::Locker::StartPreemption(workerThreadPreemptionIntervalMs); #endif +#else // MANUAL_MERGE_REQUIRED +#endif // MANUAL_MERGE_REQUIRED v8Initialized = true; } @@ -177,7 +158,7 @@ void WorkerContextExecutionProxy::initContextIfNeeded() v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); // Create a new JS object and use it as the prototype for the shadow global object. - v8::Handle<v8::Function> workerContextConstructor = GetConstructor(V8ClassIndex::WORKERCONTEXT); + v8::Handle<v8::Function> workerContextConstructor = V8DOMWrapper::getConstructorForContext(V8ClassIndex::DEDICATEDWORKERCONTEXT, context); v8::Local<v8::Object> jsWorkerContext = SafeAllocation::newInstance(workerContextConstructor); // Bail out if allocation failed. if (jsWorkerContext.IsEmpty()) { @@ -186,9 +167,9 @@ void WorkerContextExecutionProxy::initContextIfNeeded() } // Wrap the object. - V8Proxy::SetDOMWrapper(jsWorkerContext, V8ClassIndex::ToInt(V8ClassIndex::WORKERCONTEXT), m_workerContext); + V8DOMWrapper::setDOMWrapper(jsWorkerContext, V8ClassIndex::ToInt(V8ClassIndex::DEDICATEDWORKERCONTEXT), m_workerContext); - V8Proxy::SetJSWrapperForDOMObject(m_workerContext, v8::Persistent<v8::Object>::New(jsWorkerContext)); + V8DOMWrapper::setJSWrapperForDOMObject(m_workerContext, v8::Persistent<v8::Object>::New(jsWorkerContext)); m_workerContext->ref(); // Insert the object instance as the prototype of the shadow object. @@ -198,45 +179,47 @@ void WorkerContextExecutionProxy::initContextIfNeeded() m_listeners.set(new V8EventListenerList()); } -v8::Local<v8::Function> WorkerContextExecutionProxy::GetConstructor(V8ClassIndex::V8WrapperType type) -{ - // Enter the context of the proxy to make sure that the function is - // constructed in the context corresponding to this proxy. - v8::Context::Scope scope(m_context); - v8::Handle<v8::FunctionTemplate> functionTemplate = V8Proxy::GetTemplate(type); - - // Getting the function might fail if we're running out of stack or memory. - v8::TryCatch tryCatch; - v8::Local<v8::Function> value = functionTemplate->GetFunction(); - if (value.IsEmpty()) - return v8::Local<v8::Function>(); - - return value; -} - -v8::Handle<v8::Value> WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::V8WrapperType type, void* impl) +v8::Handle<v8::Value> WorkerContextExecutionProxy::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl) { if (!impl) return v8::Null(); - if (type == V8ClassIndex::WORKERCONTEXT) - return WorkerContextToV8Object(static_cast<WorkerContext*>(impl)); + if (type == V8ClassIndex::DEDICATEDWORKERCONTEXT) + return convertWorkerContextToV8Object(static_cast<WorkerContext*>(impl)); + + bool isActiveDomObject = false; + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: + ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + isActiveDomObject = true; + break; +#undef MAKE_CASE + default: + break; + } - if (type == V8ClassIndex::WORKER) { + if (isActiveDomObject) { v8::Persistent<v8::Object> result = getActiveDOMObjectMap().get(impl); if (!result.IsEmpty()) return result; v8::Local<v8::Object> object = toV8(type, type, impl); - if (!object.IsEmpty()) - static_cast<Worker*>(impl)->ref(); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(impl)->ref(); break; + ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT_NOT_REACHED(); + } + result = v8::Persistent<v8::Object>::New(object); - V8Proxy::SetJSWrapperForDOMObject(impl, result); + V8DOMWrapper::setJSWrapperForActiveDOMObject(impl, result); return result; } // Non DOM node - v8::Persistent<v8::Object> result = domObjectMap().get(impl); + v8::Persistent<v8::Object> result = getDOMObjectMap().get(impl); if (result.IsEmpty()) { v8::Local<v8::Object> object = toV8(type, type, impl); if (!object.IsEmpty()) { @@ -247,22 +230,34 @@ v8::Handle<v8::Value> WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::V8Wr case V8ClassIndex::WORKERNAVIGATOR: static_cast<WorkerNavigator*>(impl)->ref(); break; + case V8ClassIndex::DOMCOREEXCEPTION: + static_cast<DOMCoreException*>(impl)->ref(); + break; + case V8ClassIndex::RANGEEXCEPTION: + static_cast<RangeException*>(impl)->ref(); + break; + case V8ClassIndex::EVENTEXCEPTION: + static_cast<EventException*>(impl)->ref(); + break; + case V8ClassIndex::XMLHTTPREQUESTEXCEPTION: + static_cast<XMLHttpRequestException*>(impl)->ref(); + break; default: ASSERT(false); } result = v8::Persistent<v8::Object>::New(object); - V8Proxy::SetJSWrapperForDOMObject(impl, result); + V8DOMWrapper::setJSWrapperForDOMObject(impl, result); } } return result; } -v8::Handle<v8::Value> WorkerContextExecutionProxy::EventToV8Object(Event* event) +v8::Handle<v8::Value> WorkerContextExecutionProxy::convertEventToV8Object(Event* event) { if (!event) return v8::Null(); - v8::Handle<v8::Object> wrapper = domObjectMap().get(event); + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event); if (!wrapper.IsEmpty()) return wrapper; @@ -274,73 +269,79 @@ v8::Handle<v8::Value> WorkerContextExecutionProxy::EventToV8Object(Event* event) v8::Handle<v8::Object> result = toV8(type, V8ClassIndex::EVENT, event); if (result.IsEmpty()) { // Instantiation failed. Avoid updating the DOM object map and return null which - // is already handled by callers of this function in case the event is NULL. + // is already handled by callers of this function in case the event is null. return v8::Null(); } event->ref(); // fast ref - V8Proxy::SetJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result)); + V8DOMWrapper::setJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result)); return result; } -// A JS object of type EventTarget in the worker context can only be Worker or WorkerContext. -v8::Handle<v8::Value> WorkerContextExecutionProxy::EventTargetToV8Object(EventTarget* target) +v8::Handle<v8::Value> WorkerContextExecutionProxy::convertEventTargetToV8Object(EventTarget* target) { if (!target) return v8::Null(); - WorkerContext* workerContext = target->toWorkerContext(); + DedicatedWorkerContext* workerContext = target->toDedicatedWorkerContext(); if (workerContext) - return WorkerContextToV8Object(workerContext); + return convertWorkerContextToV8Object(workerContext); Worker* worker = target->toWorker(); if (worker) - return ToV8Object(V8ClassIndex::WORKER, worker); + return convertToV8Object(V8ClassIndex::WORKER, worker); + + XMLHttpRequest* xhr = target->toXMLHttpRequest(); + if (xhr) + return convertToV8Object(V8ClassIndex::XMLHTTPREQUEST, xhr); + + MessagePort* mp = target->toMessagePort(); + if (mp) + return convertToV8Object(V8ClassIndex::MESSAGEPORT, mp); ASSERT_NOT_REACHED(); return v8::Handle<v8::Value>(); } -v8::Handle<v8::Value> WorkerContextExecutionProxy::WorkerContextToV8Object(WorkerContext* workerContext) +v8::Handle<v8::Value> WorkerContextExecutionProxy::convertWorkerContextToV8Object(WorkerContext* workerContext) { if (!workerContext) return v8::Null(); - v8::Handle<v8::Context> context = workerContext->script()->proxy()->GetContext(); + v8::Handle<v8::Context> context = workerContext->script()->proxy()->context(); v8::Handle<v8::Object> global = context->Global(); ASSERT(!global.IsEmpty()); return global; } -v8::Local<v8::Object> WorkerContextExecutionProxy::toV8(V8ClassIndex::V8WrapperType descType, V8ClassIndex::V8WrapperType cptrType, void* impl) +v8::Local<v8::Object> WorkerContextExecutionProxy::toV8(V8ClassIndex::V8WrapperType descriptorType, V8ClassIndex::V8WrapperType cptrType, void* impl) { v8::Local<v8::Function> function; WorkerContextExecutionProxy* proxy = retrieve(); if (proxy) - function = proxy->GetConstructor(descType); + function = V8DOMWrapper::getConstructor(descriptorType, proxy->workerContext()); else - function = V8Proxy::GetTemplate(descType)->GetFunction(); + function = V8DOMWrapper::getTemplate(descriptorType)->GetFunction(); v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); - if (!instance.IsEmpty()) { + if (!instance.IsEmpty()) // Avoid setting the DOM wrapper for failed allocations. - V8Proxy::SetDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl); - } + V8DOMWrapper::setDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl); return instance; } bool WorkerContextExecutionProxy::forgetV8EventObject(Event* event) { - if (domObjectMap().contains(event)) { - domObjectMap().forget(event); + if (getDOMObjectMap().contains(event)) { + getDOMObjectMap().forget(event); return true; - } else - return false; + } + return false; } -v8::Local<v8::Value> WorkerContextExecutionProxy::evaluate(const String& script, const String& fileName, int baseLine) +ScriptValue WorkerContextExecutionProxy::evaluate(const String& script, const String& fileName, int baseLine, WorkerContextExecutionState* state) { LOCK_V8; v8::HandleScope hs; @@ -348,9 +349,27 @@ v8::Local<v8::Value> WorkerContextExecutionProxy::evaluate(const String& script, initContextIfNeeded(); v8::Context::Scope scope(m_context); + v8::TryCatch exceptionCatcher; + v8::Local<v8::String> scriptString = v8ExternalString(script); - v8::Handle<v8::Script> compiledScript = V8Proxy::CompileScript(scriptString, fileName, baseLine); - return runScript(compiledScript); + v8::Handle<v8::Script> compiledScript = V8Proxy::compileScript(scriptString, fileName, baseLine); + v8::Local<v8::Value> result = runScript(compiledScript); + + if (exceptionCatcher.HasCaught()) { + v8::Local<v8::Message> message = exceptionCatcher.Message(); + state->hadException = true; + state->exception = ScriptValue(exceptionCatcher.Exception()); + state->errorMessage = toWebCoreString(message->Get()); + state->lineNumber = message->GetLineNumber(); + state->sourceURL = toWebCoreString(message->GetScriptResourceName()); + exceptionCatcher.Reset(); + } else + state->hadException = false; + + if (result.IsEmpty() || result->IsUndefined()) + return ScriptValue(); + + return ScriptValue(result); } v8::Local<v8::Value> WorkerContextExecutionProxy::runScript(v8::Handle<v8::Script> script) @@ -361,10 +380,10 @@ v8::Local<v8::Value> WorkerContextExecutionProxy::runScript(v8::Handle<v8::Scrip // Compute the source string and prevent against infinite recursion. if (m_recursion >= kMaxRecursionDepth) { v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')"); - script = V8Proxy::CompileScript(code, "", 0); + script = V8Proxy::compileScript(code, "", 0); } - if (V8Proxy::HandleOutOfMemory()) + if (V8Proxy::handleOutOfMemory()) ASSERT(script.IsEmpty()); if (script.IsEmpty()) @@ -416,7 +435,7 @@ PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateObjectEvent return findOrCreateEventListenerHelper(object, isInline, findOnly, true); } -void WorkerContextExecutionProxy::RemoveEventListener(V8EventListener* listener) +void WorkerContextExecutionProxy::removeEventListener(V8EventListener* listener) { m_listeners->remove(listener); } |