diff options
Diffstat (limited to 'webkit/port/bindings/v8')
-rw-r--r-- | webkit/port/bindings/v8/ScheduledAction.h | 1 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8MessagePortCustom.cpp | 2 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8WorkerContextCustom.cpp | 224 | ||||
-rw-r--r-- | webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp | 358 | ||||
-rw-r--r-- | webkit/port/bindings/v8/WorkerContextExecutionProxy.h | 119 | ||||
-rw-r--r-- | webkit/port/bindings/v8/WorkerScriptController.cpp | 62 | ||||
-rw-r--r-- | webkit/port/bindings/v8/WorkerScriptController.h | 10 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_custom.h | 14 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_events.cpp | 134 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_events.h | 57 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.cpp | 2 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.h | 4 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 92 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 5 |
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. |