Changeset 57660 in webkit


Ignore:
Timestamp:
Apr 15, 2010 11:40:34 AM (14 years ago)
Author:
yurys@chromium.org
Message:

2010-04-15 Yury Semikhatsky <yurys@google.com>

Reviewed by Pavel Feldman.


Support basic debugging capabilities including step in/over/out in v8
implementation of ScriptDebugServer.

https://bugs.webkit.org/show_bug.cgi?id=37604

  • bindings/js/JSInjectedScriptHostCustom.cpp: (WebCore::InjectedScriptHost::createInjectedScript):
  • bindings/v8/ScriptDebugServer.cpp: (WebCore::ScriptDebugServer::ScriptDebugServer): (WebCore::ScriptDebugServer::setDebuggerScriptSource): (WebCore::ScriptDebugServer::addListener): (WebCore::ScriptDebugServer::removeListener): (WebCore::ScriptDebugServer::setBreakpoint): (WebCore::ScriptDebugServer::removeBreakpoint): (WebCore::ScriptDebugServer::clearBreakpoints): (WebCore::ScriptDebugServer::setBreakpointsActivated): (WebCore::ScriptDebugServer::continueProgram): (WebCore::ScriptDebugServer::stepIntoStatement): (WebCore::ScriptDebugServer::stepOverStatement): (WebCore::ScriptDebugServer::stepOutOfFunction): (WebCore::ScriptDebugServer::currentCallFrameState): (WebCore::ScriptDebugServer::currentCallFrameV8): (WebCore::ScriptDebugServer::onV8DebugMessage): (WebCore::ScriptDebugServer::onV8DebugHostDispatch): (WebCore::ScriptDebugServer::handleV8DebugHostDispatch): (WebCore::ScriptDebugServer::handleV8DebugMessage): (WebCore::ScriptDebugServer::dispatchDidParseSource): (WebCore::ScriptDebugServer::ensureDebuggerScriptCompiled): (WebCore::ScriptDebugServer::didResume):
  • bindings/v8/ScriptDebugServer.h: (WebCore::ScriptDebugServer::pauseOnExceptionsState): (WebCore::ScriptDebugServer::setPauseOnExceptionsState): (WebCore::ScriptDebugServer::setMessageLoopDispatchHandler):
  • bindings/v8/custom/V8InjectedScriptHostCustom.cpp: (WebCore::InjectedScriptHost::createInjectedScript): (WebCore::V8InjectedScriptHost::currentCallFrameCallback): (WebCore::V8InjectedScriptHost::isActivationCallback):
  • inspector/front-end/InjectedScript.js: (injectedScriptConstructor): (injectedScriptConstructor.):
  • inspector/front-end/ScriptsPanel.js: (WebInspector.ScriptsPanel):

2010-04-15 Yury Semikhatsky <yurys@google.com>

Reviewed by Pavel Feldman.

Support basic debugging capabilities including step in/over/out in v8
implementation of ScriptDebugServer.

https://bugs.webkit.org/show_bug.cgi?id=37604

  • WebKit.gypi:
  • src/DebuggerAgent.h:
  • src/DebuggerAgentImpl.cpp: (WebKit::DebuggerAgentImpl::setDebuggerScriptSource):
  • src/DebuggerAgentImpl.h:
  • src/DebuggerAgentManager.cpp: (WebKit::DebuggerAgentManager::hostDispatchHandler): (WebKit::DebuggerAgentManager::debugAttach): (WebKit::DebuggerAgentManager::debugDetach): (WebKit::DebuggerAgentManager::setMessageLoopDispatchHandler):
  • src/DebuggerAgentManager.h:
  • src/InspectorFrontendClientImpl.cpp: (WebKit::InspectorFrontendClientImpl::windowObjectCleared):
  • src/js/DebuggerScript.js: Added. (debuggerScriptConstructor.DebuggerScript.getAfterCompileScript): (debuggerScriptConstructor.DebuggerScript.getScripts): (debuggerScriptConstructor.DebuggerScript._formatScript): (debuggerScriptConstructor.DebuggerScript.setBreakpoint): (debuggerScriptConstructor.DebuggerScript.removeBreakpoint): (debuggerScriptConstructor.DebuggerScript.currentCallFrame): (debuggerScriptConstructor.DebuggerScript.stepIntoStatement): (debuggerScriptConstructor.DebuggerScript.stepOverStatement): (debuggerScriptConstructor.DebuggerScript.stepOutOfFunction): (debuggerScriptConstructor.DebuggerScript.clearBreakpoints): (debuggerScriptConstructor.DebuggerScript.setBreakpointsActivated): (debuggerScriptConstructor.DebuggerScript._frameMirrorToJSCallFrame): (debuggerScriptConstructor.DebuggerScript._webkitToV8LineNumber): (debuggerScriptConstructor.DebuggerScript._v8ToWwebkitLineNumber): (debuggerScriptConstructor):
  • src/js/DevTools.js: (WebInspector.loaded): (.): ():
  • src/js/DevToolsHostStub.js: (.RemoteDebuggerAgentStub.prototype.setDebuggerScriptSource):
  • src/js/InspectorControllerImpl.js: (devtools.InspectorBackendImpl):
Location:
trunk
Files:
1 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r57659 r57660  
     12010-04-15  Yury Semikhatsky  <yurys@google.com>
     2
     3        Reviewed by Pavel Feldman.
     4   
     5        Support basic debugging capabilities including step in/over/out in v8
     6        implementation of ScriptDebugServer.
     7
     8        https://bugs.webkit.org/show_bug.cgi?id=37604
     9
     10        * bindings/js/JSInjectedScriptHostCustom.cpp:
     11        (WebCore::InjectedScriptHost::createInjectedScript):
     12        * bindings/v8/ScriptDebugServer.cpp:
     13        (WebCore::ScriptDebugServer::ScriptDebugServer):
     14        (WebCore::ScriptDebugServer::setDebuggerScriptSource):
     15        (WebCore::ScriptDebugServer::addListener):
     16        (WebCore::ScriptDebugServer::removeListener):
     17        (WebCore::ScriptDebugServer::setBreakpoint):
     18        (WebCore::ScriptDebugServer::removeBreakpoint):
     19        (WebCore::ScriptDebugServer::clearBreakpoints):
     20        (WebCore::ScriptDebugServer::setBreakpointsActivated):
     21        (WebCore::ScriptDebugServer::continueProgram):
     22        (WebCore::ScriptDebugServer::stepIntoStatement):
     23        (WebCore::ScriptDebugServer::stepOverStatement):
     24        (WebCore::ScriptDebugServer::stepOutOfFunction):
     25        (WebCore::ScriptDebugServer::currentCallFrameState):
     26        (WebCore::ScriptDebugServer::currentCallFrameV8):
     27        (WebCore::ScriptDebugServer::onV8DebugMessage):
     28        (WebCore::ScriptDebugServer::onV8DebugHostDispatch):
     29        (WebCore::ScriptDebugServer::handleV8DebugHostDispatch):
     30        (WebCore::ScriptDebugServer::handleV8DebugMessage):
     31        (WebCore::ScriptDebugServer::dispatchDidParseSource):
     32        (WebCore::ScriptDebugServer::ensureDebuggerScriptCompiled):
     33        (WebCore::ScriptDebugServer::didResume):
     34        * bindings/v8/ScriptDebugServer.h:
     35        (WebCore::ScriptDebugServer::pauseOnExceptionsState):
     36        (WebCore::ScriptDebugServer::setPauseOnExceptionsState):
     37        (WebCore::ScriptDebugServer::setMessageLoopDispatchHandler):
     38        * bindings/v8/custom/V8InjectedScriptHostCustom.cpp:
     39        (WebCore::InjectedScriptHost::createInjectedScript):
     40        (WebCore::V8InjectedScriptHost::currentCallFrameCallback):
     41        (WebCore::V8InjectedScriptHost::isActivationCallback):
     42        * inspector/front-end/InjectedScript.js:
     43        (injectedScriptConstructor):
     44        (injectedScriptConstructor.):
     45        * inspector/front-end/ScriptsPanel.js:
     46        (WebInspector.ScriptsPanel):
     47
    1482010-04-15  Nikolas Zimmermann  <nzimmermann@rim.com>
    249
  • trunk/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp

    r56841 r57660  
    9696    args.append(globalThisValue);
    9797    args.append(jsNumber(scriptState, id));
     98    args.append(jsString(scriptState, String("JSC")));
    9899    JSValue result = JSC::call(scriptState, functionValue, callType, callData, globalThisValue, args);
    99100    if (result.isObject())
  • trunk/WebCore/bindings/v8/ScriptDebugServer.cpp

    r57231 r57660  
    3434#if ENABLE(JAVASCRIPT_DEBUGGER)
    3535
     36#include "Frame.h"
     37#include "Page.h"
     38#include "ScriptDebugListener.h"
    3639#include "V8Binding.h"
    37 #include <v8-debug.h>
    38 
     40#include "V8DOMWindow.h"
     41#include "V8Proxy.h"
    3942#include <wtf/StdLibExtras.h>
    4043
     
    4245
    4346v8::Persistent<v8::Context> ScriptDebugServer::s_utilityContext;
     47
     48ScriptDebugServer::MessageLoopDispatchHandler ScriptDebugServer::s_messageLoopDispatchHandler = 0;
    4449
    4550ScriptDebugServer& ScriptDebugServer::shared()
     
    4752    DEFINE_STATIC_LOCAL(ScriptDebugServer, server, ());
    4853    return server;
     54}
     55
     56ScriptDebugServer::ScriptDebugServer()
     57    : m_pauseOnExceptionsState(DontPauseOnExceptions)
     58    , m_currentCallFrameState(0)
     59{
     60}
     61
     62void ScriptDebugServer::setDebuggerScriptSource(const String& scriptSource)
     63{
     64    m_debuggerScriptSource = scriptSource;
     65}
     66
     67void ScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page)
     68{
     69#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     70    v8::HandleScope scope;
     71    v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     72    v8::Context::Scope contextScope(debuggerContext);
     73
     74    if (!m_listenersMap.size()) {
     75        ensureDebuggerScriptCompiled();
     76        ASSERT(!m_debuggerScript->IsUndefined());
     77        v8::Debug::SetMessageHandler2(&ScriptDebugServer::onV8DebugMessage);
     78        v8::Debug::SetHostDispatchHandler(&ScriptDebugServer::onV8DebugHostDispatch, 100 /* ms */);
     79    }
     80    m_listenersMap.set(page, listener);
     81    V8Proxy* proxy = V8Proxy::retrieve(page->mainFrame());
     82    v8::Local<v8::Context> context = proxy->mainWorldContext();
     83    String contextData = toWebCoreStringWithNullCheck(context->GetData());
     84    m_contextDataMap.set(listener, contextData);
     85
     86    v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("getScripts")));
     87    v8::Handle<v8::Value> value = v8::Debug::Call(getScriptsFunction);
     88    if (value.IsEmpty())
     89        return;
     90    ASSERT(!value->IsUndefined() && value->IsArray());
     91    v8::Handle<v8::Array> scriptsArray = v8::Handle<v8::Array>::Cast(value);
     92    for (unsigned i = 0; i < scriptsArray->Length(); ++i)
     93        dispatchDidParseSource(listener, v8::Handle<v8::Object>::Cast(scriptsArray->Get(v8::Integer::New(i))));
     94#endif
     95}
     96
     97void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page)
     98{
     99    if (!m_listenersMap.contains(page))
     100        return;
     101
     102    m_listenersMap.remove(page);
     103
     104    if (m_listenersMap.isEmpty()) {
     105        v8::Debug::SetMessageHandler2(0);
     106        v8::Debug::SetHostDispatchHandler(0);
     107    }
     108    // FIXME: Remove all breakpoints set by the agent.
     109    // FIXME: Force continue if detach happened in nessted message loop while
     110    // debugger was paused on a breakpoint(as long as there are other
     111    // attached agents v8 will wait for explicit'continue' message).
     112    // FIXME: send continue command to v8 if necessary;
     113}
     114
     115void ScriptDebugServer::setBreakpoint(const String& sourceID, unsigned lineNumber, ScriptBreakpoint breakpoint)
     116{
     117#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     118    v8::HandleScope scope;
     119    v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     120    v8::Context::Scope contextScope(debuggerContext);
     121
     122    v8::Local<v8::Object> args = v8::Object::New();
     123    args->Set(v8::String::New("scriptId"), v8String(sourceID));
     124    args->Set(v8::String::New("lineNumber"), v8::Integer::New(lineNumber));
     125    args->Set(v8::String::New("condition"), v8String(breakpoint.condition));
     126    args->Set(v8::String::New("enabled"), v8::Boolean::New(breakpoint.enabled));
     127
     128    v8::Handle<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("setBreakpoint")));
     129    v8::Debug::Call(setBreakpointFunction, args);
     130#endif
     131}
     132
     133void ScriptDebugServer::removeBreakpoint(const String& sourceID, unsigned lineNumber)
     134{
     135#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     136    v8::HandleScope scope;
     137    v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     138    v8::Context::Scope contextScope(debuggerContext);
     139
     140    v8::Local<v8::Object> args = v8::Object::New();
     141    args->Set(v8::String::New("scriptId"), v8String(sourceID));
     142    args->Set(v8::String::New("lineNumber"), v8::Integer::New(lineNumber));
     143
     144    v8::Handle<v8::Function> removeBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("removeBreakpoint")));
     145    v8::Debug::Call(removeBreakpointFunction, args);
     146#endif
     147}
     148
     149void ScriptDebugServer::clearBreakpoints()
     150{
     151#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     152    ensureDebuggerScriptCompiled();
     153    v8::HandleScope scope;
     154    v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     155    v8::Context::Scope contextScope(debuggerContext);
     156
     157    v8::Handle<v8::Function> setBreakpointsActivated = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("clearBreakpoints")));
     158    v8::Debug::Call(setBreakpointsActivated);
     159#endif
     160}
     161
     162void ScriptDebugServer::setBreakpointsActivated(bool enabled)
     163{
     164#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     165    ensureDebuggerScriptCompiled();
     166    v8::HandleScope scope;
     167    v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     168    v8::Context::Scope contextScope(debuggerContext);
     169
     170    v8::Local<v8::Object> args = v8::Object::New();
     171    args->Set(v8::String::New("enabled"), v8::Boolean::New(enabled));
     172    v8::Handle<v8::Function> setBreakpointsActivated = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("setBreakpointsActivated")));
     173    v8::Debug::Call(setBreakpointsActivated, args);
     174#endif
     175}
     176
     177void ScriptDebugServer::continueProgram()
     178{
     179#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     180    String cmd("{\"seq\":1,\"type\":\"request\",\"command\":\"continue\"}");
     181    v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.characters()), cmd.length(), new v8::Debug::ClientData());
     182    didResume();
     183#endif
     184}
     185
     186void ScriptDebugServer::stepIntoStatement()
     187{
     188#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     189    String cmd("{\"seq\":1,\"type\":\"request\",\"command\":\"continue\",\"arguments\":{\"stepaction\":\"in\"}}");
     190    v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.characters()), cmd.length(), new v8::Debug::ClientData());
     191    didResume();
     192#endif
     193}
     194
     195void ScriptDebugServer::stepOverStatement()
     196{
     197#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     198    String cmd("{\"seq\":1,\"type\":\"request\",\"command\":\"continue\",\"arguments\":{\"stepaction\":\"next\"}}");
     199    v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.characters()), cmd.length(), new v8::Debug::ClientData());
     200    didResume();
     201#endif
     202}
     203
     204void ScriptDebugServer::stepOutOfFunction()
     205{
     206#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     207    String cmd("{\"seq\":1,\"type\":\"request\",\"command\":\"continue\",\"arguments\":{\"stepaction\":\"out\"}}");
     208    v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.characters()), cmd.length(), new v8::Debug::ClientData());
     209    didResume();
     210#endif
     211}
     212
     213ScriptState* ScriptDebugServer::currentCallFrameState()
     214{
     215    return m_currentCallFrameState;
     216}
     217
     218v8::Handle<v8::Value> ScriptDebugServer::currentCallFrameV8()
     219{
     220#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     221    if (!m_currentCallFrame.IsEmpty())
     222        return m_currentCallFrame;
     223
     224    // Check on a bp.
     225    v8::Handle<v8::Function> currentCallFrameFunction = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("currentCallFrame")));
     226    v8::Handle<v8::Value> argv[] = { m_executionState };
     227    v8::Handle<v8::Value> result = currentCallFrameFunction->Call(m_debuggerScript, 1, argv);
     228    m_currentCallFrame = v8::Persistent<v8::Value>::New(result);
     229    return result;
     230#else
     231    return v8::Handle<v8::Value>();
     232#endif
     233}
     234
     235void ScriptDebugServer::onV8DebugMessage(const v8::Debug::Message& message)
     236{
     237    ScriptDebugServer::shared().handleV8DebugMessage(message);
     238}
     239
     240void ScriptDebugServer::onV8DebugHostDispatch()
     241{
     242    ScriptDebugServer::shared().handleV8DebugHostDispatch();
     243}
     244
     245void ScriptDebugServer::handleV8DebugHostDispatch()
     246{
     247    if (!s_messageLoopDispatchHandler)
     248        return;
     249
     250    Vector<WebCore::Page*> pages;
     251    for (ListenersMap::iterator it = m_listenersMap.begin(); it != m_listenersMap.end(); ++it)
     252        pages.append(it->first);
     253   
     254    s_messageLoopDispatchHandler(pages);
     255}
     256
     257void ScriptDebugServer::handleV8DebugMessage(const v8::Debug::Message& message)
     258{
     259    v8::HandleScope scope;
     260
     261    if (!message.IsEvent())
     262        return;
     263
     264    // Ignore unsupported event types.
     265    if (message.GetEvent() != v8::AfterCompile && message.GetEvent() != v8::Break)
     266        return;
     267
     268    v8::Handle<v8::Context> context = message.GetEventContext();
     269    // If the context is from one of the inpected tabs it should have its context
     270    // data. Skip events from unknown contexts.
     271    if (context.IsEmpty())
     272        return;
     273
     274    // Test that context has associated global dom window object.
     275    v8::Handle<v8::Object> global = context->Global();
     276    if (global.IsEmpty())
     277        return;
     278
     279    global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global);
     280    if (global.IsEmpty())
     281        return;
     282
     283    Frame* frame = V8Proxy::retrieveFrame(context);
     284    if (frame) {
     285        ScriptDebugListener* listener = m_listenersMap.get(frame->page());
     286        if (listener) {
     287            if (message.GetEvent() == v8::AfterCompile) {
     288                v8::Context::Scope contextScope(v8::Debug::GetDebugContext());
     289                v8::Local<v8::Object> args = v8::Object::New();
     290                args->Set(v8::String::New("eventData"), message.GetEventData());
     291                v8::Handle<v8::Function> onAfterCompileFunction = v8::Local<v8::Function>::Cast(m_debuggerScript->Get(v8::String::New("getAfterCompileScript")));
     292                v8::Handle<v8::Value> argv[] = { message.GetExecutionState(), args };
     293                v8::Handle<v8::Value> value = onAfterCompileFunction->Call(m_debuggerScript, 2, argv);
     294                ASSERT(value->IsObject());
     295                v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
     296                dispatchDidParseSource(listener, object);
     297            } else if (message.GetEvent() == v8::Break) {
     298                m_executionState = v8::Persistent<v8::Object>::New(message.GetExecutionState());
     299                m_currentCallFrameState = mainWorldScriptState(frame);
     300                listener->didPause();
     301                m_currentCallFrameState = 0;
     302            }
     303        }
     304    }
     305}
     306
     307void ScriptDebugServer::dispatchDidParseSource(ScriptDebugListener* listener, v8::Handle<v8::Object> object)
     308{
     309    String contextData = toWebCoreStringWithNullCheck(object->Get(v8::String::New("contextData")));
     310    if (contextData != m_contextDataMap.get(listener))
     311        return;
     312
     313    listener->didParseSource(
     314        toWebCoreStringWithNullCheck(object->Get(v8::String::New("id"))),
     315        toWebCoreStringWithNullCheck(object->Get(v8::String::New("name"))),
     316        toWebCoreStringWithNullCheck(object->Get(v8::String::New("source"))),
     317        object->Get(v8::String::New("lineOffset"))->ToInteger()->Value());
     318}
     319
     320void ScriptDebugServer::ensureDebuggerScriptCompiled()
     321{
     322    if (m_debuggerScript.IsEmpty()) {
     323        v8::HandleScope scope;
     324        v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
     325        v8::Context::Scope contextScope(debuggerContext);
     326        m_debuggerScript = v8::Persistent<v8::Object>::New(v8::Handle<v8::Object>::Cast(v8::Script::Compile(v8String(m_debuggerScriptSource))->Run()));
     327    }
     328}
     329
     330void ScriptDebugServer::didResume()
     331{
     332    if (!m_currentCallFrame.IsEmpty()) {
     333        m_currentCallFrame.Dispose();
     334        m_currentCallFrame.Clear();
     335    }
     336    if (!m_executionState.IsEmpty()) {
     337        m_executionState.Dispose();
     338        m_executionState.Clear();
     339    }
    49340}
    50341
  • trunk/WebCore/bindings/v8/ScriptDebugServer.h

    r57231 r57660  
    3737#include "ScriptBreakpoint.h"
    3838#include "ScriptState.h"
     39#include "StringHash.h"
    3940#include "Timer.h"
    40 
     41#include <v8-debug.h>
     42#include <wtf/HashMap.h>
    4143#include <wtf/Noncopyable.h>
    4244
    4345namespace WebCore {
    4446
     47class Page;
    4548class ScriptDebugListener;
    4649
     
    5861    static bool topStackFrame(String& sourceName, int& lineNumber, String& functionName);
    5962
    60     void addListener(ScriptDebugListener*, Page*) { }
    61     void removeListener(ScriptDebugListener*, Page*) { }
     63    void addListener(ScriptDebugListener*, Page*);
     64    void removeListener(ScriptDebugListener*, Page*);
    6265
    63     void setBreakpoint(const String& sourceID, unsigned lineNumber, ScriptBreakpoint breakpoint) { }
    64     void removeBreakpoint(const String& sourceID, unsigned lineNumber) { }
    65     void clearBreakpoints() { }
    66     void setBreakpointsActivated(bool activated) { }
     66    void setBreakpoint(const String& sourceID, unsigned lineNumber, ScriptBreakpoint breakpoint);
     67    void removeBreakpoint(const String& sourceID, unsigned lineNumber);
     68    void clearBreakpoints();
     69    void setBreakpointsActivated(bool activated);
    6770
    6871    enum PauseOnExceptionsState {
     
    7174        PauseOnUncaughtExceptions
    7275    };
    73     PauseOnExceptionsState pauseOnExceptionsState() const { return DontPauseOnExceptions; }
    74     void setPauseOnExceptionsState(PauseOnExceptionsState) { }
     76    PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; }
     77    void setPauseOnExceptionsState(PauseOnExceptionsState pauseOnExceptionsState) { m_pauseOnExceptionsState = pauseOnExceptionsState; }
    7578
    7679    void pauseProgram() { }
    77     void continueProgram() { }
    78     void stepIntoStatement() { }
    79     void stepOverStatement() { }
    80     void stepOutOfFunction() { }
     80    void continueProgram();
     81    void stepIntoStatement();
     82    void stepOverStatement();
     83    void stepOutOfFunction();
    8184
    8285    void recompileAllJSFunctionsSoon() { }
    8386    void recompileAllJSFunctions(Timer<ScriptDebugServer>* = 0) { }
    8487
    85     ScriptState* currentCallFrameState() { return 0; }
     88    ScriptState* currentCallFrameState();
    8689
    8790    void pageCreated(Page*) { }
    8891
     92    // v8-specific methods.
     93    void setDebuggerScriptSource(const String& scriptSource);
     94
     95    typedef void (*MessageLoopDispatchHandler)(const Vector<WebCore::Page*>&);
     96    static void setMessageLoopDispatchHandler(MessageLoopDispatchHandler messageLoopDispatchHandler) { s_messageLoopDispatchHandler = messageLoopDispatchHandler; }
     97
     98    v8::Handle<v8::Value> currentCallFrameV8();
     99
    89100private:
    90     ScriptDebugServer() { }
     101    ScriptDebugServer();
    91102    ~ScriptDebugServer() { }
     103
     104    static void onV8DebugMessage(const v8::Debug::Message& message);
     105    static void onV8DebugHostDispatch();
     106
     107    void handleV8DebugMessage(const v8::Debug::Message& message);
     108    void handleV8DebugHostDispatch();
     109
     110    void dispatchDidParseSource(ScriptDebugListener* listener, v8::Handle<v8::Object> sourceObject);
     111   
     112    void ensureDebuggerScriptCompiled();
     113    void didResume();
    92114
    93115    static void createUtilityContext();
     
    103125    // Utility context holding JavaScript functions used internally.
    104126    static v8::Persistent<v8::Context> s_utilityContext;
     127
     128    typedef HashMap<Page*, ScriptDebugListener*> ListenersMap;
     129    ListenersMap m_listenersMap;
     130    typedef HashMap<ScriptDebugListener*, String> ContextDataMap;
     131    ContextDataMap m_contextDataMap;
     132    String m_debuggerScriptSource;
     133    PauseOnExceptionsState m_pauseOnExceptionsState;
     134    v8::Persistent<v8::Object> m_debuggerScript;
     135    ScriptState* m_currentCallFrameState;
     136    v8::Persistent<v8::Value> m_currentCallFrame;
     137    v8::Persistent<v8::Object> m_executionState;
     138
     139    static MessageLoopDispatchHandler s_messageLoopDispatchHandler;
    105140};
    106141
  • trunk/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp

    r56844 r57660  
    4040#include "Node.h"
    4141#include "Page.h"
     42#include "ScriptDebugServer.h"
    4243#include "SerializedScriptValue.h"
    4344
     
    111112      scriptHostWrapper,
    112113      windowGlobal,
    113       v8::Number::New(id)
     114      v8::Number::New(id),
     115      v8::String::New("v8")
    114116    };
    115     v8::Local<v8::Value> injectedScriptValue = v8::Function::Cast(*v)->Call(windowGlobal, 3, args);
     117    v8::Local<v8::Value> injectedScriptValue = v8::Function::Cast(*v)->Call(windowGlobal, 4, args);
    116118    v8::Local<v8::Object> injectedScript(v8::Object::Cast(*injectedScriptValue));
    117119    return ScriptObject(inspectedScriptState, injectedScript);
     
    157159{
    158160    INC_STATS("InjectedScriptHost.currentCallFrame()");
    159     return v8::Undefined();
     161    return ScriptDebugServer::shared().currentCallFrameV8();
    160162}
    161163
     
    163165{
    164166    INC_STATS("InjectedScriptHost.isActivation()");
    165     return v8::Undefined();
     167    return v8::Boolean::New(true);
    166168}
    167169#endif
  • trunk/WebCore/inspector/front-end/InjectedScript.js

    r57405 r57660  
    2727 */
    2828
    29 var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
     29var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId, jsEngine) {
    3030
    3131var InjectedScript = {};
     
    126126        return false;
    127127    var properties = [];
     128   
    128129    var propertyNames = ignoreHasOwnProperty ? InjectedScript._getPropertyNames(object) : Object.getOwnPropertyNames(object);
    129130    if (!ignoreHasOwnProperty && object.__proto__)
    130131        propertyNames.push("__proto__");
    131132
     133    if (jsEngine === "v8") {
     134        // Check if the object is a scope.
     135        if (InjectedScript._isScopeProxy(objectProxy)) {
     136            propertyNames = [];
     137            for (var name in object)
     138                propertyNames.push(name);
     139        } else {
     140            // FIXME(http://crbug.com/41243): Object.getOwnPropertyNames may return duplicated names.
     141            var a = [];
     142            propertyNames.sort();
     143            var prev;
     144            for (var i = 0; i < propertyNames.length; i++) {
     145                var n = propertyNames[i];
     146                if (n != prev)
     147                    a.push(n);
     148                prev = n;
     149            }
     150            propertyNames = a;
     151        }
     152    }
     153   
    132154    // Go over properties, prepare results.
    133155    for (var i = 0; i < propertyNames.length; ++i) {
     
    158180    return properties;
    159181}
     182
     183InjectedScript._isScopeProxy = function(objectProxy)
     184{
     185    var objectId = objectProxy.objectId;
     186    return typeof objectId === "object" && !objectId.thisObject;
     187}
    160188
    161189InjectedScript.setPropertyValue = function(objectProxy, propertyName, expression)
     
    814842}
    815843
     844// FIXME(37663): unify scope chain representation and remove this if.
     845if (jsEngine === "v8") {
     846
     847InjectedScript.CallFrameProxy.prototype = {
     848   
     849
     850    _wrapScopeChain: function(callFrame)
     851    {
     852        var ScopeType = { Global: 0,
     853                          Local: 1,
     854                          With: 2,
     855                          Closure: 3,
     856                          Catch: 4 };
     857        var scopeChain = callFrame.scopeChain;
     858        var scopeChainProxy = [];
     859        for (var i = 0; i < scopeChain.length; i += 2) {
     860            var scopeType = scopeChain[i];
     861            var scopeObject = scopeChain[i + 1];
     862            var scopeObjectProxy = InjectedScript.createProxyObject(scopeObject, { callFrame: this.id, chainIndex: (i + 1) }, true);
     863
     864            var foundLocalScope = false;
     865            switch(scopeType) {
     866                case ScopeType.Local: {
     867                    foundLocalScope = true;
     868                    scopeObjectProxy.isLocal = true;
     869                    scopeObjectProxy.thisObject = InjectedScript.createProxyObject(callFrame.thisObject, { callFrame: this.id, thisObject: true }, true);
     870                    break;
     871                }
     872                case ScopeType.Closure: {
     873                    scopeObjectProxy.isClosure = true;
     874                    break;
     875                }
     876                case ScopeType.With: {
     877                    scopeObjectProxy.isWithBlock = true;
     878                    break;
     879                }
     880            }
     881
     882            if (foundLocalScope) {
     883                if (scopeObject instanceof inspectedWindow.Element)
     884                    scopeObjectProxy.isElement = true;
     885                else if (scopeObject instanceof inspectedWindow.Document)
     886                    scopeObjectProxy.isDocument = true;
     887            }
     888 
     889            scopeChainProxy.push(scopeObjectProxy);
     890        }
     891        return scopeChainProxy;
     892    }
     893}
     894
     895} else {
     896
    816897InjectedScript.CallFrameProxy.prototype = {
    817898    _wrapScopeChain: function(callFrame)
     
    841922        return scopeChainProxy;
    842923    }
     924}
     925
    843926}
    844927
  • trunk/WebCore/inspector/front-end/ScriptsPanel.js

    r55771 r57660  
    199199
    200200    this._debuggerEnabled = Preferences.debuggerAlwaysEnabled;
     201    if (Preferences.debuggerAlwaysEnabled)
     202        this._attachDebuggerWhenShown = true;
    201203    this.reset();
    202204}
  • trunk/WebKit/chromium/ChangeLog

    r57655 r57660  
     12010-04-15  Yury Semikhatsky  <yurys@google.com>
     2
     3        Reviewed by Pavel Feldman.
     4
     5        Support basic debugging capabilities including step in/over/out in v8
     6        implementation of ScriptDebugServer.
     7
     8        https://bugs.webkit.org/show_bug.cgi?id=37604
     9
     10        * WebKit.gypi:
     11        * src/DebuggerAgent.h:
     12        * src/DebuggerAgentImpl.cpp:
     13        (WebKit::DebuggerAgentImpl::setDebuggerScriptSource):
     14        * src/DebuggerAgentImpl.h:
     15        * src/DebuggerAgentManager.cpp:
     16        (WebKit::DebuggerAgentManager::hostDispatchHandler):
     17        (WebKit::DebuggerAgentManager::debugAttach):
     18        (WebKit::DebuggerAgentManager::debugDetach):
     19        (WebKit::DebuggerAgentManager::setMessageLoopDispatchHandler):
     20        * src/DebuggerAgentManager.h:
     21        * src/InspectorFrontendClientImpl.cpp:
     22        (WebKit::InspectorFrontendClientImpl::windowObjectCleared):
     23        * src/js/DebuggerScript.js: Added.
     24        (debuggerScriptConstructor.DebuggerScript.getAfterCompileScript):
     25        (debuggerScriptConstructor.DebuggerScript.getScripts):
     26        (debuggerScriptConstructor.DebuggerScript._formatScript):
     27        (debuggerScriptConstructor.DebuggerScript.setBreakpoint):
     28        (debuggerScriptConstructor.DebuggerScript.removeBreakpoint):
     29        (debuggerScriptConstructor.DebuggerScript.currentCallFrame):
     30        (debuggerScriptConstructor.DebuggerScript.stepIntoStatement):
     31        (debuggerScriptConstructor.DebuggerScript.stepOverStatement):
     32        (debuggerScriptConstructor.DebuggerScript.stepOutOfFunction):
     33        (debuggerScriptConstructor.DebuggerScript.clearBreakpoints):
     34        (debuggerScriptConstructor.DebuggerScript.setBreakpointsActivated):
     35        (debuggerScriptConstructor.DebuggerScript._frameMirrorToJSCallFrame):
     36        (debuggerScriptConstructor.DebuggerScript._webkitToV8LineNumber):
     37        (debuggerScriptConstructor.DebuggerScript._v8ToWwebkitLineNumber):
     38        (debuggerScriptConstructor):
     39        * src/js/DevTools.js:
     40        (WebInspector.loaded):
     41        (.):
     42        ():
     43        * src/js/DevToolsHostStub.js:
     44        (.RemoteDebuggerAgentStub.prototype.setDebuggerScriptSource):
     45        * src/js/InspectorControllerImpl.js:
     46        (devtools.InspectorBackendImpl):
     47
    1482010-04-15  Ben Murdoch  <benm@google.com>
    249
  • trunk/WebKit/chromium/WebKit.gypi

    r57220 r57660  
    3636            'src/js/InspectorControllerImpl.js',
    3737            'src/js/DebuggerAgent.js',
     38            'src/js/DebuggerScript.js',
    3839            'src/js/ProfilerAgent.js',
    3940            'src/js/ProfilerProcessor.js',
  • trunk/WebKit/chromium/src/DebuggerAgent.h

    r54592 r57660  
    4141    \
    4242    /* Request v8 to process all debug commands in the queue. */ \
    43     METHOD0(processDebugCommands)
     43    METHOD0(processDebugCommands) \
     44    \
     45    /* Push DebuggerScript.js content to the agent. */ \
     46    METHOD1(setDebuggerScriptSource, String)
    4447
    4548DEFINE_RPC_CLASS(DebuggerAgent, DEBUGGER_AGENT_STRUCT)
  • trunk/WebKit/chromium/src/DebuggerAgentImpl.cpp

    r55726 r57660  
    3636#include "Frame.h"
    3737#include "Page.h"
     38#include "ScriptDebugServer.h"
    3839#include "V8Binding.h"
    3940#include "WebDevToolsAgentImpl.h"
     
    7778    DebuggerAgentManager::UtilityContextScope utilityScope;
    7879    v8::Debug::ProcessDebugMessages();
     80}
     81
     82void DebuggerAgentImpl::setDebuggerScriptSource(const String& source)
     83{
     84    WebCore::ScriptDebugServer::shared().setDebuggerScriptSource(source);
    7985}
    8086
  • trunk/WebKit/chromium/src/DebuggerAgentImpl.h

    r55726 r57660  
    6161    virtual void getContextId();
    6262    virtual void processDebugCommands();
     63    virtual void setDebuggerScriptSource(const String&);
    6364
    6465    void debuggerOutput(const WebCore::String& out);
  • trunk/WebKit/chromium/src/DebuggerAgentManager.cpp

    r54232 r57660  
    3535#include "Frame.h"
    3636#include "PageGroupLoadDeferrer.h"
     37#include "ScriptDebugServer.h"
    3738#include "V8Proxy.h"
    3839#include "WebDevToolsAgentImpl.h"
     
    7374
    7475
     76void DebuggerAgentManager::hostDispatchHandler(const Vector<WebCore::Page*>& pages)
     77{
     78    if (!s_messageLoopDispatchHandler)
     79        return;
     80
     81    if (s_inHostDispatchHandler)
     82        return;
     83
     84    s_inHostDispatchHandler = true;
     85
     86    Vector<WebViewImpl*> views;
     87    // 1. Disable active objects and input events.
     88    for (size_t i = 0; i < pages.size(); i++) {
     89        WebCore::Page* page = pages[i];
     90        WebViewImpl* view = WebViewImpl::fromPage(page);
     91        s_pageDeferrers.set(view , new WebCore::PageGroupLoadDeferrer(page, true));
     92        views.append(view);
     93        view->setIgnoreInputEvents(true);
     94    }
     95
     96    // 2. Process messages.
     97    s_messageLoopDispatchHandler();
     98
     99    // 3. Bring things back.
     100    for (Vector<WebViewImpl*>::iterator it = views.begin(); it != views.end(); ++it) {
     101        if (s_pageDeferrers.contains(*it)) {
     102            // The view was not closed during the dispatch.
     103            (*it)->setIgnoreInputEvents(false);
     104        }
     105    }
     106    deleteAllValues(s_pageDeferrers);
     107    s_pageDeferrers.clear();
     108
     109    s_inHostDispatchHandler = false;
     110}
     111
    75112void DebuggerAgentManager::debugHostDispatchHandler()
    76113{
     
    117154void DebuggerAgentManager::debugAttach(DebuggerAgentImpl* debuggerAgent)
    118155{
     156#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     157    return;
     158#endif
    119159    if (!s_attachedAgentsMap) {
    120160        s_attachedAgentsMap = new AttachedAgentsMap();
     
    129169void DebuggerAgentManager::debugDetach(DebuggerAgentImpl* debuggerAgent)
    130170{
     171#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     172    return;
     173#endif
    131174    if (!s_attachedAgentsMap) {
    132175        ASSERT_NOT_REACHED();
     
    250293{
    251294    s_messageLoopDispatchHandler = handler;
     295    WebCore::ScriptDebugServer::setMessageLoopDispatchHandler(DebuggerAgentManager::hostDispatchHandler);
    252296}
    253297
  • trunk/WebKit/chromium/src/DebuggerAgentManager.h

    r54232 r57660  
    3232#define DebuggerAgentManager_h
    3333
     34#include "WebCString.h"
    3435#include "WebDevToolsAgent.h"
    3536#include <v8-debug.h>
    3637#include <wtf/HashMap.h>
    3738#include <wtf/Noncopyable.h>
     39#include <wtf/Vector.h>
    3840
    3941namespace WebCore {
     42class Page;
    4043class PageGroupLoadDeferrer;
    4144class String;
     
    98101    ~DebuggerAgentManager();
    99102
     103    static void hostDispatchHandler(const Vector<WebCore::Page*>&);
    100104    static void debugHostDispatchHandler();
    101105    static void onV8DebugMessage(const v8::Debug::Message& message);
  • trunk/WebKit/chromium/src/InspectorFrontendClientImpl.cpp

    r57146 r57660  
    7070
    7171    global->Set(v8::String::New("InspectorFrontendHost"), frontendHostObj);
     72#if ENABLE(V8_SCRIPT_DEBUG_SERVER)
     73    global->Set(v8::String::New("v8ScriptDebugServerEnabled"), v8::True());
     74#endif
    7275}
    7376
  • trunk/WebKit/chromium/src/js/DevTools.js

    r57220 r57660  
    184184    Preferences.debuggerAlwaysEnabled = true;
    185185    Preferences.profilerAlwaysEnabled = true;
     186    RemoteDebuggerAgent.setDebuggerScriptSource("(" + debuggerScriptConstructor + ")();");
     187 
    186188    oldLoaded.call(this);
    187189
     
    189191};
    190192
     193
     194if (!window.v8ScriptDebugServerEnabled) {
    191195
    192196/**
     
    226230
    227231
    228 /**
    229  * @param {string} type Type of the the property value("object" or "function").
    230  * @param {string} className Class name of the property value.
    231  * @constructor
    232  */
    233 WebInspector.UnresolvedPropertyValue = function(type, className)
    234 {
    235     this.type = type;
    236     this.className = className;
    237 };
    238 
    239 
    240232(function()
    241233{
     
    248240    };
    249241})();
     242
     243
     244(function () {
     245var orig = InjectedScriptAccess.prototype.getProperties;
     246InjectedScriptAccess.prototype.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback)
     247{
     248    if (objectProxy.isScope)
     249        devtools.tools.getDebuggerAgent().resolveScope(objectProxy.objectId, callback);
     250    else if (objectProxy.isV8Ref)
     251        devtools.tools.getDebuggerAgent().resolveChildren(objectProxy.objectId, callback, false);
     252    else
     253        orig.apply(this, arguments);
     254};
     255})();
     256
     257
     258(function()
     259{
     260InjectedScriptAccess.prototype.evaluateInCallFrame = function(callFrameId, code, objectGroup, callback)
     261{
     262    //TODO(pfeldman): remove once 49084 is rolled.
     263    if (!callback)
     264        callback = objectGroup;
     265    devtools.tools.getDebuggerAgent().evaluateInCallFrame(callFrameId, code, callback);
     266};
     267})();
     268
     269
     270(function()
     271{
     272var orig = InjectedScriptAccess.prototype.getCompletions;
     273InjectedScriptAccess.prototype.getCompletions = function(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions)
     274{
     275    if (typeof callFrameId === "number")
     276        devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame(expressionString, callFrameId, reportCompletions);
     277    else
     278        return orig.apply(this, arguments);
     279};
     280})();
     281
     282}
    250283
    251284
     
    344377
    345378
    346 (function () {
    347 var orig = InjectedScriptAccess.prototype.getProperties;
    348 InjectedScriptAccess.prototype.getProperties = function(objectProxy, ignoreHasOwnProperty, abbreviate, callback)
    349 {
    350     if (objectProxy.isScope)
    351         devtools.tools.getDebuggerAgent().resolveScope(objectProxy.objectId, callback);
    352     else if (objectProxy.isV8Ref)
    353         devtools.tools.getDebuggerAgent().resolveChildren(objectProxy.objectId, callback, false);
    354     else
    355         orig.apply(this, arguments);
    356 };
    357 })();
    358 
    359 
    360 (function()
    361 {
    362 InjectedScriptAccess.prototype.evaluateInCallFrame = function(callFrameId, code, objectGroup, callback)
    363 {
    364     //TODO(pfeldman): remove once 49084 is rolled.
    365     if (!callback)
    366         callback = objectGroup;
    367     devtools.tools.getDebuggerAgent().evaluateInCallFrame(callFrameId, code, callback);
    368 };
    369 })();
    370 
    371 
    372 (function()
    373 {
    374 var orig = InjectedScriptAccess.prototype.getCompletions;
    375 InjectedScriptAccess.prototype.getCompletions = function(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions)
    376 {
    377     if (typeof callFrameId === "number")
    378         devtools.tools.getDebuggerAgent().resolveCompletionsOnFrame(expressionString, callFrameId, reportCompletions);
    379     else
    380         return orig.apply(this, arguments);
    381 };
    382 })();
    383 
    384 
    385379// We need to have a place for postponed tasks
    386380// which should be executed when all the messages between agent and frontend
  • trunk/WebKit/chromium/src/js/DevToolsHostStub.js

    r54592 r57660  
    5656
    5757
     58RemoteDebuggerAgentStub.prototype.setDebuggerScriptSource = function(source)
     59{
     60};
     61
     62
    5863/**
    5964 * @constructor
  • trunk/WebKit/chromium/src/js/InspectorControllerImpl.js

    r57505 r57660  
    8787    this.installInspectorControllerDelegate_("setRuleSelector");
    8888    this.installInspectorControllerDelegate_("addRule");
     89
     90    if (window.v8ScriptDebugServerEnabled) {
     91    this.installInspectorControllerDelegate_("disableDebugger");
     92    this.installInspectorControllerDelegate_("enableDebugger");
     93    this.installInspectorControllerDelegate_("setBreakpoint");
     94    this.installInspectorControllerDelegate_("removeBreakpoint");
     95    this.installInspectorControllerDelegate_("activateBreakpoints");
     96    this.installInspectorControllerDelegate_("deactivateBreakpoints");
     97    this.installInspectorControllerDelegate_("pauseInDebugger");
     98    this.installInspectorControllerDelegate_("resumeDebugger");
     99    this.installInspectorControllerDelegate_("stepIntoStatementInDebugger");
     100    this.installInspectorControllerDelegate_("stepOutOfFunctionInDebugger");
     101    this.installInspectorControllerDelegate_("stepOverStatementInDebugger");
     102    this.installInspectorControllerDelegate_("setPauseOnExceptionsState");
     103    }
    89104};
    90105devtools.InspectorBackendImpl.prototype.__proto__ = WebInspector.InspectorBackendStub.prototype;
     
    108123};
    109124
     125
     126if (!window.v8ScriptDebugServerEnabled) {
    110127
    111128devtools.InspectorBackendImpl.prototype.setBreakpoint = function(sourceID, line, enabled, condition)
     
    194211};
    195212
     213}
     214
    196215
    197216/**
Note: See TracChangeset for help on using the changeset viewer.