aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4codegen.cpp3
-rw-r--r--src/qml/debugger/qv4debugservice.cpp91
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp80
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp21
-rw-r--r--src/qml/jsruntime/qv4script.cpp21
-rw-r--r--src/qml/jsruntime/qv4script_p.h24
7 files changed, 178 insertions, 64 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 2d45543305..2f80b0e519 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1950,7 +1950,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::BasicBlock *entryBlock = function->newBasicBlock(0);
IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock);
- function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode;
+ function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode
+ || _module->debugMode; // Conditional breakpoints are like eval in the function
function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->usesThis = _env->usesThis;
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index 8e81d6e24e..1b30dd7f61 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -405,7 +405,7 @@ public:
void clearHandles(QV4::ExecutionEngine *engine)
{
- collector.reset(new VariableCollector(engine));
+ theCollector.reset(new VariableCollector(engine));
}
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
@@ -414,18 +414,18 @@ public:
QJsonObject frame;
frame[QLatin1String("index")] = frameNr;
frame[QLatin1String("debuggerFrame")] = false;
- frame[QLatin1String("func")] = collector->addFunctionRef(stackFrame.function);
- frame[QLatin1String("script")] = collector->addScriptRef(stackFrame.source);
+ frame[QLatin1String("func")] = theCollector->addFunctionRef(stackFrame.function);
+ frame[QLatin1String("script")] = theCollector->addScriptRef(stackFrame.source);
frame[QLatin1String("line")] = stackFrame.line - 1;
if (stackFrame.column >= 0)
frame[QLatin1String("column")] = stackFrame.column;
QJsonArray properties;
- collector->setDestination(&properties);
- if (debugger->collectThisInContext(collector.data(), frameNr)) {
+ theCollector->setDestination(&properties);
+ if (debugger->collectThisInContext(theCollector.data(), frameNr)) {
QJsonObject obj;
obj[QLatin1String("properties")] = properties;
- frame[QLatin1String("receiver")] = collector->addObjectRef(obj, false);
+ frame[QLatin1String("receiver")] = theCollector->addObjectRef(obj, false);
}
QJsonArray scopes;
@@ -473,7 +473,7 @@ public:
QJsonObject scope;
QJsonArray properties;
- collector->collectScope(&properties, debugger, frameNr, scopeNr);
+ theCollector->collectScope(&properties, debugger, frameNr, scopeNr);
QJsonObject anonymous;
anonymous[QLatin1String("properties")] = properties;
@@ -482,16 +482,21 @@ public:
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
scope[QLatin1String("index")] = scopeNr;
scope[QLatin1String("frameIndex")] = frameNr;
- scope[QLatin1String("object")] = collector->addObjectRef(anonymous, true);
+ scope[QLatin1String("object")] = theCollector->addObjectRef(anonymous, true);
return scope;
}
- QJsonValue lookup(int refId) const { return collector->lookup(refId); }
+ QJsonValue lookup(int refId) const { return theCollector->lookup(refId); }
QJsonArray buildRefs()
{
- return collector->retrieveRefsToInclude();
+ return theCollector->retrieveRefsToInclude();
+ }
+
+ VariableCollector *collector() const
+ {
+ return theCollector.data();
}
void selectFrame(int frameNr)
@@ -501,7 +506,7 @@ public:
{ return theSelectedFrame; }
private:
- QScopedPointer<VariableCollector> collector;
+ QScopedPointer<VariableCollector> theCollector;
int theSelectedFrame;
void addHandler(V8CommandHandler* handler);
@@ -959,6 +964,67 @@ public:
// response will be send by
}
};
+
+// Request:
+// {
+// "seq": 4,
+// "type": "request",
+// "command": "evaluate",
+// "arguments": {
+// "expression": "a",
+// "frame": 0
+// }
+// }
+//
+// Response:
+// {
+// "body": {
+// "handle": 3,
+// "type": "number",
+// "value": 1
+// },
+// "command": "evaluate",
+// "refs": [],
+// "request_seq": 4,
+// "running": false,
+// "seq": 5,
+// "success": true,
+// "type": "response"
+// }
+//
+// The "value" key in "body" is the result of evaluating the expression in the request.
+class V8EvaluateRequest: public V8CommandHandler
+{
+public:
+ V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {}
+
+ virtual void handleRequest()
+ {
+ //decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString expression = arguments.value(QStringLiteral("expression")).toString();
+ const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+ Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused);
+
+ VariableCollector *collector = debugServicePrivate->collector();
+ QJsonArray dest;
+ collector->setDestination(&dest);
+ debugger->evaluateExpression(frame, expression, collector);
+
+ const int ref = dest.at(0).toObject().value(QStringLiteral("value")).toObject()
+ .value(QStringLiteral("ref")).toInt();
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(collector->lookup(ref).toObject());
+ addRefs();
+ }
+};
} // anonymous namespace
QV4DebugServicePrivate::QV4DebugServicePrivate()
@@ -978,8 +1044,7 @@ QV4DebugServicePrivate::QV4DebugServicePrivate()
addHandler(new V8DisconnectRequest);
addHandler(new V8SetExceptionBreakRequest);
addHandler(new V8ScriptsRequest);
-
- // TODO: evaluate
+ addHandler(new V8EvaluateRequest);
}
void QV4DebugServicePrivate::addHandler(V8CommandHandler* handler)
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 04422b9f5e..78de614664 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -45,6 +45,7 @@
#include "qv4function_p.h"
#include "qv4instr_moth_p.h"
#include "qv4runtime_p.h"
+#include "qv4script_p.h"
#include <iostream>
#include <algorithm>
@@ -53,29 +54,74 @@ using namespace QV4;
using namespace QV4::Debugging;
namespace {
-class EvalJob: public Debugger::Job
+class JavaScriptJob: public Debugger::Job
{
QV4::ExecutionEngine *engine;
const QString &script;
public:
- EvalJob(QV4::ExecutionEngine *engine, const QString &script)
+ JavaScriptJob(QV4::ExecutionEngine *engine, const QString &script)
: engine(engine)
, script(script)
{}
- ~EvalJob() {}
-
void run()
{
- // TODO
- qDebug() << "Evaluating script:" << script;
- Q_UNUSED(engine);
+ QV4::Scope scope(engine);
+ QV4::ExecutionContext *ctx = engine->currentContext();
+ ContextStateSaver ctxSaver(ctx);
+ QV4::ScopedValue result(scope);
+
+ QV4::Script script(ctx, this->script);
+ script.strictMode = ctx->d()->strictMode;
+ script.inheritContext = false;
+ script.parse();
+ if (!scope.engine->hasException)
+ result = script.run();
+ if (scope.engine->hasException)
+ result = ctx->catchException();
+ handleResult(result);
+ }
+
+protected:
+ virtual void handleResult(QV4::ScopedValue &result) = 0;
+};
+
+class EvalJob: public JavaScriptJob
+{
+ bool result;
+
+public:
+ EvalJob(QV4::ExecutionEngine *engine, const QString &script)
+ : JavaScriptJob(engine, script)
+ , result(false)
+ {}
+
+ virtual void handleResult(QV4::ScopedValue &result)
+ {
+ this->result = result->toBoolean();
}
bool resultAsBoolean() const
{
- return true;
+ return result;
+ }
+};
+
+class ExpressionEvalJob: public JavaScriptJob
+{
+ Debugger::Collector *collector;
+
+public:
+ ExpressionEvalJob(ExecutionEngine *engine, const QString &expression, Debugger::Collector *collector)
+ : JavaScriptJob(engine, expression)
+ , collector(collector)
+ {
+ }
+
+ virtual void handleResult(QV4::ScopedValue &result)
+ {
+ collector->collect(QStringLiteral("body"), result);
}
};
@@ -444,6 +490,19 @@ QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const
return types;
}
+
+void Debugger::evaluateExpression(int frameNr, const QString &expression, Debugger::Collector *resultsCollector)
+{
+ Q_ASSERT(state() == Paused);
+ Q_UNUSED(frameNr);
+
+ Q_ASSERT(m_runningJob == 0);
+ ExpressionEvalJob job(m_engine, expression, resultsCollector);
+ m_runningJob = &job;
+ m_runningJob->run();
+ m_runningJob = 0;
+}
+
void Debugger::maybeBreakAtInstruction()
{
if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
@@ -481,6 +540,8 @@ void Debugger::maybeBreakAtInstruction()
void Debugger::enteringFunction()
{
+ if (m_runningJob)
+ return;
QMutexLocker locker(&m_lock);
if (m_stepping == StepIn) {
@@ -490,6 +551,8 @@ void Debugger::enteringFunction()
void Debugger::leavingFunction(const ReturnedValue &retVal)
{
+ if (m_runningJob)
+ return;
Q_UNUSED(retVal); // TODO
QMutexLocker locker(&m_lock);
@@ -560,6 +623,7 @@ bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
EvalJob evilJob(m_engine, condition);
m_runningJob = &evilJob;
m_runningJob->run();
+ m_runningJob = 0;
return evilJob.resultAsBoolean();
}
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index f834b8d15f..cedfee7f90 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -181,6 +181,8 @@ public:
void collectReturnedValue(Collector *collector) const;
QVector<ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
+ void evaluateExpression(int frameNr, const QString &expression, Collector *resultsCollector);
+
public: // compile-time interface
void maybeBreakAtInstruction();
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index fc4a097915..a699442273 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -357,27 +357,6 @@ EvalFunction::Data::Data(ExecutionContext *scope)
ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
{
- struct ContextStateSaver {
- ExecutionContext *savedContext;
- bool strictMode;
- ExecutionContext::EvalCode *evalCode;
- CompiledData::CompilationUnit *compilationUnit;
-
- ContextStateSaver(ExecutionContext *context)
- : savedContext(context)
- , strictMode(context->d()->strictMode)
- , evalCode(context->d()->currentEvalCode)
- , compilationUnit(context->d()->compilationUnit)
- {}
-
- ~ContextStateSaver()
- {
- savedContext->d()->strictMode = strictMode;
- savedContext->d()->currentEvalCode = evalCode;
- savedContext->d()->compilationUnit = compilationUnit;
- }
- };
-
if (callData->argc < 1)
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index e08a63bd1f..27bb7c8d2f 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -287,27 +287,6 @@ void Script::parse()
ReturnedValue Script::run()
{
- struct ContextStateSaver {
- ExecutionContext *savedContext;
- bool strictMode;
- Lookup *lookups;
- CompiledData::CompilationUnit *compilationUnit;
-
- ContextStateSaver(ExecutionContext *context)
- : savedContext(context)
- , strictMode(context->d()->strictMode)
- , lookups(context->d()->lookups)
- , compilationUnit(context->d()->compilationUnit)
- {}
-
- ~ContextStateSaver()
- {
- savedContext->d()->strictMode = strictMode;
- savedContext->d()->lookups = lookups;
- savedContext->d()->compilationUnit = compilationUnit;
- }
- };
-
if (!parsed)
parse();
if (!vmFunction)
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 6a749d1438..6f947cd430 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -55,6 +55,30 @@ namespace QV4 {
struct ExecutionContext;
+struct ContextStateSaver {
+ ExecutionContext *savedContext;
+ bool strictMode;
+ Lookup *lookups;
+ CompiledData::CompilationUnit *compilationUnit;
+ int lineNumber;
+
+ ContextStateSaver(ExecutionContext *context)
+ : savedContext(context)
+ , strictMode(context->d()->strictMode)
+ , lookups(context->d()->lookups)
+ , compilationUnit(context->d()->compilationUnit)
+ , lineNumber(context->d()->lineNumber)
+ {}
+
+ ~ContextStateSaver()
+ {
+ savedContext->d()->strictMode = strictMode;
+ savedContext->d()->lookups = lookups;
+ savedContext->d()->compilationUnit = compilationUnit;
+ savedContext->d()->lineNumber = lineNumber;
+ }
+};
+
struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject {
struct Data : FunctionObject::Data {
Data(ExecutionContext *scope, Function *f, Object *qml);