2009-04-09 Jian Li <jianli@chromium.org>
[WebKit-https.git] / WebCore / bindings / v8 / WorkerContextExecutionProxy.cpp
index a46aa24..6adfdbf 100644 (file)
@@ -39,6 +39,7 @@
 #include "V8Proxy.h"
 #include "Event.h"
 #include "V8WorkerContextEventListener.h"
+#include "V8WorkerContextObjectEventListener.h"
 #include "WorkerContext.h"
 #include "WorkerLocation.h"
 #include "WorkerNavigator.h"
@@ -62,6 +63,9 @@ WorkerContextExecutionProxy::WorkerContextExecutionProxy(WorkerContext* workerCo
     : m_workerContext(workerContext)
     , m_recursion(0)
 {
+    // Need to use lock since V8EventListenerList constructor creates HandleScope.
+    v8::Locker locker;
+    m_listeners.set(new V8EventListenerList("m_listeners"));
 }
 
 WorkerContextExecutionProxy::~WorkerContextExecutionProxy()
@@ -72,10 +76,14 @@ WorkerContextExecutionProxy::~WorkerContextExecutionProxy()
 void WorkerContextExecutionProxy::dispose()
 {
     // Disconnect all event listeners.
-    for (size_t listenerIndex = 0; listenerIndex < m_listeners.size(); ++listenerIndex)
-       m_listeners[listenerIndex]->disconnect();
+    for (V8EventListenerList::iterator iterator(m_listeners->begin()); iterator != m_listeners->end(); ++iterator)
+       static_cast<V8WorkerContextEventListener*>(*iterator)->disconnect();
 
-    m_listeners.clear();
+    {
+        // Need to use lock since V8EventListenerList::clear() creates HandleScope.
+        v8::Locker locker;
+        m_listeners->clear();
+    }
 
     // Detach all events from their JS wrappers.
     for (size_t eventIndex = 0; eventIndex < m_events.size(); ++eventIndex) {
@@ -99,7 +107,7 @@ void WorkerContextExecutionProxy::dispose()
     v8::HandleScope scope;
     v8::Persistent<v8::Object> wrapper = domObjectMap().get(m_workerContext);
     if (!wrapper.IsEmpty())
-        V8Proxy::SetDOMWrapper(wrapper, V8ClassIndex::INVALID_CLASS_INDEX, NULL);
+        V8Proxy::SetDOMWrapper(wrapper, V8ClassIndex::INVALID_CLASS_INDEX, 0);
     domObjectMap().forget(m_workerContext);
 }
 
@@ -108,7 +116,9 @@ 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());
+    // Return 0 if the current executing context is not the worker context.
+    if (global.IsEmpty())
+        return 0;
     WorkerContext* workerContext = V8Proxy::ToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, global);
     return workerContext->script()->proxy();
 }
@@ -121,7 +131,7 @@ void WorkerContextExecutionProxy::initContextIfNeeded()
 
     // Create a new environment
     v8::Persistent<v8::ObjectTemplate> globalTemplate;
-    m_context = v8::Context::New(NULL, globalTemplate);
+    m_context = v8::Context::New(0, globalTemplate);
 
     // Starting from now, use local context only.
     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(m_context);
@@ -279,6 +289,10 @@ v8::Local<v8::Value> WorkerContextExecutionProxy::evaluate(const String& script,
     v8::Locker locker;
     v8::HandleScope hs;
 
+    // Enable preemption so that one worker will not be blocked by another long-running worker.
+    const int workerThreadPreemptionIntervalMs = 100;
+    v8::Locker::StartPreemption(workerThreadPreemptionIntervalMs);
+
     initContextIfNeeded();
     v8::Context::Scope scope(m_context);
 
@@ -319,34 +333,45 @@ v8::Local<v8::Value> WorkerContextExecutionProxy::runScript(v8::Handle<v8::Scrip
     return result;
 }
 
-PassRefPtr<V8EventListener> WorkerContextExecutionProxy::FindOrCreateEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly)
+PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateEventListenerHelper(v8::Local<v8::Value> object, bool isInline, bool findOnly, bool createObjectEventListener)
 {
     if (!object->IsObject())
         return 0;
 
-    for (size_t index = 0; index < m_listeners.size(); ++index) {
-        V8EventListener* el = m_listeners[index];
-        if (el->isInline() == isInline && el->getListenerObject() == object)
-            return el;
-    }
+    V8EventListener* listener = m_listeners->find(object->ToObject(), isInline);
     if (findOnly)
-        return NULL;
+        return listener;
 
     // Create a new one, and add to cache.
-    RefPtr<V8WorkerContextEventListener> listener = V8WorkerContextEventListener::create(this, v8::Local<v8::Object>::Cast(object), isInline);
-    m_listeners.append(listener.get());
+    RefPtr<V8EventListener> newListener;
+    if (createObjectEventListener)
+        newListener = V8WorkerContextObjectEventListener::create(this, v8::Local<v8::Object>::Cast(object), isInline);
+    else
+        newListener = V8WorkerContextEventListener::create(this, v8::Local<v8::Object>::Cast(object), isInline);
+    {
+        // Need to use lock since V8EventListenerList::add() creates HandleScope.
+        v8::Locker locker;
+        m_listeners->add(newListener.get());
+    }
 
-    return listener.release();
+    return newListener.release();
+}
+
+PassRefPtr<V8EventListener> WorkerContextExecutionProxy::FindOrCreateEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly)
+{
+    return findOrCreateEventListenerHelper(object, isInline, findOnly, false);
+}
+
+PassRefPtr<V8EventListener> WorkerContextExecutionProxy::findOrCreateObjectEventListener(v8::Local<v8::Value> object, bool isInline, bool findOnly)
+{
+    return findOrCreateEventListenerHelper(object, isInline, findOnly, true);
 }
 
 void WorkerContextExecutionProxy::RemoveEventListener(V8EventListener* listener)
 {
-    for (size_t index = 0; index < m_listeners.size(); ++index) {
-        if (m_listeners[index] == listener) {
-            m_listeners.remove(index);
-            return;
-        }
-    }
+    // Need to use lock since V8EventListenerList::remove() creates HandleScope.
+    v8::Locker locker;
+    m_listeners->remove(listener);
 }
 
 void WorkerContextExecutionProxy::trackEvent(Event* event)