8#include <private/qqmlcontext_p.h>
9#include <private/qqmlengine_p.h>
10#include <private/qv4scopedvalue_p.h>
11#include <private/qv4script_p.h>
12#include <private/qv4stackframe_p.h>
16QV4Debugger::BreakPoint::BreakPoint(
const QString &fileName,
int line)
17 : fileName(fileName), lineNumber(line)
20inline size_t qHash(
const QV4Debugger::BreakPoint &b, size_t seed = 0)
noexcept
22 return qHash(b.fileName, seed) ^ b.lineNumber;
25inline bool operator==(
const QV4Debugger::BreakPoint &a,
26 const QV4Debugger::BreakPoint &b)
28 return a.lineNumber == b.lineNumber && a.fileName == b.fileName;
35 , m_pauseRequested(
false)
36 , m_haveBreakPoints(
false)
37 , m_breakOnThrow(
false)
39 , m_gatherSources(
nullptr)
40 , m_runningJob(
nullptr)
43 static int debuggerId = qRegisterMetaType<
QV4Debugger*>();
46 Q_UNUSED(pauseReasonId);
47 connect(
this, &QV4Debugger::scheduleJob,
48 this, &QV4Debugger::runJobUnpaused, Qt::QueuedConnection);
68 QMutexLocker locker(&m_lock);
71 m_pauseRequested =
true;
76 QMutexLocker locker(&m_lock);
80 if (!m_returnedValue.isUndefined())
81 m_returnedValue.set(m_engine, QV4::Encode::undefined());
83 m_currentFrame = m_engine->currentStackFrame;
85 m_runningCondition.wakeAll();
95 QMutexLocker locker(&m_lock);
96 m_breakPoints.insert(BreakPoint(fileName.mid(fileName.lastIndexOf(
'/') + 1),
97 lineNumber), condition);
98 m_haveBreakPoints =
true;
103 QMutexLocker locker(&m_lock);
104 m_breakPoints.remove(BreakPoint(fileName.mid(fileName.lastIndexOf(
'/') + 1),
106 m_haveBreakPoints = !m_breakPoints.isEmpty();
111 QMutexLocker locker(&m_lock);
113 m_breakOnThrow = onoff;
118 QMutexLocker locker(&m_lock);
119 m_pauseRequested =
false;
125 state.fileName = QUrl(getFunction()->sourceFile()).fileName();
126 state.lineNumber = engine()->currentStackFrame->lineNumber();
132 return m_pauseRequested || m_haveBreakPoints || m_gatherSources || m_stepping >=
StepOver;
137 return m_engine->stackTrace(frameLimit);
145 QMutexLocker locker(&m_lock);
147 if (m_gatherSources) {
149 delete m_gatherSources;
150 m_gatherSources =
nullptr;
153 switch (m_stepping) {
155 if (m_currentFrame != m_engine->currentStackFrame)
166 if (m_pauseRequested) {
167 m_pauseRequested =
false;
169 }
else if (m_haveBreakPoints) {
170 if (QV4::Function *f = getFunction()) {
172 const int lineNumber = engine()->currentStackFrame->lineNumber();
173 if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber))
183 QMutexLocker locker(&m_lock);
185 if (m_stepping == StepIn)
186 m_currentFrame = m_engine->currentStackFrame;
195 QMutexLocker locker(&m_lock);
197 if (m_stepping != NotStepping && m_currentFrame == m_engine->currentStackFrame) {
198 m_currentFrame = m_currentFrame->parentFrame();
200 m_returnedValue.set(m_engine, retVal);
212 QMutexLocker locker(&m_lock);
218 if (m_engine->currentStackFrame)
219 return m_engine->currentStackFrame->v4Function;
221 return m_engine->globalCode;
226 QMutexLocker locker(&m_lock);
229 m_jobIsRunning.wakeAll();
238 emit debuggerPaused(
this, reason);
241 m_runningCondition.wait(&m_lock);
244 m_jobIsRunning.wakeAll();
253bool QV4Debugger::reallyHitTheBreakPoint(
const QString &filename,
int linenr)
255 const auto it = m_breakPoints.constFind(
256 BreakPoint(QUrl(filename).fileName(), linenr));
257 if (it == m_breakPoints.cend())
259 QString condition = it.value();
260 if (condition.isEmpty())
263 Q_ASSERT(m_runningJob ==
nullptr);
264 EvalJob evilJob(m_engine, condition);
265 m_runningJob = &evilJob;
267 m_runningJob =
nullptr;
274 QMutexLocker locker(&m_lock);
275 runInEngine_havingLock(job);
281 Q_ASSERT(m_runningJob ==
nullptr);
285 m_runningCondition.wakeAll();
288 m_jobIsRunning.wait(&m_lock);
289 m_runningJob =
nullptr;
294#include "moc_qv4debugger.cpp"
bool resultAsBoolean() const
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
void maybeBreakAtInstruction() override
QV4::Function * getFunction() const
void enteringFunction() override
void runInEngine(QV4DebugJob *job)
QV4DataCollector * collector()
void removeBreakPoint(const QString &fileName, int lineNumber)
QV4::ExecutionEngine * engine() const
QVector< QV4::StackFrame > stackTrace(int frameLimit=-1) const
void setBreakOnThrow(bool onoff)
bool pauseAtNextOpportunity() const override
void leavingFunction(const QV4::ReturnedValue &retVal) override
ExecutionState currentExecutionState() const
const QV4DataCollector * collector() const
QV4Debugger(QV4::ExecutionEngine *engine)
void aboutToThrow() override
void addBreakPoint(const QString &fileName, int lineNumber, const QString &condition=QString())
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept