V8DebugService: Optimize Code.
authorAurindam Jana <aurindam.jana@nokia.com>
Thu, 24 Nov 2011 17:12:17 +0000 (18:12 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 25 Nov 2011 14:58:35 +0000 (15:58 +0100)
Replace usage of QJSEngine with V8 APIs.

Change-Id: I5221d11c1fb96a4912063d452af437a7f5bdb471
Reviewed-by: Christiaan Janssen <christiaan.janssen@nokia.com>
src/declarative/debugger/qv8debugservice.cpp
src/declarative/debugger/qv8debugservice_p.h

index d28cd13..8741dd8 100644 (file)
 #include "qv8debugservice_p.h"
 #include "qdeclarativedebugservice_p_p.h"
 #include <private/qv8debug_p.h>
-#include <private/qv8engine_p.h>
 #include <private/qdeclarativeengine_p.h>
+#include <private/qjsconverter_impl_p.h>
 
 #include <QtCore/QHash>
 #include <QtCore/QFileInfo>
 
+#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<v8::Object> createV8Object(const QVariantMap &map) const;
 
     bool connectReceived;
     bool scheduleBreak;
 
     v8::Isolate *debuggerThreadIsolate;
-    QJSEngine *debuggerThreadEngine;
-    v8::Isolate *guiThreadIsolate;
-    QJSEngine *guiThreadEngine;
+    v8::Persistent<v8::Object> debuggerScript;
+    v8::Persistent<v8::Object> debuggerUtility;
+    v8::Persistent<v8::Context> debuggerUtilityContext;
     // keep messageReceived() from running until initialize() has finished
     QMutex initializeMutex;
 
@@ -127,7 +173,6 @@ public:
     QHash<QString, QString> sourcePath;
     QHash<QString, QString> requestCache;
     QHash<int, SignalHandlerData> 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": <number>,
-                //   "command": "scripts",
-                //   "body": [ { "name" : <name of script> } ]
-                // }
-
-                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<v8::Object> &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<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
+    v8::Context::Scope contextScope(debuggerContext);
+    v8::Handle<v8::Function> getScriptNameFn =
+            v8::Local<v8::Function>::Cast(d->debuggerScript->Get(v8::String::New("getScriptName")));
+    v8::Handle<v8::Value> argv[] = { eventData };
+    v8::Handle<v8::Value> 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<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
+        v8::Context::Scope contextScope(debuggerContext);
+        v8::Handle<v8::Script> script = v8::Script::New(v8::String::New(DEBUGGER_SCRIPT), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
+        d->debuggerScript = v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::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<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
+        v8::Context::Scope contextScope(debuggerContext);
+        v8::Handle<v8::Function> getScriptsFn =
+                v8::Local<v8::Function>::Cast(d->debuggerScript->Get(v8::String::New("getScripts")));
+        v8::Handle<v8::Value> argv[] = {};
+        v8::Handle<v8::Value> result = getScriptsFn->Call(d->debuggerScript, 0, argv);
+        if (result.IsEmpty())
+            return;
+
+        Q_ASSERT(!result->IsUndefined() && result->IsArray());
+        v8::Handle<v8::Array> scripts = v8::Handle<v8::Array>::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" : <number>,
-            //   "command"     : "connect",
-            //   "running"     : <is the VM running after sending this response>
-            //   "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" : <number>,
-            //   "command"     : "interrupt",
-            //   "running"     : <is the VM running after sending this response>
-            //   "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<v8::Function> parseFn =
+                    v8::Local<v8::Function>::Cast(d->debuggerUtility->Get(v8::String::New("parseRequest")));
+            v8::Handle<v8::Value> argv[] = { QJSConverter::toString(request) };
+            v8::Handle<v8::Value> result = parseFn->Call(d->debuggerUtility, 1, argv);
+            Q_ASSERT(result->IsObject());
+
+            v8::Handle<v8::Object> requestObj = v8::Handle<v8::Object>::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<v8::Object> 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"         : <number>,
-                    //   "type"        : "response",
-                    //   "request_seq" : <number>,
-                    //   "command"     : "setbreakpoint",
-                    //   "body"        : { "type"       : <"function" or "script">
-                    //                     "breakpoint" : <break point number of the new break point>
-                    //                   }
-                    //   "running"     : <is the VM running after sending this response>
-                    //   "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<v8::Object> 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<v8::Object> 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<v8::Script> script = v8::Script::New(v8::String::New(DEBUGGER_UTILITY), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
+        debuggerUtility = v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::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<v8::Object> 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<v8::Function> stringifyFn =
+            v8::Local<v8::Function>::Cast(debuggerUtility->Get(v8::String::New("stringifyRequest")));
+    v8::Handle<v8::Value> argv[] = { respObj };
+    v8::Handle<v8::Value> result = stringifyFn->Call(debuggerScript, 1, argv);
+    Q_ASSERT(result->IsString());
+
+    return QJSConverter::toString(result->ToString());
+
+}
+
+v8::Handle<v8::Object> QV8DebugServicePrivate::createV8Object(const QVariantMap &map) const
+{
+    v8::Handle<v8::Object> obj = v8::Object::New();
+    foreach (const QVariant &var, map) {
+        v8::Handle<v8::String> key = QJSConverter::toString(map.key(var));
+        v8::Handle<v8::Value> 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
index 802b77f..2d06390 100644 (file)
@@ -54,6 +54,7 @@
 //
 
 #include "qdeclarativedebugservice_p.h"
+#include <private/qv8_p.h>
 
 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<v8::Object> &eventData);
 
     void signalEmitted(const QString &signal);
 
 private slots:
     void scheduledDebugBreak();
-    void initialize();
+    void cancelDebugBreak();
+    void initialize(bool);
 
 protected:
     void statusChanged(Status newStatus);