summaryrefslogtreecommitdiffstats
path: root/webkit/port/bindings/v8
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/port/bindings/v8')
-rw-r--r--webkit/port/bindings/v8/ScheduledAction.h1
-rw-r--r--webkit/port/bindings/v8/V8MessagePortCustom.cpp2
-rw-r--r--webkit/port/bindings/v8/V8WorkerContextCustom.cpp224
-rw-r--r--webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp358
-rw-r--r--webkit/port/bindings/v8/WorkerContextExecutionProxy.h119
-rw-r--r--webkit/port/bindings/v8/WorkerScriptController.cpp62
-rw-r--r--webkit/port/bindings/v8/WorkerScriptController.h10
-rw-r--r--webkit/port/bindings/v8/v8_custom.h14
-rw-r--r--webkit/port/bindings/v8/v8_events.cpp134
-rw-r--r--webkit/port/bindings/v8/v8_events.h57
-rw-r--r--webkit/port/bindings/v8/v8_index.cpp2
-rw-r--r--webkit/port/bindings/v8/v8_index.h4
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp92
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h5
14 files changed, 974 insertions, 110 deletions
diff --git a/webkit/port/bindings/v8/ScheduledAction.h b/webkit/port/bindings/v8/ScheduledAction.h
index ea4be9b..19b2ec0 100644
--- a/webkit/port/bindings/v8/ScheduledAction.h
+++ b/webkit/port/bindings/v8/ScheduledAction.h
@@ -13,6 +13,7 @@ class ScheduledAction {
public:
virtual ~ScheduledAction() { }
virtual void execute(DOMWindow* window) = 0;
+ virtual void execute(ScriptExecutionContext*) {}
};
}
diff --git a/webkit/port/bindings/v8/V8MessagePortCustom.cpp b/webkit/port/bindings/v8/V8MessagePortCustom.cpp
index 0025046..81948f8 100644
--- a/webkit/port/bindings/v8/V8MessagePortCustom.cpp
+++ b/webkit/port/bindings/v8/V8MessagePortCustom.cpp
@@ -54,7 +54,7 @@ static void CreateHiddenDependency(v8::Local<v8::Object> object,
v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex);
if (cache->IsNull() || cache->IsUndefined()) {
cache = v8::Array::New();
- object->SetInternalField(V8Custom::kXMLHttpRequestCacheIndex, cache);
+ object->SetInternalField(V8Custom::kMessagePortRequestCacheIndex, cache);
}
v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
diff --git a/webkit/port/bindings/v8/V8WorkerContextCustom.cpp b/webkit/port/bindings/v8/V8WorkerContextCustom.cpp
new file mode 100644
index 0000000..d3c1c3a
--- /dev/null
+++ b/webkit/port/bindings/v8/V8WorkerContextCustom.cpp
@@ -0,0 +1,224 @@
+// 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 "v8_binding.h"
+#include "v8_custom.h"
+#include "v8_events.h"
+#include "v8_proxy.h"
+#include "WorkerContextExecutionProxy.h"
+
+#include "V8Document.h"
+#include "V8HTMLDocument.h"
+
+#include "ExceptionCode.h"
+#include "MessagePort.h"
+#include "WorkerContext.h"
+
+namespace WebCore {
+
+// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency
+
+// Use an array to hold dependents. It works like a ref-counted scheme.
+// A value can be added more than once to the xhr object.
+static void CreateHiddenDependency(v8::Local<v8::Object> object,
+ v8::Local<v8::Value> value) {
+ ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Value> cache =
+ object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex);
+ if (cache->IsNull() || cache->IsUndefined()) {
+ cache = v8::Array::New();
+ object->SetInternalField(V8Custom::kWorkerContextRequestCacheIndex, cache);
+ }
+
+ v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
+ cache_array->Set(v8::Integer::New(cache_array->Length()), value);
+}
+
+static void RemoveHiddenDependency(v8::Local<v8::Object> object,
+ v8::Local<v8::Value> value) {
+ ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Value> cache =
+ object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex);
+ ASSERT(cache->IsArray());
+ v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
+ for (int i = cache_array->Length() - 1; i >= 0; i--) {
+ v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i));
+ if (cached->StrictEquals(value)) {
+ cache_array->Delete(i);
+ return;
+ }
+ }
+
+ // We should only get here if we try to remove an event listener that was
+ // never added.
+}
+
+ACCESSOR_GETTER(WorkerContextSelf) {
+ INC_STATS(L"DOM.WorkerContext.self._get");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::WORKERCONTEXT, imp);
+}
+
+ACCESSOR_GETTER(WorkerContextOnmessage) {
+ INC_STATS(L"DOM.WorkerContext.onmessage._get");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ if (imp->onmessage()) {
+ V8WorkerContextEventListener* listener =
+ static_cast<V8WorkerContextEventListener*>(imp->onmessage());
+ v8::Local<v8::Object> v8_listener = listener->GetListenerObject();
+ return v8_listener;
+ }
+ return v8::Undefined();
+}
+
+ACCESSOR_SETTER(WorkerContextOnmessage) {
+ INC_STATS(L"DOM.WorkerContext.onmessage._set");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ V8WorkerContextEventListener* old_listener =
+ static_cast<V8WorkerContextEventListener*>(imp->onmessage());
+ if (value->IsNull()) {
+ if (imp->onmessage()) {
+ v8::Local<v8::Object> old_v8_listener = old_listener->GetListenerObject();
+ RemoveHiddenDependency(info.Holder(), old_v8_listener);
+ }
+
+ // Clear the listener
+ imp->setOnmessage(0);
+
+ } else {
+ RefPtr<V8EventListener> listener =
+ imp->script()->proxy()->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(value), false, false);
+ if (listener) {
+ if (old_listener) {
+ v8::Local<v8::Object> old_v8_listener =
+ old_listener->GetListenerObject();
+ RemoveHiddenDependency(info.Holder(), old_v8_listener);
+ }
+
+ imp->setOnmessage(listener);
+ CreateHiddenDependency(info.Holder(), value);
+ }
+ }
+}
+
+v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args,
+ bool singleShot) {
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ int delay = ToInt32(args[1]);
+
+ notImplemented();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> ClearTimeoutOrInterval(const v8::Arguments& args) {
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ bool ok = false;
+ int tid = ToInt32(args[0], ok);
+ if (ok) {
+ imp->removeTimeout(tid);
+ }
+
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(WorkerContextSetTimeout) {
+ INC_STATS(L"DOM.WorkerContext.setTimeout()");
+ return SetTimeoutOrInterval(args, true);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextClearTimeout) {
+ INC_STATS(L"DOM.WorkerContext.clearTimeout()");
+ return ClearTimeoutOrInterval(args);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextSetInterval) {
+ INC_STATS(L"DOM.WorkerContext.setInterval()");
+ return SetTimeoutOrInterval(args, false);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextClearInterval) {
+ INC_STATS(L"DOM.WorkerContext.clearInterval()");
+ return ClearTimeoutOrInterval(args);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextAddEventListener) {
+ INC_STATS(L"DOM.WorkerContext.addEventListener()");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ RefPtr<V8EventListener> listener =
+ imp->script()->proxy()->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(args[1]), false, false);
+
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ imp->addEventListener(type, listener, useCapture);
+
+ CreateHiddenDependency(args.Holder(), args[1]);
+ }
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) {
+ INC_STATS(L"DOM.WorkerContext.removeEventListener()");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+ WorkerContextExecutionProxy* proxy = imp->script()->proxy();
+
+ RefPtr<V8EventListener> listener = proxy->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(args[1]), false, true);
+
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ imp->removeEventListener(type, listener.get(), useCapture);
+
+ RemoveHiddenDependency(args.Holder(), args[1]);
+ }
+
+ return v8::Undefined();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
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)
diff --git a/webkit/port/bindings/v8/WorkerContextExecutionProxy.h b/webkit/port/bindings/v8/WorkerContextExecutionProxy.h
new file mode 100644
index 0000000..ac9fcfd
--- /dev/null
+++ b/webkit/port/bindings/v8/WorkerContextExecutionProxy.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef WorkerContextExecutionProxy_h_
+#define WorkerContextExecutionProxy_h_
+
+#if ENABLE(WORKERS)
+
+#include <list>
+#include <wtf/HashSet.h>
+#include "v8.h"
+#include "v8_index.h"
+
+namespace WebCore {
+
+class Event;
+class V8EventListener;
+class WorkerContext;
+
+class WorkerContextExecutionProxy {
+ public:
+ WorkerContextExecutionProxy(WorkerContext*);
+ ~WorkerContextExecutionProxy();
+
+ // Returns a local handle of the context.
+ v8::Local<v8::Context> GetContext() {
+ return v8::Local<v8::Context>::New(m_context);
+ }
+
+ // Returns the dom constructor function for the given node type.
+ v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType t);
+
+ // Finds or creates an event listener;
+ PassRefPtr<V8EventListener> FindOrCreateEventListener(
+ v8::Local<v8::Value> listener, bool is_inline, bool find_only);
+
+ // Removes an event listener;
+ void RemoveEventListener(V8EventListener* listener);
+
+ // Track the event so that we can detach it from the JS wrapper when a worker
+ // terminates. This is needed because we need to be able to dispose these
+ // events and releases references to their event targets: WorkerContext.
+ void TrackEvent(Event* event);
+
+ // Evaluate a script file in the current execution environment.
+ v8::Local<v8::Value> Evaluate(const String& str,
+ const String& file_name,
+ int base_line);
+
+ // Returns WorkerContext object.
+ WorkerContext* worker_context() { return m_workerContext; }
+
+ // Returns WorkerContextExecutionProxy object of the currently executing
+ // context.
+ static WorkerContextExecutionProxy* retrieve();
+
+ // Returns the JS wrapper of object.
+ static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type,
+ void* imp);
+ static v8::Handle<v8::Value> EventToV8Object(Event* event);
+ static v8::Handle<v8::Value> EventTargetToV8Object(EventTarget* target);
+ static v8::Handle<v8::Value> WorkerContextToV8Object(WorkerContext* wc);
+
+ private:
+ void InitContextIfNeeded();
+ void Dispose();
+
+ // Run an already compiled script.
+ v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script);
+
+ static v8::Local<v8::Object> InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_type,
+ void* impl);
+
+ static bool ForgetV8EventObject(Event* event);
+
+ WorkerContext* m_workerContext;
+ v8::Persistent<v8::Context> m_context;
+ int m_recursion;
+
+ typedef std::list<V8EventListener*> EventListenerList;
+ EventListenerList m_listeners;
+
+ typedef HashSet<Event*> EventSet;
+ EventSet m_events;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
+
+#endif // WorkerContextExecutionProxy_h_
diff --git a/webkit/port/bindings/v8/WorkerScriptController.cpp b/webkit/port/bindings/v8/WorkerScriptController.cpp
index 967a2d2..a897bb2 100644
--- a/webkit/port/bindings/v8/WorkerScriptController.cpp
+++ b/webkit/port/bindings/v8/WorkerScriptController.cpp
@@ -35,52 +35,23 @@
#include "ScriptSourceCode.h"
#include "ScriptValue.h"
-#include "v8_proxy.h"
#include "DOMTimer.h"
#include "WorkerContext.h"
+#include "WorkerContextExecutionProxy.h"
#include "WorkerMessagingProxy.h"
#include "WorkerThread.h"
namespace WebCore {
-// TODO(dimich): Move these stubs once they're implemented.
-int DOMTimer::install(ScriptExecutionContext*, ScheduledAction*, int timeout,
- bool singleShot) {
- return 0;
-}
-void DOMTimer::removeById(ScriptExecutionContext*, int timeoutId) {
-}
-
WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
: m_workerContext(workerContext)
+ , m_proxy(new WorkerContextExecutionProxy(workerContext))
, m_executionForbidden(false)
{
}
WorkerScriptController::~WorkerScriptController()
{
- Dispose();
-}
-
-void WorkerScriptController::Dispose()
-{
- if (!m_context.IsEmpty()) {
- m_context.Dispose();
- m_context.Clear();
- }
-}
-
-void WorkerScriptController::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);
-
- // TODO (jianli): to initialize the context.
}
ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
@@ -91,32 +62,15 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
return ScriptValue();
}
- v8::Local<v8::Value> result;
- {
- v8::Locker locker;
- v8::HandleScope hs;
-
- InitContextIfNeeded();
- v8::Context::Scope scope(m_context);
-
- v8::Local<v8::String> code = v8ExternalString(sourceCode.source());
- v8::Handle<v8::Script> script =
- V8Proxy::CompileScript(code,
- sourceCode.url().string(),
- sourceCode.startLine() - 1);
-
- // TODO (jianli): handle infinite recursion.
-
- result = script->Run();
-
- if (V8Proxy::HandleOutOfMemory())
- return ScriptValue();
- }
+ v8::Local<v8::Value> result =
+ m_proxy->Evaluate(sourceCode.source(),
+ sourceCode.url().string(),
+ sourceCode.startLine() - 1);
m_workerContext->thread()->messagingProxy()->
reportWorkerThreadActivity(m_workerContext->hasPendingActivity());
- return ScriptValue(result);
+ return ScriptValue();
}
void WorkerScriptController::forbidExecution()
@@ -124,8 +78,6 @@ void WorkerScriptController::forbidExecution()
// This function is called from another thread.
MutexLocker lock(m_sharedDataMutex);
m_executionForbidden = true;
-
- Dispose();
}
} // namespace WebCore
diff --git a/webkit/port/bindings/v8/WorkerScriptController.h b/webkit/port/bindings/v8/WorkerScriptController.h
index a66e080..efc71d3 100644
--- a/webkit/port/bindings/v8/WorkerScriptController.h
+++ b/webkit/port/bindings/v8/WorkerScriptController.h
@@ -29,6 +29,8 @@
#if ENABLE(WORKERS)
+#include <wtf/OwnPtr.h>
+#include <wtf/Threading.h>
#include "v8.h"
namespace WebCore {
@@ -36,22 +38,22 @@ namespace WebCore {
class ScriptSourceCode;
class ScriptValue;
class WorkerContext;
+ class WorkerContextExecutionProxy;
class WorkerScriptController {
public:
WorkerScriptController(WorkerContext*);
~WorkerScriptController();
+ WorkerContextExecutionProxy* proxy() { return m_proxy.get(); }
+
ScriptValue evaluate(const ScriptSourceCode&);
void forbidExecution();
private:
- void InitContextIfNeeded();
- void Dispose();
-
WorkerContext* m_workerContext;
- v8::Persistent<v8::Context> m_context;
+ OwnPtr<WorkerContextExecutionProxy> m_proxy;
Mutex m_sharedDataMutex;
bool m_executionForbidden;
diff --git a/webkit/port/bindings/v8/v8_custom.h b/webkit/port/bindings/v8/v8_custom.h
index 72f9979..d27ed41 100644
--- a/webkit/port/bindings/v8/v8_custom.h
+++ b/webkit/port/bindings/v8/v8_custom.h
@@ -88,6 +88,11 @@ class V8Custom {
kDefaultWrapperInternalFieldCount + 0;
static const int kWorkerInternalFieldCount =
kDefaultWrapperInternalFieldCount + 1;
+
+ static const int kWorkerContextRequestCacheIndex =
+ kDefaultWrapperInternalFieldCount + 0;
+ static const int kWorkerContextInternalFieldCount =
+ kDefaultWrapperInternalFieldCount + 1;
#endif
static const int kDOMWindowLocationIndex =
@@ -425,6 +430,15 @@ DECLARE_PROPERTY_ACCESSOR(WorkerOnerror)
DECLARE_CALLBACK(WorkerConstructor)
DECLARE_CALLBACK(WorkerAddEventListener)
DECLARE_CALLBACK(WorkerRemoveEventListener)
+
+DECLARE_PROPERTY_ACCESSOR_GETTER(WorkerContextSelf)
+DECLARE_PROPERTY_ACCESSOR(WorkerContextOnmessage)
+DECLARE_CALLBACK(WorkerContextSetTimeout)
+DECLARE_CALLBACK(WorkerContextClearTimeout)
+DECLARE_CALLBACK(WorkerContextSetInterval)
+DECLARE_CALLBACK(WorkerContextClearInterval)
+DECLARE_CALLBACK(WorkerContextAddEventListener)
+DECLARE_CALLBACK(WorkerContextRemoveEventListener)
#endif
#undef DECLARE_INDEXED_ACCESS_CHECK
diff --git a/webkit/port/bindings/v8/v8_events.cpp b/webkit/port/bindings/v8/v8_events.cpp
index 7aecbb1..06de1c6 100644
--- a/webkit/port/bindings/v8/v8_events.cpp
+++ b/webkit/port/bindings/v8/v8_events.cpp
@@ -40,14 +40,14 @@
#include "Tokenizer.h"
#include "Node.h"
#include "XMLHttpRequest.h"
+#include "WorkerContextExecutionProxy.h"
#include "CString.h"
namespace WebCore {
V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isInline)
- : m_frame(frame), m_isInline(isInline) {
- ASSERT(m_frame);
+ : m_isInline(isInline), m_frame(frame) {
if (!m_frame) return;
// Get the position in the source if any.
@@ -61,7 +61,7 @@ V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isInline)
void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) {
// EventListener could be disconnected from the frame.
- if (!m_frame)
+ if (disconnected())
return;
// The callback function on XMLHttpRequest can clear the event listener
@@ -449,4 +449,132 @@ v8::Local<v8::Function> V8LazyEventListener::GetWrappedListenerFunction() {
return v8::Local<v8::Function>::New(m_wrapped_function);
}
+#if ENABLE(WORKERS)
+V8WorkerContextEventListener::V8WorkerContextEventListener(
+ WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline)
+ : V8ObjectEventListener(NULL, listener, isInline)
+ , m_proxy(proxy) {
+}
+
+V8WorkerContextEventListener::~V8WorkerContextEventListener() {
+ if (m_proxy) {
+ m_proxy->RemoveEventListener(this);
+ }
+ DisposeListenerObject();
+}
+
+void V8WorkerContextEventListener::handleEvent(Event* event,
+ bool isWindowEvent) {
+ // EventListener could be disconnected from the frame.
+ if (disconnected())
+ return;
+
+ // The callback function on XMLHttpRequest can clear the event listener
+ // and destroys 'this' object. Keep a local reference of it.
+ // See issue 889829
+ RefPtr<V8AbstractEventListener> self(this);
+
+ v8::HandleScope handle_scope;
+
+ v8::Handle<v8::Context> context = m_proxy->GetContext();
+ if (context.IsEmpty())
+ return;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Value> jsevent =
+ WorkerContextExecutionProxy::EventToV8Object(event);
+
+ // For compatibility, we store the event object as a property on the window
+ // called "event". Because this is the global namespace, we save away any
+ // existing "event" property, and then restore it after executing the
+ // javascript handler.
+ v8::Local<v8::String> event_symbol = v8::String::NewSymbol("event");
+
+ // Save the old 'event' property.
+ v8::Local<v8::Value> saved_evt = context->Global()->Get(event_symbol);
+
+ // Make the event available in the window object.
+ //
+ // TODO: This does not work as in safari if the window.event
+ // property is already set. We need to make sure that property
+ // access is intercepted correctly.
+ context->Global()->Set(event_symbol, jsevent);
+
+ v8::Local<v8::Value> ret;
+ {
+ // Catch exceptions thrown in the event handler so they do not
+ // propagate to javascript code that caused the event to fire.
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+
+ // Call the event handler.
+ ret = CallListenerFunction(jsevent, event, isWindowEvent);
+ }
+
+ // Restore the old event. This must be done for all exit paths through
+ // this method.
+ context->Global()->Set(event_symbol, saved_evt);
+
+ if (V8Proxy::HandleOutOfMemory())
+ ASSERT(ret.IsEmpty());
+
+ if (ret.IsEmpty()) {
+ return;
+ }
+
+ if (!ret.IsEmpty()) {
+ if (!ret->IsNull() && !ret->IsUndefined() &&
+ event->storesResultAsString()) {
+ event->storeResult(ToWebCoreString(ret));
+ }
+ // Prevent default action if the return value is false;
+ // TODO(fqian): example, and reference to buganizer entry
+ if (m_isInline) {
+ if (ret->IsBoolean() && !ret->BooleanValue()) {
+ event->preventDefault();
+ }
+ }
+ }
+}
+
+v8::Local<v8::Value> V8WorkerContextEventListener::CallListenerFunction(
+ v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent) {
+ v8::Local<v8::Function> handler_func = GetListenerFunction();
+ if (handler_func.IsEmpty()) return v8::Local<v8::Value>();
+
+ v8::Local<v8::Object> receiver = GetReceiverObject(event, isWindowEvent);
+ v8::Handle<v8::Value> parameters[1] = {jsevent};
+
+ v8::Local<v8::Value> result;
+ {
+ //ConsoleMessageScope scope;
+
+ result = handler_func->Call(receiver, 1, parameters);
+ }
+
+ m_proxy->TrackEvent(event);
+
+ return result;
+}
+
+v8::Local<v8::Object> V8WorkerContextEventListener::GetReceiverObject(
+ Event* event, bool isWindowEvent) {
+ if (!m_listener.IsEmpty() && !m_listener->IsFunction()) {
+ return v8::Local<v8::Object>::New(m_listener);
+ }
+
+ if (isWindowEvent) {
+ return v8::Context::GetCurrent()->Global();
+ }
+
+ EventTarget* target = event->currentTarget();
+ v8::Handle<v8::Value> value =
+ WorkerContextExecutionProxy::EventTargetToV8Object(target);
+ if (value.IsEmpty()) return v8::Local<v8::Object>();
+ return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
+}
+#endif // WORKERS
+
} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_events.h b/webkit/port/bindings/v8/v8_events.h
index 7306ab4..e01f972 100644
--- a/webkit/port/bindings/v8/v8_events.h
+++ b/webkit/port/bindings/v8/v8_events.h
@@ -17,6 +17,10 @@
namespace WebCore {
+#if ENABLE(WORKERS)
+class WorkerContextExecutionProxy;
+#endif // WORKERS
+
// There are two kinds of event listeners: HTML or non-HMTL.
// onload, onfocus, etc (attributes) are always HTML event handler type;
// Event listeners added by Window.addEventListener
@@ -34,7 +38,7 @@ class V8AbstractEventListener : public EventListener {
Frame* frame() { return m_frame; }
// Handle event.
- void handleEvent(Event*, bool isWindowEvent);
+ virtual void handleEvent(Event*, bool isWindowEvent);
// Returns the listener object, either a function or an object.
virtual v8::Local<v8::Object> GetListenerObject() {
@@ -44,10 +48,18 @@ class V8AbstractEventListener : public EventListener {
// Dispose listener object and clear the handle
void DisposeListenerObject();
+ virtual bool disconnected() const { return m_frame == NULL; }
+
+ protected:
+ // Listener object.
+ v8::Persistent<v8::Object> m_listener;
+
+ // Flags this is a HTML type listener.
+ bool m_isInline;
+
private:
V8AbstractEventListener(Frame* frame, bool isInline);
-
// Call listener function.
virtual v8::Local<v8::Value> CallListenerFunction(
v8::Handle<v8::Value> jsevent,
@@ -66,12 +78,6 @@ class V8AbstractEventListener : public EventListener {
// the event listener is deleted. Fix this!
Frame* m_frame;
- // Listener object.
- v8::Persistent<v8::Object> m_listener;
-
- // Flags this is a HTML type listener.
- bool m_isInline;
-
// Position in the HTML source for HTML event listeners.
int m_lineNumber;
int m_columnNumber;
@@ -98,11 +104,13 @@ class V8EventListener : public V8AbstractEventListener {
// Detach the listener from its owner frame.
void disconnectFrame() { m_frame = 0; }
+ protected:
+ v8::Local<v8::Function> GetListenerFunction();
+
private:
// Call listener function.
virtual v8::Local<v8::Value> CallListenerFunction(
v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent);
- v8::Local<v8::Function> GetListenerFunction();
};
@@ -158,6 +166,37 @@ class V8LazyEventListener : public V8AbstractEventListener {
v8::Local<v8::Function> GetListenerFunction();
};
+#if ENABLE(WORKERS)
+class V8WorkerContextEventListener : public V8ObjectEventListener {
+ public:
+ static PassRefPtr<V8WorkerContextEventListener> create(
+ WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline) {
+ return adoptRef(new V8WorkerContextEventListener(proxy,
+ listener,
+ isInline));
+ }
+ V8WorkerContextEventListener(WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline);
+
+ virtual ~V8WorkerContextEventListener();
+ virtual void handleEvent(Event*, bool isWindowEvent);
+ virtual bool disconnected() const { return m_proxy == NULL; }
+
+ void disconnect() { m_proxy = NULL; }
+
+ private:
+ virtual v8::Local<v8::Value>
+ CallListenerFunction(v8::Handle<v8::Value> jsevent,
+ Event* event, bool isWindowEvent);
+ v8::Local<v8::Object> GetReceiverObject(Event* event,
+ bool isWindowEvent);
+ WorkerContextExecutionProxy* m_proxy;
+};
+#endif // WORKERS
+
} // namespace WebCore
#endif // V8_EVENTS_H__
diff --git a/webkit/port/bindings/v8/v8_index.cpp b/webkit/port/bindings/v8/v8_index.cpp
index 9f93a93..6be992c 100644
--- a/webkit/port/bindings/v8/v8_index.cpp
+++ b/webkit/port/bindings/v8/v8_index.cpp
@@ -355,7 +355,9 @@
#if ENABLE(WORKERS)
#include "V8Worker.h"
+#include "V8WorkerContext.h"
#include "V8WorkerLocation.h"
+#include "V8WorkerNavigator.h"
#endif
namespace WebCore {
diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h
index d388116..f77557f 100644
--- a/webkit/port/bindings/v8/v8_index.h
+++ b/webkit/port/bindings/v8/v8_index.h
@@ -29,7 +29,9 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)();
#if ENABLE(WORKERS)
#define WORKER_NONNODE_WRAPPER_TYPES(V) \
V(WORKER, Worker) \
- V(WORKERLOCATION, WorkerLocation)
+ V(WORKERCONTEXT, WorkerContext) \
+ V(WORKERLOCATION, WorkerLocation) \
+ V(WORKERNAVIGATOR, WorkerNavigator)
#else
#define WORKER_NONNODE_WRAPPER_TYPES(V)
#endif
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
index 4a76163..81c6e63 100644
--- a/webkit/port/bindings/v8/v8_proxy.cpp
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -193,7 +193,9 @@
#if ENABLE(WORKERS)
#include "Worker.h"
+#include "WorkerContext.h"
#include "WorkerLocation.h"
+#include "WorkerNavigator.h"
#endif // WORKERS
#if ENABLE(XPATH)
@@ -380,7 +382,7 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* para);
static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* para);
// A map from DOM node to its JS wrapper.
-static DOMWrapperMap<Node>& dom_node_map()
+static DOMWrapperMap<Node>& GetDOMNodeMap()
{
static DOMWrapperMap<Node> static_dom_node_map(&WeakNodeCallback);
return static_dom_node_map;
@@ -389,7 +391,7 @@ static DOMWrapperMap<Node>& dom_node_map()
// A map from a DOM object (non-node) to its JS wrapper. This map does not
// contain the DOM objects which can have pending activity (active dom objects).
-static DOMWrapperMap<void>& dom_object_map()
+DOMWrapperMap<void>& GetDOMObjectMap()
{
static DOMWrapperMap<void>
static_dom_object_map(&WeakDOMObjectCallback);
@@ -399,7 +401,7 @@ static DOMWrapperMap<void>& dom_object_map()
// A map from a DOM object to its JS wrapper for DOM objects which
// can have pending activity.
-static DOMWrapperMap<void>& active_dom_object_map()
+static DOMWrapperMap<void>& GetActiveDOMObjectMap()
{
static DOMWrapperMap<void>
static_active_dom_object_map(&WeakActiveDOMObjectCallback);
@@ -560,18 +562,17 @@ SVGElement* V8Proxy::GetSVGContext(void* obj)
#endif
-
// Called when obj is near death (not reachable from JS roots)
// It is time to remove the entry from the table and dispose
// the handle.
static void WeakDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* dom_obj) {
v8::HandleScope scope;
- ASSERT(dom_object_map().contains(dom_obj));
+ ASSERT(GetDOMObjectMap().contains(dom_obj));
ASSERT(obj->IsObject());
// Forget function removes object from the map and dispose the wrapper.
- dom_object_map().forget(dom_obj);
+ GetDOMObjectMap().forget(dom_obj);
V8ClassIndex::V8WrapperType type =
V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj));
@@ -590,11 +591,11 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* dom_obj)
{
v8::HandleScope scope;
- ASSERT(active_dom_object_map().contains(dom_obj));
+ ASSERT(GetActiveDOMObjectMap().contains(dom_obj));
ASSERT(obj->IsObject());
// Forget function removes object from the map and dispose the wrapper.
- active_dom_object_map().forget(dom_obj);
+ GetActiveDOMObjectMap().forget(dom_obj);
V8ClassIndex::V8WrapperType type =
V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj));
@@ -611,9 +612,9 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* param)
{
Node* node = static_cast<Node*>(param);
- ASSERT(dom_node_map().contains(node));
+ ASSERT(GetDOMNodeMap().contains(node));
- dom_node_map().forget(node);
+ GetDOMNodeMap().forget(node);
node->deref();
}
@@ -632,11 +633,11 @@ void V8Proxy::GCProtect(void* dom_object)
return;
if (gc_protected_map().contains(dom_object))
return;
- if (!dom_object_map().contains(dom_object))
+ if (!GetDOMObjectMap().contains(dom_object))
return;
// Create a new (strong) persistent handle for the object.
- v8::Persistent<v8::Object> wrapper = dom_object_map().get(dom_object);
+ v8::Persistent<v8::Object> wrapper = GetDOMObjectMap().get(dom_object);
if (wrapper.IsEmpty()) return;
gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper));
@@ -663,12 +664,12 @@ static void GCPrologue()
v8::HandleScope scope;
#ifndef NDEBUG
- EnumerateDOMObjectMap(dom_object_map().impl());
+ EnumerateDOMObjectMap(GetDOMObjectMap().impl());
#endif
// Run through all objects with possible pending activity making their
// wrappers non weak if there is pending activity.
- DOMObjectMap active_map = active_dom_object_map().impl();
+ DOMObjectMap active_map = GetActiveDOMObjectMap().impl();
for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
it != end; ++it) {
void* obj = it->first;
@@ -731,7 +732,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
typedef std::pair<uintptr_t, Node*> GrouperPair;
typedef Vector<GrouperPair> GrouperList;
- DOMNodeMap node_map = dom_node_map().impl();
+ DOMNodeMap node_map = GetDOMNodeMap().impl();
GrouperList grouper;
grouper.reserveCapacity(node_map.size());
@@ -797,7 +798,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
group.reserveCapacity(next_key_index - i);
for (; i < next_key_index; ++i) {
v8::Persistent<v8::Value> wrapper =
- dom_node_map().get(grouper[i].second);
+ GetDOMNodeMap().get(grouper[i].second);
if (!wrapper.IsEmpty())
group.append(wrapper);
}
@@ -816,7 +817,7 @@ static void GCEpilogue()
// Run through all objects with pending activity making their wrappers weak
// again.
- DOMObjectMap active_map = active_dom_object_map().impl();
+ DOMObjectMap active_map = GetActiveDOMObjectMap().impl();
for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
it != end; ++it) {
void* obj = it->first;
@@ -841,8 +842,8 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
#ifndef NDEBUG
// Check all survivals are weak.
- EnumerateDOMObjectMap(dom_object_map().impl());
- EnumerateDOMNodeMap(dom_node_map().impl());
+ EnumerateDOMObjectMap(GetDOMObjectMap().impl());
+ EnumerateDOMNodeMap(GetDOMNodeMap().impl());
EnumerateDOMObjectMap(gc_protected_map());
EnumerateGlobalHandles();
#undef USE_VAR
@@ -1104,8 +1105,8 @@ void V8Proxy::DestroyGlobal()
bool V8Proxy::DOMObjectHasJSWrapper(void* obj) {
- return dom_object_map().contains(obj) ||
- active_dom_object_map().contains(obj);
+ return GetDOMObjectMap().contains(obj) ||
+ GetActiveDOMObjectMap().contains(obj);
}
@@ -1123,7 +1124,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
default: break;
}
#endif
- dom_object_map().set(obj, wrapper);
+ GetDOMObjectMap().set(obj, wrapper);
}
// The caller must have increased obj's ref count.
@@ -1139,14 +1140,14 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
#undef MAKE_CASE
}
#endif
- active_dom_object_map().set(obj, wrapper);
+ GetActiveDOMObjectMap().set(obj, wrapper);
}
// The caller must have increased node's ref count.
void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper)
{
ASSERT(MaybeDOMWrapper(wrapper));
- dom_node_map().set(node, wrapper);
+ GetDOMNodeMap().set(node, wrapper);
}
PassRefPtr<EventListener> V8Proxy::createInlineEventListener(
@@ -1379,7 +1380,7 @@ v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script,
return v8::Local<v8::Value>();
// Compute the source string and prevent against infinite recursion.
- if (m_recursion >= 20) {
+ if (m_recursion >= kMaxRecursionDepth) {
v8::Local<v8::String> code =
v8ExternalString("throw RangeError('Recursion too deep')");
// TODO(kasperl): Ideally, we should be able to re-use the origin of the
@@ -1794,8 +1795,18 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate(
desc->SetCallHandler(USE_CALLBACK(WorkerConstructor));
break;
}
+
+ case V8ClassIndex::WORKERCONTEXT: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kWorkerContextInternalFieldCount);
+ break;
+ }
#endif // WORKERS
+
// The following objects are created from JavaScript.
case V8ClassIndex::DOMPARSER:
desc->SetCallHandler(USE_CALLBACK(DOMParserConstructor));
@@ -2520,8 +2531,8 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void
// Non DOM node
v8::Persistent<v8::Object> result = is_active_dom_object ?
- active_dom_object_map().get(imp) :
- dom_object_map().get(imp);
+ GetActiveDOMObjectMap().get(imp) :
+ GetDOMObjectMap().get(imp);
if (result.IsEmpty()) {
v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp);
if (!v8obj.IsEmpty()) {
@@ -2667,6 +2678,7 @@ v8::Local<v8::Object> V8Proxy::InstantiateV8Object(
desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
}
+
v8::Local<v8::Function> function;
V8Proxy* proxy = V8Proxy::retrieve();
if (proxy) {
@@ -2994,7 +3006,7 @@ v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event)
if (!event)
return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(event);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(event);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3053,7 +3065,7 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node)
{
if (!node) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_node_map().get(node);
+ v8::Handle<v8::Object> wrapper = GetDOMNodeMap().get(node);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3171,9 +3183,9 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node)
}
-// A JS object of type EventTarget can only be five possible types:
+// A JS object of type EventTarget can only be the following possible types:
// 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance;
-// 5) XMLHttpRequestUpload
+// 5) XMLHttpRequestUpload 6) Worker
// check EventTarget.h for new type conversion methods
v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
{
@@ -3186,6 +3198,12 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
#endif
+#if ENABLE(WORKERS)
+ Worker* worker = target->toWorker();
+ if (worker)
+ return ToV8Object(V8ClassIndex::WORKER, worker);
+#endif // WORKERS
+
Node* node = target->toNode();
if (node)
return NodeToV8Object(node);
@@ -3193,7 +3211,7 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
// XMLHttpRequest is created within its JS counterpart.
XMLHttpRequest* xhr = target->toXMLHttpRequest();
if (xhr) {
- v8::Handle<v8::Object> wrapper = active_dom_object_map().get(xhr);
+ v8::Handle<v8::Object> wrapper = GetActiveDOMObjectMap().get(xhr);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
@@ -3201,14 +3219,14 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
// MessagePort is created within its JS counterpart
MessagePort* port = target->toMessagePort();
if (port) {
- v8::Handle<v8::Object> wrapper = active_dom_object_map().get(port);
+ v8::Handle<v8::Object> wrapper = GetActiveDOMObjectMap().get(port);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload();
if (upload) {
- v8::Handle<v8::Object> wrapper = dom_object_map().get(upload);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(upload);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
@@ -3250,7 +3268,7 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet)
{
if (!sheet) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(sheet);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(sheet);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3282,7 +3300,7 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value)
{
if (!value) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(value);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(value);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3319,7 +3337,7 @@ v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule)
{
if (!rule) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(rule);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(rule);
if (!wrapper.IsEmpty())
return wrapper;
diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h
index 772489f..2054035 100644
--- a/webkit/port/bindings/v8/v8_proxy.h
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -6,6 +6,7 @@
#define V8_PROXY_H__
#include <v8.h>
+#include "dom_wrapper_map.h"
#include "v8_index.h"
#include "v8_custom.h"
#include "v8_utility.h"
@@ -142,6 +143,10 @@ void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc,
const BatchedConstant* consts,
size_t num_consts);
+DOMWrapperMap<void>& GetDOMObjectMap();
+
+const int kMaxRecursionDepth = 20;
+
class V8Proxy {
public:
// The types of javascript errors that can be thrown.