Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (c) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WorkerScriptDebugServer.h"
     33 
     34 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
     35 
     36 #include "ScriptDebugListener.h"
     37 #include "V8DOMWrapper.h"
     38 #include "V8DedicatedWorkerContext.h"
     39 #include "V8SharedWorkerContext.h"
     40 #include "WorkerContext.h"
     41 #include "WorkerContextExecutionProxy.h"
     42 #include "WorkerThread.h"
     43 #include <v8.h>
     44 #include <wtf/MessageQueue.h>
     45 
     46 namespace WebCore {
     47 
     48 static WorkerContext* retrieveWorkerContext(v8::Handle<v8::Context> context)
     49 {
     50     v8::Handle<v8::Object> global = context->Global();
     51     ASSERT(!global.IsEmpty());
     52 
     53     v8::Handle<v8::Object> prototype = v8::Handle<v8::Object>::Cast(global->GetPrototype());
     54     ASSERT(!prototype.IsEmpty());
     55 
     56     prototype = v8::Handle<v8::Object>::Cast(prototype->GetPrototype());
     57     ASSERT(!prototype.IsEmpty());
     58 
     59     WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(prototype);
     60     if (&V8DedicatedWorkerContext::info == typeInfo)
     61         return V8DedicatedWorkerContext::toNative(prototype);
     62     if (&V8SharedWorkerContext::info == typeInfo)
     63         return V8SharedWorkerContext::toNative(prototype);
     64     ASSERT_NOT_REACHED();
     65     return 0;
     66 }
     67 
     68 WorkerScriptDebugServer::WorkerScriptDebugServer()
     69     : ScriptDebugServer()
     70     , m_pausedWorkerContext(0)
     71 {
     72 }
     73 
     74 void WorkerScriptDebugServer::addListener(ScriptDebugListener* listener, WorkerContext* workerContext)
     75 {
     76     v8::HandleScope scope;
     77     v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     78     v8::Context::Scope contextScope(debuggerContext);
     79 
     80     if (!m_listenersMap.size()) {
     81         // FIXME: synchronize access to this code.
     82         ensureDebuggerScriptCompiled();
     83         ASSERT(!m_debuggerScript.get()->IsUndefined());
     84         v8::Debug::SetDebugEventListener2(&WorkerScriptDebugServer::v8DebugEventCallback, v8::External::New(this));
     85     }
     86     m_listenersMap.set(workerContext, listener);
     87 
     88     WorkerContextExecutionProxy* proxy = workerContext->script()->proxy();
     89     if (!proxy)
     90         return;
     91     v8::Handle<v8::Context> context = proxy->context();
     92 
     93     v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getWorkerScripts")));
     94     v8::Handle<v8::Value> argv[] = { v8::Handle<v8::Value>() };
     95     v8::Handle<v8::Value> value = getScriptsFunction->Call(m_debuggerScript.get(), 0, argv);
     96     if (value.IsEmpty())
     97         return;
     98     ASSERT(!value->IsUndefined() && value->IsArray());
     99     v8::Handle<v8::Array> scriptsArray = v8::Handle<v8::Array>::Cast(value);
    100     for (unsigned i = 0; i < scriptsArray->Length(); ++i)
    101         dispatchDidParseSource(listener, v8::Handle<v8::Object>::Cast(scriptsArray->Get(v8::Integer::New(i))));
    102 }
    103 
    104 void WorkerScriptDebugServer::removeListener(ScriptDebugListener* listener, WorkerContext* workerContext)
    105 {
    106     if (!m_listenersMap.contains(workerContext))
    107         return;
    108 
    109     if (m_pausedWorkerContext == workerContext)
    110         continueProgram();
    111 
    112     m_listenersMap.remove(workerContext);
    113 
    114     if (m_listenersMap.isEmpty())
    115         v8::Debug::SetDebugEventListener2(0);
    116 }
    117 
    118 ScriptDebugListener* WorkerScriptDebugServer::getDebugListenerForContext(v8::Handle<v8::Context> context)
    119 {
    120     WorkerContext* workerContext = retrieveWorkerContext(context);
    121     if (!workerContext)
    122         return 0;
    123     return m_listenersMap.get(workerContext);
    124 }
    125 
    126 void WorkerScriptDebugServer::runMessageLoopOnPause(v8::Handle<v8::Context> context)
    127 {
    128     WorkerContext* workerContext = retrieveWorkerContext(context);
    129     WorkerThread* workerThread = workerContext->thread();
    130 
    131     m_pausedWorkerContext = workerContext;
    132 
    133     MessageQueueWaitResult result;
    134     do {
    135         result = workerThread->runLoop().runInMode(workerContext, "debugger");
    136     // Keep waiting until execution is resumed.
    137     } while (result == MessageQueueMessageReceived && isPaused());
    138     m_pausedWorkerContext = 0;
    139 
    140     // The listener may have been removed in the nested loop.
    141     if (ScriptDebugListener* listener = m_listenersMap.get(workerContext))
    142         listener->didContinue();
    143 }
    144 
    145 void WorkerScriptDebugServer::quitMessageLoopOnPause()
    146 {
    147     // FIXME: do exit nested loop when listener is removed on pause.
    148 }
    149 
    150 } // namespace WebCore
    151 
    152 #endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
    153