summaryrefslogtreecommitdiffstats
path: root/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
diff options
context:
space:
mode:
authorjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-09 19:16:29 +0000
committerjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-09 19:16:29 +0000
commita6309f8198825442d77f0fc9aa70c82ae5dd6d04 (patch)
tree1ff2b6257184f746d15a1c4cdd91d41e038af3bc /webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
parenteb6c8c24620c8f9f8afd3523cac74f03df0cfe52 (diff)
downloadchromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.zip
chromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.tar.gz
chromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.tar.bz2
More v8 bindings work to support executing worker and handling events in its worker context.
For now, we still execute the worker script in the same renderer process with v8 locker. It will be rerouted once we have worker process ready. Review URL: http://codereview.chromium.org/18821 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9399 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp')
-rw-r--r--webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp358
1 files changed, 358 insertions, 0 deletions
diff --git a/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp b/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
new file mode 100644
index 0000000..496dce3
--- /dev/null
+++ b/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
@@ -0,0 +1,358 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+
+#if ENABLE(WORKERS)
+
+#include "WorkerContextExecutionProxy.h"
+
+#include "v8_binding.h"
+#include "v8_events.h"
+#include "v8_index.h"
+#include "v8_proxy.h"
+#include "WorkerContext.h"
+#include "WorkerLocation.h"
+#include "WorkerNavigator.h"
+#include "WorkerScriptController.h"
+
+namespace WebCore {
+
+WorkerContextExecutionProxy::WorkerContextExecutionProxy(
+ WorkerContext* workerContext)
+ : m_workerContext(workerContext),
+ m_recursion(0) {
+}
+
+WorkerContextExecutionProxy::~WorkerContextExecutionProxy() {
+ Dispose();
+}
+
+void WorkerContextExecutionProxy::Dispose() {
+ // Disconnect all event listeners.
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ static_cast<V8WorkerContextEventListener*>(*iter)->disconnect();
+ }
+ m_listeners.clear();
+
+ // Detach all events from their JS wrappers.
+ for (EventSet::iterator iter = m_events.begin();
+ iter != m_events.end();
+ ++iter) {
+ Event* event = *iter;
+ if (ForgetV8EventObject(event)) {
+ event->deref();
+ }
+ }
+ m_events.clear();
+
+ // Dispose the context.
+ if (!m_context.IsEmpty()) {
+ m_context.Dispose();
+ m_context.Clear();
+ }
+}
+
+WorkerContextExecutionProxy* WorkerContextExecutionProxy::retrieve() {
+ v8::Handle<v8::Context> context = v8::Context::GetCurrent();
+ v8::Handle<v8::Object> global = context->Global();
+ global = V8Proxy::LookupDOMWrapper(V8ClassIndex::WORKERCONTEXT, global);
+ ASSERT(!global.IsEmpty());
+ WorkerContext* worker_context =
+ V8Proxy::ToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT,
+ global);
+ return worker_context->script()->proxy();
+}
+
+void WorkerContextExecutionProxy::InitContextIfNeeded() {
+ // Bail out if the context has already been initialized.
+ if (!m_context.IsEmpty()) {
+ return;
+ }
+
+ // Create a new environment
+ v8::Persistent<v8::ObjectTemplate> global_template;
+ m_context = v8::Context::New(NULL, global_template);
+
+ // Starting from now, use local context only.
+ v8::Local<v8::Context> context = v8::Local<v8::Context>::New(m_context);
+ v8::Context::Scope scope(context);
+
+ // Allocate strings used during initialization.
+ v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__");
+
+ // Create a new JS object and use it as the prototype for the
+ // shadow global object.
+ v8::Handle<v8::Function> worker_context_constructor =
+ GetConstructor(V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Object> js_worker_context =
+ SafeAllocation::NewInstance(worker_context_constructor);
+ // Bail out if allocation failed.
+ if (js_worker_context.IsEmpty()) {
+ Dispose();
+ return;
+ }
+
+ // Wrap the object.
+ V8Proxy::SetDOMWrapper(js_worker_context,
+ V8ClassIndex::ToInt(V8ClassIndex::WORKERCONTEXT),
+ m_workerContext);
+
+ V8Proxy::SetJSWrapperForDOMObject(m_workerContext,
+ v8::Persistent<v8::Object>::New(js_worker_context));
+
+ // Insert the object instance as the prototype of the shadow object.
+ v8::Handle<v8::Object> v8_global = m_context->Global();
+ v8_global->Set(implicit_proto_string, js_worker_context);
+}
+
+v8::Local<v8::Function> WorkerContextExecutionProxy::GetConstructor(
+ V8ClassIndex::V8WrapperType t) {
+ // 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> templ = V8Proxy::GetTemplate(t);
+
+ // Getting the function might fail if we're running out of
+ // stack or memory.
+ v8::TryCatch try_catch;
+ v8::Local<v8::Function> value = templ->GetFunction();
+ if (value.IsEmpty()) {
+ return v8::Local<v8::Function>();
+ }
+
+ return value;
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::ToV8Object(
+ V8ClassIndex::V8WrapperType type, void* imp) {
+ if (!imp) return v8::Null();
+
+ // Non DOM node
+ v8::Persistent<v8::Object> result = GetDOMObjectMap().get(imp);
+ if (result.IsEmpty()) {
+ v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp);
+ if (!v8obj.IsEmpty()) {
+ // Go through big switch statement, it has some duplications
+ // that were handled by code above (such as CSSVALUE, CSSRULE, etc).
+ switch (type) {
+ case V8ClassIndex::WORKERLOCATION:
+ static_cast<WorkerLocation*>(imp)->ref();
+ break;
+ case V8ClassIndex::WORKERNAVIGATOR:
+ static_cast<WorkerNavigator*>(imp)->ref();
+ break;
+ default:
+ ASSERT(false);
+ }
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ V8Proxy::SetJSWrapperForDOMObject(imp, result);
+ }
+ }
+ return result;
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::EventToV8Object(
+ Event* event) {
+ if (!event)
+ return v8::Null();
+
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(event);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT;
+
+ if (event->isMessageEvent())
+ type = V8ClassIndex::MESSAGEEVENT;
+
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(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.
+ return v8::Null();
+ }
+
+ event->ref(); // fast ref
+ V8Proxy::SetJSWrapperForDOMObject(
+ event, v8::Persistent<v8::Object>::New(result));
+
+ return result;
+}
+
+// A JS object of type EventTarget in the worker context can only be
+// WorkerContext.
+v8::Handle<v8::Value> WorkerContextExecutionProxy::EventTargetToV8Object(
+ EventTarget* target) {
+ if (!target)
+ return v8::Null();
+
+ WorkerContext* worker_context = target->toWorkerContext();
+ if (worker_context)
+ return WorkerContextToV8Object(worker_context);
+
+ ASSERT(0);
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::WorkerContextToV8Object(
+ WorkerContext* worker_context) {
+ if (!worker_context) return v8::Null();
+
+ v8::Handle<v8::Context> context =
+ worker_context->script()->proxy()->GetContext();
+
+ v8::Handle<v8::Object> global = context->Global();
+ ASSERT(!global.IsEmpty());
+ return global;
+}
+
+v8::Local<v8::Object> WorkerContextExecutionProxy::InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_type,
+ void* imp) {
+ v8::Local<v8::Function> function;
+ WorkerContextExecutionProxy* proxy = retrieve();
+ if (proxy) {
+ function = proxy->GetConstructor(desc_type);
+ } else {
+ function = V8Proxy::GetTemplate(desc_type)->GetFunction();
+ }
+ v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function);
+ if (!instance.IsEmpty()) {
+ // Avoid setting the DOM wrapper for failed allocations.
+ V8Proxy::SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp);
+ }
+ return instance;
+}
+
+bool WorkerContextExecutionProxy::ForgetV8EventObject(Event* event) {
+ if (GetDOMObjectMap().contains(event)) {
+ GetDOMObjectMap().forget(event);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+v8::Local<v8::Value> WorkerContextExecutionProxy::Evaluate(
+ const String& str, const String& file_name, int base_line) {
+ v8::HandleScope hs;
+
+ InitContextIfNeeded();
+ v8::Context::Scope scope(m_context);
+
+ v8::Local<v8::String> code = v8ExternalString(str);
+ v8::Handle<v8::Script> script = V8Proxy::CompileScript(code,
+ file_name,
+ base_line);
+ return RunScript(script);
+}
+
+v8::Local<v8::Value> WorkerContextExecutionProxy::RunScript(
+ v8::Handle<v8::Script> script) {
+ if (script.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // 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);
+ }
+
+ if (V8Proxy::HandleOutOfMemory())
+ ASSERT(script.IsEmpty());
+
+ if (script.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // Run the script and keep track of the current recursion depth.
+ v8::Local<v8::Value> result;
+ {
+ m_recursion++;
+ result = script->Run();
+ m_recursion--;
+ }
+
+ // Handle V8 internal error situation (Out-of-memory).
+ if (result.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ return result;
+}
+
+PassRefPtr<V8EventListener>
+WorkerContextExecutionProxy::FindOrCreateEventListener(
+ v8::Local<v8::Value> obj, bool is_inline, bool find_only) {
+ if (!obj->IsObject())
+ return 0;
+
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ V8EventListener* el = *iter;
+ if (el->isInline() == is_inline && el->GetListenerObject() == obj)
+ return el;
+ }
+ if (find_only)
+ return NULL;
+
+ // Create a new one, and add to cache.
+ RefPtr<V8EventListener> listener = V8WorkerContextEventListener::create(
+ this, v8::Local<v8::Object>::Cast(obj), is_inline);
+ m_listeners.push_back(listener.get());
+
+ return listener.release();
+}
+
+void WorkerContextExecutionProxy::RemoveEventListener(
+ V8EventListener* listener) {
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ if (*iter == listener) {
+ m_listeners.erase(iter);
+ return;
+ }
+ }
+}
+
+void WorkerContextExecutionProxy::TrackEvent(Event* event) {
+ m_events.add(event);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)