From: Aurindam Jana Date: Thu, 24 Nov 2011 17:12:17 +0000 (+0100) Subject: V8DebugService: Optimize Code. X-Git-Tag: qt-v5.0.0-alpha1~1020 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ad78e5fd290f69510f02b3b6bf3b6d2f52d59423;p=profile%2Fivi%2Fqtdeclarative.git V8DebugService: Optimize Code. Replace usage of QJSEngine with V8 APIs. Change-Id: I5221d11c1fb96a4912063d452af437a7f5bdb471 Reviewed-by: Christiaan Janssen --- diff --git a/src/declarative/debugger/qv8debugservice.cpp b/src/declarative/debugger/qv8debugservice.cpp index d28cd13..8741dd8 100644 --- a/src/declarative/debugger/qv8debugservice.cpp +++ b/src/declarative/debugger/qv8debugservice.cpp @@ -42,12 +42,61 @@ #include "qv8debugservice_p.h" #include "qdeclarativedebugservice_p_p.h" #include -#include #include +#include #include #include +#define DEBUGGER_SCRIPT "(function(){"\ + "var DebuggerScript = {};"\ + "DebuggerScript.getScriptName = function(eventData){"\ + "return eventData.script_.script_.nameOrSourceURL();"\ + "};"\ + "DebuggerScript.getScripts = function(){"\ + "var result = [];"\ + "var scripts = Debug.scripts();"\ + "for (var i = 0; i < scripts.length; ++i) {"\ + "var script = scripts[i];"\ + "if (script.type == Debug.ScriptType.Native) continue;"\ + "result.push(script.nameOrSourceURL());"\ + "}"\ + "return result;"\ + "};"\ + "return DebuggerScript;"\ + "})();" + +#define DEBUGGER_UTILITY "(function(){"\ + "var DebuggerUtility = {};"\ + "DebuggerUtility.parseRequest = function(request){"\ + "return JSON.parse(request);"\ + "};"\ + "DebuggerUtility.stringifyRequest = function(request){"\ + "return JSON.stringify(request);"\ + "};"\ + "return DebuggerUtility;"\ + "})();" + +const char *V8_DEBUGGER_KEY_CONNECT = "connect"; +const char *V8_DEBUGGER_KEY_INTERRUPT = "interrupt"; +const char *V8_DEBUGGER_KEY_DISCONNECT = "disconnect"; +const char *V8_DEBUGGER_KEY_CLEARBREAKPOINT = "clearbreakpoint"; +const char *V8_DEBUGGER_KEY_CHANGEBREAKPOINT = "changebreakpoint"; +const char *V8_DEBUGGER_KEY_SETBREAKPOINT = "setbreakpoint"; +const char *V8_DEBUGGER_KEY_TARGET = "target"; +const char *V8_DEBUGGER_KEY_SCRIPT = "script"; +const char *V8_DEBUGGER_KEY_COMMAND = "command"; +const char *V8_DEBUGGER_KEY_SEQ = "seq"; +const char *V8_DEBUGGER_KEY_REQUEST_SEQ = "request_seq"; +const char *V8_DEBUGGER_KEY_SUCCESS = "success"; +const char *V8_DEBUGGER_KEY_BREAKPOINT = "breakpoint"; +const char *V8_DEBUGGER_KEY_ARGUMENTS = "arguments"; +const char *V8_DEBUGGER_KEY_ENABLED = "enabled"; +const char *V8_DEBUGGER_KEY_TYPE = "type"; +const char *V8_DEBUGGER_KEY_EVENT = "event"; +const char *V8_DEBUGGER_KEY_BODY = "body"; +const char *V8_DEBUGGER_KEY_RUNNING = "running"; + QT_BEGIN_NAMESPACE struct SignalHandlerData @@ -77,7 +126,7 @@ void DebugMessageHandler(const v8::Debug::Message& message) v8ServiceInstancePtr->debugMessageHandler(response, message.WillStartRunning()); if (event == v8::AfterCompile) { - v8ServiceInstancePtr->appendSourcePath(response); + v8ServiceInstancePtr->appendSourcePath(message.GetEventData()); } //TODO::v8::Exception } @@ -88,22 +137,17 @@ public: : connectReceived(false) , scheduleBreak(false) , debuggerThreadIsolate(0) - , debuggerThreadEngine(0) - , guiThreadIsolate(0) - , guiThreadEngine(0) , isRunning(true) - , internalRequests(0) { } ~QV8DebugServicePrivate() { - delete debuggerThreadEngine; + debuggerScript.Dispose(); + debuggerUtility.Dispose(); + debuggerUtilityContext.Dispose(); if (debuggerThreadIsolate) debuggerThreadIsolate->Dispose(); - delete guiThreadEngine; - if (guiThreadIsolate) - guiThreadIsolate->Dispose(); } void initializeDebuggerThread(); @@ -111,14 +155,16 @@ public: void sendDebugMessage(const QString &message); void updateSourcePath(const QString &sourcePath); static QByteArray packMessage(const QString &message); + QString createResponse(const QVariantMap &response) const; + v8::Handle createV8Object(const QVariantMap &map) const; bool connectReceived; bool scheduleBreak; v8::Isolate *debuggerThreadIsolate; - QJSEngine *debuggerThreadEngine; - v8::Isolate *guiThreadIsolate; - QJSEngine *guiThreadEngine; + v8::Persistent debuggerScript; + v8::Persistent debuggerUtility; + v8::Persistent debuggerUtilityContext; // keep messageReceived() from running until initialize() has finished QMutex initializeMutex; @@ -127,7 +173,6 @@ public: QHash sourcePath; QHash requestCache; QHash handlersList; - int internalRequests; }; QV8DebugService::QV8DebugService(QObject *parent) @@ -139,7 +184,7 @@ QV8DebugService::QV8DebugService(QObject *parent) // wait for statusChanged() -> initialize() d->initializeMutex.lock(); if (registerService() == Enabled) { - initialize(); + initialize(false); // ,block mode, client attached while (!d->connectReceived) { waitForMessage(); @@ -184,65 +229,25 @@ void QV8DebugService::debugMessageHandler(const QString &message, bool willStart if (d->scheduleBreak) scheduledDebugBreak(); - if (d->internalRequests > 0) { - // there are outstanding internal requests, - // check the sequence number: internal if seq is -1 - - QVariantMap responseMap; - { - v8::Isolate::Scope i_scope(d->guiThreadIsolate); - QJSValue parser = d->guiThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue out = parser.call(QJSValue(), QJSValueList() << QJSValue(message)); - responseMap = out.toVariant().toMap(); - } - - if (responseMap.value(QLatin1String("request_seq")).toInt() == -1) { - if (responseMap.value(QLatin1String("command")) == QLatin1String("scripts")) { - - // Reply to scripts request on connect: - - // { - // "type": "response", - // "request_seq": , - // "command": "scripts", - // "body": [ { "name" : } ] - // } - - QVariantList body = responseMap.value(QLatin1String("body")).toList(); - foreach (const QVariant &listEntry, body) { - QVariantMap entryMap = listEntry.toMap(); - const QString sourcePath = entryMap.value(QLatin1String("name")).toString(); - d->updateSourcePath(sourcePath); - } - } - - d->internalRequests--; - return; - } - } sendMessage(QV8DebugServicePrivate::packMessage(message)); } -void QV8DebugService::appendSourcePath(const QString &message) +void QV8DebugService::appendSourcePath(const v8::Handle &eventData) { Q_D(QV8DebugService); - QVariantMap msgMap; - /* Parse the byte string in a separate isolate - This will ensure that the debug message handler does not - receive any messages related to this operation */ - { - v8::Isolate::Scope scope(d->guiThreadIsolate); - QJSValue parser = d->guiThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue out = parser.call(QJSValue(), QJSValueList() << QJSValue(message)); - msgMap = out.toVariant().toMap(); - } - - const QString sourcePath(msgMap.value(QLatin1String("body")).toMap().value( - QLatin1String("script")).toMap().value( - QLatin1String("name")).toString()); - d->updateSourcePath(sourcePath); + Q_ASSERT(!d->debuggerScript.IsEmpty()); + v8::HandleScope handleScope; + v8::Local debuggerContext = v8::Debug::GetDebugContext(); + v8::Context::Scope contextScope(debuggerContext); + v8::Handle getScriptNameFn = + v8::Local::Cast(d->debuggerScript->Get(v8::String::New("getScriptName"))); + v8::Handle argv[] = { eventData }; + v8::Handle scriptName = getScriptNameFn->Call(d->debuggerScript, 1, argv); + Q_ASSERT(scriptName->IsString()); + + d->updateSourcePath(QJSConverter::toString(scriptName->ToString())); } void QV8DebugService::signalEmitted(const QString &signal) @@ -265,15 +270,36 @@ void QV8DebugService::signalEmitted(const QString &signal) scheduledDebugBreak(); } -void QV8DebugService::initialize() +void QV8DebugService::initialize(bool getCompiledScripts) { Q_D(QV8DebugService); + if (d->debuggerScript.IsEmpty()) { + v8::HandleScope handleScope; + v8::Local debuggerContext = v8::Debug::GetDebugContext(); + v8::Context::Scope contextScope(debuggerContext); + v8::Handle script = v8::Script::New(v8::String::New(DEBUGGER_SCRIPT), 0, 0, v8::Handle(), v8::Script::NativeMode); + d->debuggerScript = v8::Persistent::New(v8::Local::Cast(script->Run())); + } v8::Debug::SetMessageHandler2(DebugMessageHandler); - //Create an isolate & engine for parsing JSON messages in GUI thread - d->guiThreadIsolate = v8::Isolate::New(); - v8::Isolate::Scope scope(d->guiThreadIsolate); - d->guiThreadEngine = new QJSEngine(); + if (getCompiledScripts) { + v8::HandleScope handleScope; + v8::Local debuggerContext = v8::Debug::GetDebugContext(); + v8::Context::Scope contextScope(debuggerContext); + v8::Handle getScriptsFn = + v8::Local::Cast(d->debuggerScript->Get(v8::String::New("getScripts"))); + v8::Handle argv[] = {}; + v8::Handle result = getScriptsFn->Call(d->debuggerScript, 0, argv); + if (result.IsEmpty()) + return; + + Q_ASSERT(!result->IsUndefined() && result->IsArray()); + v8::Handle scripts = v8::Handle::Cast(result); + uint len = scripts->Length(); + for (uint i = 0; i < len; ++i) { + d->updateSourcePath(QJSConverter::toString(scripts->Get(i)->ToString())); + } + } d->initializeMutex.unlock(); } @@ -287,42 +313,22 @@ void QV8DebugService::scheduledDebugBreak() } } +void QV8DebugService::cancelDebugBreak() +{ + v8::Debug::CancelDebugBreak(); +} + // executed in the debugger thread void QV8DebugService::statusChanged(QDeclarativeDebugService::Status newStatus) { Q_D(QV8DebugService); if (newStatus == Enabled) { - if (!d->debuggerThreadEngine) + if (!d->debuggerThreadIsolate) d->initializeDebuggerThread(); // execute in GUI thread d->initializeMutex.lock(); - QMetaObject::invokeMethod(this, "initialize", Qt::QueuedConnection); - - // Request already compiled scripts from v8 (recycling the sequence number from connect) - - // { "seq" : -1, - // "type" : "request", - // "command" : "scripts", - // "arguments" : { "includeSource" : false } - // } - const QString obj(QLatin1String("{}")); - v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); - QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); - jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("request"))); - jsonVal.setProperty(QLatin1String("seq"), QJSValue(-1)); - jsonVal.setProperty(QLatin1String("command"), QJSValue(QLatin1String("scripts"))); - - QJSValue args = parser.call(QJSValue(), QJSValueList() << obj); - - args.setProperty(QLatin1String("includeSource"), QJSValue(false)); - jsonVal.setProperty(QLatin1String("arguments"), args); - - QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); - QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - d->internalRequests++; - d->sendDebugMessage(json.toString()); + QMetaObject::invokeMethod(this, "initialize", Qt::QueuedConnection, Q_ARG(bool, true)); } } @@ -338,7 +344,7 @@ void QV8DebugService::messageReceived(const QByteArray &message) QMutexLocker locker(&d->initializeMutex); if (command == "V8DEBUG") { - if (!d->debuggerThreadEngine) + if (!d->debuggerThreadIsolate) d->initializeDebuggerThread(); @@ -349,193 +355,139 @@ void QV8DebugService::messageReceived(const QByteArray &message) request = QString::fromUtf8(requestArray); } - QVariantMap reqMap; + bool forwardRequestToV8 = false; + Q_ASSERT(!d->debuggerUtility.IsEmpty()); { v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); - QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue out = parser.call(QJSValue(), QJSValueList() << QJSValue(request)); - reqMap = out.toVariant().toMap(); - } - const QString debugCommand(reqMap.value(QLatin1String("command")).toString()); - const int sequence = reqMap.value(QLatin1String("seq")).toInt(); - - if (debugCommand == QLatin1String("connect")) { - d->connectReceived = true; - //Prepare the response string - //Create a json message using v8 debugging protocol - //and send it to client - - // { "type" : "response", - // "request_seq" : , - // "command" : "connect", - // "running" : - // "success" : true - // } - { - const QString obj(QLatin1String("{}")); - v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); - QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); - jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); - - jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); - jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); - jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); - jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - - QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); - QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); - } - } else if (debugCommand == QLatin1String("interrupt")) { - //Prepare the response string - //Create a json message using v8 debugging protocol - //and send it to client - - // { "type" : "response", - // "request_seq" : , - // "command" : "interrupt", - // "running" : - // "success" : true - // } - { - const QString obj(QLatin1String("{}")); - v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); - QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); - jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); - - const int sequence = reqMap.value(QLatin1String("seq")).toInt(); - jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); - jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); - jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); - jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - - QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); - QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); - } - // break has to be executed in gui thread - d->scheduleBreak = true; - QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection); - } else { - bool forwardRequestToV8 = true; - - if (debugCommand == QLatin1String("setbreakpoint")) { - const QVariantMap arguments = reqMap.value(QLatin1String("arguments")).toMap(); - const QString type(arguments.value(QLatin1String("type")).toString()); - if (type == QLatin1String("script")) { - QString fileName(arguments.value(QLatin1String("target")).toString()); + v8::HandleScope handleScope; + v8::Context::Scope contextScope(d->debuggerUtilityContext); + + v8::Handle parseFn = + v8::Local::Cast(d->debuggerUtility->Get(v8::String::New("parseRequest"))); + v8::Handle argv[] = { QJSConverter::toString(request) }; + v8::Handle result = parseFn->Call(d->debuggerUtility, 1, argv); + Q_ASSERT(result->IsObject()); + + v8::Handle requestObj = v8::Handle::Cast(result); + const QString debugCommand = QJSConverter::toString(requestObj->Get(v8::String::New(V8_DEBUGGER_KEY_COMMAND))->ToString()); + const int sequence = requestObj->Get(v8::String::New(V8_DEBUGGER_KEY_SEQ))->Int32Value(); + + if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_CONNECT)) { + d->connectReceived = true; + QVariantMap response; + response.insert(QLatin1String(V8_DEBUGGER_KEY_COMMAND), QVariant(debugCommand)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_REQUEST_SEQ), QVariant(sequence)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_SUCCESS), QVariant(true)); + sendMessage(QV8DebugServicePrivate::packMessage(d->createResponse(response))); + + } else if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_INTERRUPT)) { + // break has to be executed in gui thread + d->scheduleBreak = true; + QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection); + QVariantMap response; + response.insert(QLatin1String(V8_DEBUGGER_KEY_COMMAND), QVariant(debugCommand)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_REQUEST_SEQ), QVariant(sequence)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_SUCCESS), QVariant(true)); + sendMessage(QV8DebugServicePrivate::packMessage(d->createResponse(response))); + + } else if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_DISCONNECT)) { + // cancel break has to be executed in gui thread + QMetaObject::invokeMethod(this, "cancelDebugBreak", Qt::QueuedConnection); + forwardRequestToV8 = true; + + } else if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_CLEARBREAKPOINT)) { + //check if the breakpoint is a negative integer (event breakpoint) + v8::Handle argsObj = requestObj->Get(v8::String::New(V8_DEBUGGER_KEY_ARGUMENTS))->ToObject(); + const int bp = argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_BREAKPOINT))->Int32Value(); - //Check if the filepath has been cached - if (d->sourcePath.contains(fileName)) { - QString filePath = d->sourcePath.value(fileName); - request.replace(fileName, filePath); - } else { - //Store the setbreakpoint message till filepath is resolved - d->requestCache.insertMulti(fileName, request); - forwardRequestToV8 = false; - } - } else if (type == QLatin1String("event")) { - //Do not send this request to v8 - forwardRequestToV8 = false; - - //Prepare the response string - //Create a json message using v8 debugging protocol - //and send it to client - - // { "seq" : , - // "type" : "response", - // "request_seq" : , - // "command" : "setbreakpoint", - // "body" : { "type" : <"function" or "script"> - // "breakpoint" : - // } - // "running" : - // "success" : true - // } - { - const QString obj(QLatin1String("{}")); - v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); - QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); - QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); - jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); - - const int sequence = reqMap.value(QLatin1String("seq")).toInt(); - jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); - jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); - - //Check that the function starts with 'on' - QString eventName(arguments.value(QLatin1String("target")).toString()); - - - if (eventName.startsWith(QLatin1String("on"))) { - SignalHandlerData data; - //Only store the probable signal name. - //Normalize to lower case. - data.functionName = eventName.remove(0,2).toLower(); - data.enabled = arguments.value(QLatin1String("enabled")).toBool(); - d->handlersList.insert(-sequence, data); - - QJSValue args = parser.call(QJSValue(), QJSValueList() << obj); - - args.setProperty(QLatin1String("type"), QJSValue(QLatin1String("event"))); - args.setProperty(QLatin1String("breakpoint"), QJSValue(-sequence)); - - jsonVal.setProperty(QLatin1String("body"), args); - jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); - - } else { - jsonVal.setProperty(QLatin1String("success"), QJSValue(false)); - } - - - jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - - QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); - QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); - } + if (bp < 0) { + d->handlersList.remove(bp); + } else { + forwardRequestToV8 = true; } - } else if (debugCommand == QLatin1String("changebreakpoint")) { + + } else if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_CHANGEBREAKPOINT)) { //check if the breakpoint is a negative integer (event breakpoint) - const QVariantMap arguments = reqMap.value(QLatin1String("arguments")).toMap(); - const int bp = arguments.value(QLatin1String("breakpoint")).toInt(); + v8::Handle argsObj = requestObj->Get(v8::String::New(V8_DEBUGGER_KEY_ARGUMENTS))->ToObject(); + const int bp = argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_BREAKPOINT))->Int32Value(); if (bp < 0) { SignalHandlerData data = d->handlersList.value(bp); - data.enabled = arguments.value(QLatin1String("enabled")).toBool(); + data.enabled = argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_ENABLED))->BooleanValue(); d->handlersList.insert(bp, data); - forwardRequestToV8 = false; + + } else { + forwardRequestToV8 = true; } - } else if (debugCommand == QLatin1String("clearbreakpoint")) { - //check if the breakpoint is a negative integer (event breakpoint) - const QVariantMap arguments = reqMap.value(QLatin1String("arguments")).toMap(); - const int bp = arguments.value(QLatin1String("breakpoint")).toInt(); - if (bp < 0) { - d->handlersList.remove(bp); - forwardRequestToV8 = false; + } else if (debugCommand == QLatin1String(V8_DEBUGGER_KEY_SETBREAKPOINT)) { + v8::Handle argsObj = requestObj->Get(v8::String::New(V8_DEBUGGER_KEY_ARGUMENTS))->ToObject(); + const QString type = QJSConverter::toString(argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_TYPE))->ToString()); + QString target = QJSConverter::toString(argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_TARGET))->ToString()); + + if (type == QLatin1String(V8_DEBUGGER_KEY_SCRIPT)) { + //check if the script associated with the breakpoint is cached + if (d->sourcePath.contains(target)) { + //replace fileName with correct filePath + request.replace(target, d->sourcePath.value(target)); + forwardRequestToV8 = true; + + } else { + //store the message till file is compiled + d->requestCache.insertMulti(target, request); + } + + } else if (type == QLatin1String(V8_DEBUGGER_KEY_EVENT)) { + //Handle this internally + bool success = true; + if (target.startsWith(QLatin1String("on"))) { + SignalHandlerData data; + //Only store the probable signal name. + //Normalize to lower case. + data.functionName = target.remove(0,2).toLower(); + data.enabled = argsObj->Get(v8::String::New(V8_DEBUGGER_KEY_ENABLED))->BooleanValue(); + d->handlersList.insert(-sequence, data); + } else { + success = false; + } + //TODO::have to send back response + QVariantMap body; + body.insert(QLatin1String(V8_DEBUGGER_KEY_TYPE), QVariant(QLatin1String(V8_DEBUGGER_KEY_EVENT))); + body.insert(QLatin1String(V8_DEBUGGER_KEY_BREAKPOINT), QVariant(-sequence)); + QVariantMap response; + response.insert(QLatin1String(V8_DEBUGGER_KEY_COMMAND), QVariant(debugCommand)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_REQUEST_SEQ), QVariant(sequence)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_SUCCESS), QVariant(success)); + response.insert(QLatin1String(V8_DEBUGGER_KEY_BODY), body); + + sendMessage(QV8DebugServicePrivate::packMessage(d->createResponse(response))); } - } else if (debugCommand == QLatin1String("disconnect")) { - v8::Debug::CancelDebugBreak(); + } else { + //Forward all other requests + forwardRequestToV8 = true; } - - if (forwardRequestToV8) - d->sendDebugMessage(request); } + + if (forwardRequestToV8) + d->sendDebugMessage(request); } } void QV8DebugServicePrivate::initializeDebuggerThread() { - Q_ASSERT(!debuggerThreadEngine); + Q_ASSERT(!debuggerThreadIsolate); //Create an isolate & engine in debugger thread debuggerThreadIsolate = v8::Isolate::New(); v8::Isolate::Scope i_scope(debuggerThreadIsolate); - debuggerThreadEngine = new QJSEngine(); + if (debuggerUtility.IsEmpty()) { + v8::HandleScope handleScope; + debuggerUtilityContext = v8::Context::New(); + v8::Context::Scope contextScope(debuggerUtilityContext); + v8::Handle script = v8::Script::New(v8::String::New(DEBUGGER_UTILITY), 0, 0, v8::Handle(), v8::Script::NativeMode); + debuggerUtility = v8::Persistent::New(v8::Local::Cast(script->Run())); + } } void QV8DebugServicePrivate::sendDebugMessage(const QString &message) @@ -568,4 +520,52 @@ QByteArray QV8DebugServicePrivate::packMessage(const QString &message) return reply; } +QString QV8DebugServicePrivate::createResponse(const QVariantMap &response) const +{ + v8::HandleScope handleScope; + v8::Context::Scope contextScope(debuggerUtilityContext); + + v8::Handle respObj = createV8Object(response); + respObj->Set(v8::String::New(V8_DEBUGGER_KEY_TYPE), v8::String::New("response")); + respObj->Set(v8::String::New(V8_DEBUGGER_KEY_RUNNING), v8::Boolean::New(isRunning)); + v8::Handle stringifyFn = + v8::Local::Cast(debuggerUtility->Get(v8::String::New("stringifyRequest"))); + v8::Handle argv[] = { respObj }; + v8::Handle result = stringifyFn->Call(debuggerScript, 1, argv); + Q_ASSERT(result->IsString()); + + return QJSConverter::toString(result->ToString()); + +} + +v8::Handle QV8DebugServicePrivate::createV8Object(const QVariantMap &map) const +{ + v8::Handle obj = v8::Object::New(); + foreach (const QVariant &var, map) { + v8::Handle key = QJSConverter::toString(map.key(var)); + v8::Handle val; + switch (var.type()) { + case QVariant::Bool: + val = v8::Boolean::New(var.toBool()); + break; + case QVariant::Int: + val = v8::Int32::New(var.toInt()); + break; + case QVariant::String: + val = QJSConverter::toString(var.toString()); + break; + case QVariant::Map: + createV8Object(var.toMap()); + break; + default: + //Add other types when required. + //Not handled currently + break; + } + if (!val.IsEmpty()) + obj->Set(key, val); + } + return obj; +} + QT_END_NAMESPACE diff --git a/src/declarative/debugger/qv8debugservice_p.h b/src/declarative/debugger/qv8debugservice_p.h index 802b77f..2d06390 100644 --- a/src/declarative/debugger/qv8debugservice_p.h +++ b/src/declarative/debugger/qv8debugservice_p.h @@ -54,6 +54,7 @@ // #include "qdeclarativedebugservice_p.h" +#include QT_BEGIN_HEADER @@ -78,13 +79,14 @@ public: void debugMessageHandler(const QString &message, bool willStartRunning); - void appendSourcePath(const QString &message); + void appendSourcePath(const v8::Handle &eventData); void signalEmitted(const QString &signal); private slots: void scheduledDebugBreak(); - void initialize(); + void cancelDebugBreak(); + void initialize(bool); protected: void statusChanged(Status newStatus);