aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4debugging_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4debugging_p.h')
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h169
1 files changed, 159 insertions, 10 deletions
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index e44f415da4..98b549995e 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -45,6 +45,7 @@
#include "qv4global_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+#include "qv4scopedvalue_p.h"
#include <QHash>
#include <QThread>
@@ -59,30 +60,88 @@ struct Function;
namespace Debugging {
+enum PauseReason {
+ PauseRequest,
+ BreakPoint,
+ Throwing,
+ Step
+};
+
class DebuggerAgent;
class Q_QML_EXPORT Debugger
{
public:
+ class Job
+ {
+ public:
+ virtual ~Job() = 0;
+ virtual void run() = 0;
+ };
+
+ class Q_QML_EXPORT Collector
+ {
+ public:
+ Collector(ExecutionEngine *engine): m_engine(engine), m_isProperty(false) {}
+ virtual ~Collector();
+
+ void collect(const QString &name, const ScopedValue &value);
+ void collect(const ObjectRef object);
+
+ protected:
+ virtual void addUndefined(const QString &name) = 0;
+ virtual void addNull(const QString &name) = 0;
+ virtual void addBoolean(const QString &name, bool value) = 0;
+ virtual void addString(const QString &name, const QString &value) = 0;
+ virtual void addObject(const QString &name, ValueRef value) = 0;
+ virtual void addInteger(const QString &name, int value) = 0;
+ virtual void addDouble(const QString &name, double value) = 0;
+
+ QV4::ExecutionEngine *engine() const { return m_engine; }
+
+ bool isProperty() const { return m_isProperty; }
+ void setIsProperty(bool onoff) { m_isProperty = onoff; }
+
+ private:
+ QV4::ExecutionEngine *m_engine;
+ bool m_isProperty;
+ };
+
enum State {
Running,
Paused
};
- Debugger(ExecutionEngine *_engine);
+ enum Speed {
+ FullThrottle = 0,
+ StepIn,
+ StepOut,
+ StepOver,
+
+ NotStepping = FullThrottle
+ };
+
+ Debugger(ExecutionEngine *engine);
~Debugger();
+ ExecutionEngine *engine() const
+ { return m_engine; }
+
void attachToAgent(DebuggerAgent *agent);
void detachFromAgent();
+ DebuggerAgent *agent() const { return m_agent; }
+ void gatherSources(int requestSequenceNr);
void pause();
- void resume();
+ void resume(Speed speed);
State state() const { return m_state; }
- void addBreakPoint(const QString &fileName, int lineNumber);
+ void addBreakPoint(const QString &fileName, int lineNumber, const QString &condition = QString());
void removeBreakPoint(const QString &fileName, int lineNumber);
+ void setBreakOnThrow(bool onoff);
+
struct ExecutionState
{
ExecutionState() : lineNumber(-1), function(0) {}
@@ -94,22 +153,47 @@ public:
ExecutionState currentExecutionState(const uchar *code = 0) const;
bool pauseAtNextOpportunity() const {
- return m_pauseRequested || m_havePendingBreakPoints;
+ return m_pauseRequested || m_havePendingBreakPoints || m_gatherSources;
}
void setPendingBreakpoints(Function *function);
+ QVector<StackFrame> stackTrace(int frameLimit = -1) const;
+ void collectArgumentsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0);
+ void collectLocalsInContext(Collector *collector, int frameNr = 0, int scopeNr = 0);
+ bool collectThisInContext(Collector *collector, int frame = 0);
+ void collectThrownValue(Collector *collector);
+ void collectReturnedValue(Collector *collector) const;
+ QVector<ExecutionContext::Type> getScopeTypes(int frame = 0) const;
+
public: // compile-time interface
void maybeBreakAtInstruction(const uchar *code, bool breakPointHit);
public: // execution hooks
- void aboutToThrow(const ValueRef value);
+ void enteringFunction();
+ void leavingFunction(const ReturnedValue &retVal);
+ void aboutToThrow();
private:
+ Function *getFunction() const;
+
+ // requires lock to be held
+ void pauseAndWait(PauseReason reason);
+ // requires lock to be held
+ void setTemporaryBreakPointOnNextLine();
// requires lock to be held
- void pauseAndWait();
+ void clearTemporaryBreakPoints();
+ // requires lock to be held
+ bool temporaryBreakPointInFunction(ExecutionContext *context) const;
void applyPendingBreakPoints();
+ static void setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff);
+ static bool hasBreakOnInstruction(Function *function, qptrdiff codeOffset);
+ bool reallyHitTheBreakPoint(const QString &filename, int linenr);
+
+ void runInEngine(Job *job);
+ void runInEngine_havingLock(Debugger::Job *job);
+private:
struct BreakPoints : public QHash<QString, QList<int> >
{
void add(const QString &fileName, int lineNumber);
@@ -118,23 +202,60 @@ private:
void applyToFunction(Function *function, bool removeBreakPoints);
};
- QV4::ExecutionEngine *_engine;
+ QV4::ExecutionEngine *m_engine;
DebuggerAgent *m_agent;
QMutex m_lock;
QWaitCondition m_runningCondition;
State m_state;
bool m_pauseRequested;
+ Job *m_gatherSources;
bool m_havePendingBreakPoints;
BreakPoints m_pendingBreakPointsToAdd;
BreakPoints m_pendingBreakPointsToAddToFutureCode;
BreakPoints m_pendingBreakPointsToRemove;
const uchar *m_currentInstructionPointer;
+ Speed m_stepping;
+ bool m_stopForStepping;
+ QV4::PersistentValue m_returnedValue;
+
+ struct TemporaryBreakPoint {
+ Function *function;
+ QVector<qptrdiff> codeOffsets;
+ ExecutionContext *context;
+ TemporaryBreakPoint(): function(0), context(0) {}
+ TemporaryBreakPoint(Function *function, ExecutionContext *context)
+ : function(function)
+ , context(context)
+ {}
+ } m_temporaryBreakPoints;
+
+ bool m_breakOnThrow;
+
+ Job *m_runningJob;
+ QWaitCondition m_jobIsRunning;
+
+ struct BreakPointConditions: public QHash<QString, QString>
+ {
+ static QString genKey(const QString &fileName, int lineNumber)
+ {
+ return fileName + QLatin1Char(':') + QString::number(lineNumber);
+ }
+
+ QString condition(const QString &fileName, int lineNumber)
+ { return value(genKey(fileName, lineNumber)); }
+ void add(const QString &fileName, int lineNumber, const QString &condition)
+ { insert(genKey(fileName, lineNumber), condition); }
+ void remove(const QString &fileName, int lineNumber)
+ { take(genKey(fileName, lineNumber)); }
+ };
+ BreakPointConditions m_breakPointConditions;
};
class Q_QML_EXPORT DebuggerAgent : public QObject
{
Q_OBJECT
public:
+ DebuggerAgent(): m_breakOnThrow(false) {}
~DebuggerAgent();
void addDebugger(Debugger *debugger);
@@ -142,13 +263,40 @@ public:
void pause(Debugger *debugger) const;
void pauseAll() const;
- void addBreakPoint(const QString &fileName, int lineNumber) const;
- void removeBreakPoint(const QString &fileName, int lineNumber) const;
+ void resumeAll() const;
+ int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
+ void removeBreakPoint(int id);
+ void removeAllBreakPoints();
+ void enableBreakPoint(int id, bool onoff);
+ QList<int> breakPointIds(const QString &fileName, int lineNumber) const;
+
+ bool breakOnThrow() const { return m_breakOnThrow; }
+ void setBreakOnThrow(bool onoff);
- Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger) = 0;
+ Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger,
+ QV4::Debugging::PauseReason reason) = 0;
+ Q_INVOKABLE virtual void sourcesCollected(QV4::Debugging::Debugger *debugger,
+ QStringList sources, int requestSequenceNr) = 0;
protected:
QList<Debugger *> m_debuggers;
+
+ struct BreakPoint {
+ QString fileName;
+ int lineNr;
+ bool enabled;
+ QString condition;
+
+ BreakPoint(): lineNr(-1), enabled(false) {}
+ BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition)
+ : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition)
+ {}
+
+ bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); }
+ };
+
+ QHash<int, BreakPoint> m_breakPoints;
+ bool m_breakOnThrow;
};
} // namespace Debugging
@@ -157,5 +305,6 @@ protected:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Debugging::Debugger*)
+Q_DECLARE_METATYPE(QV4::Debugging::PauseReason)
#endif // DEBUGGING_H