9#include <private/qqmlcontext_p.h>
10#include <private/qqmlengine_p.h>
11#include <private/qv4scopedvalue_p.h>
12#include <private/qv4script_p.h>
13#include <private/qv4stackframe_p.h>
17QV4Debugger::BreakPoint::BreakPoint(
const QString &fileName,
int line)
18 : fileName(fileName), lineNumber(line)
21inline size_t qHash(
const QV4Debugger::BreakPoint &b, size_t seed = 0)
noexcept
23 return qHash(b.fileName, seed) ^ b.lineNumber;
26inline bool operator==(
const QV4Debugger::BreakPoint &a,
27 const QV4Debugger::BreakPoint &b)
29 return a.lineNumber == b.lineNumber && a.fileName == b.fileName;
36 , m_pauseRequested(
false)
37 , m_haveBreakPoints(
false)
38 , m_breakOnThrow(
false)
40 , m_gatherSources(
nullptr)
41 , m_runningJob(
nullptr)
44 static int debuggerId = qRegisterMetaType<
QV4Debugger*>();
47 Q_UNUSED(pauseReasonId);
48 connect(
this, &QV4Debugger::scheduleJob,
49 this, &QV4Debugger::runJobUnpaused, Qt::QueuedConnection);
69 QMutexLocker locker(&m_lock);
72 m_pauseRequested =
true;
77 QMutexLocker locker(&m_lock);
81 if (!m_returnedValue.isUndefined())
82 m_returnedValue.set(m_engine, QV4::Encode::undefined());
84 m_currentFrame = m_engine->currentStackFrame;
86 m_runningCondition.wakeAll();
96 QMutexLocker locker(&m_lock);
97 m_breakPoints.insert(BreakPoint(fileName.mid(fileName.lastIndexOf(
'/') + 1),
98 lineNumber), condition);
99 m_haveBreakPoints =
true;
104 QMutexLocker locker(&m_lock);
105 m_breakPoints.remove(BreakPoint(fileName.mid(fileName.lastIndexOf(
'/') + 1),
107 m_haveBreakPoints = !m_breakPoints.isEmpty();
112 QMutexLocker locker(&m_lock);
114 m_breakOnThrow = onoff;
119 QMutexLocker locker(&m_lock);
120 m_pauseRequested =
false;
126 state.fileName = QUrl(getFunction()->sourceFile()).fileName();
127 state.lineNumber = engine()->currentStackFrame->lineNumber();
133 return m_pauseRequested || m_haveBreakPoints || m_gatherSources || m_stepping >=
StepOver;
138 return m_engine->stackTrace(frameLimit);
146 QMutexLocker locker(&m_lock);
148 if (m_gatherSources) {
150 delete m_gatherSources;
151 m_gatherSources =
nullptr;
154 switch (m_stepping) {
156 if (m_currentFrame != m_engine->currentStackFrame)
167 if (m_pauseRequested) {
168 m_pauseRequested =
false;
170 }
else if (m_haveBreakPoints) {
171 if (QV4::Function *f = getFunction()) {
173 const int lineNumber = engine()->currentStackFrame->lineNumber();
174 if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber))
184 QMutexLocker locker(&m_lock);
186 if (m_stepping == StepIn)
187 m_currentFrame = m_engine->currentStackFrame;
196 QMutexLocker locker(&m_lock);
198 if (m_stepping != NotStepping && m_currentFrame == m_engine->currentStackFrame) {
199 m_currentFrame = m_currentFrame->parentFrame();
201 m_returnedValue.set(m_engine, retVal);
213 QMutexLocker locker(&m_lock);
219 if (m_engine->currentStackFrame)
220 return m_engine->currentStackFrame->v4Function;
222 return m_engine->globalCode;
227 QMutexLocker locker(&m_lock);
230 m_jobIsRunning.wakeAll();
239 emit debuggerPaused(
this, reason);
242 m_runningCondition.wait(&m_lock);
245 m_jobIsRunning.wakeAll();
254bool QV4Debugger::reallyHitTheBreakPoint(
const QString &filename,
int linenr)
256 const auto it = m_breakPoints.constFind(
257 BreakPoint(QUrl(filename).fileName(), linenr));
258 if (it == m_breakPoints.cend())
260 QString condition = it.value();
261 if (condition.isEmpty())
264 Q_ASSERT(m_runningJob ==
nullptr);
265 EvalJob evilJob(m_engine, condition);
266 m_runningJob = &evilJob;
268 m_runningJob =
nullptr;
275 QMutexLocker locker(&m_lock);
276 runInEngine_havingLock(job);
282 Q_ASSERT(m_runningJob ==
nullptr);
286 m_runningCondition.wakeAll();
289 m_jobIsRunning.wait(&m_lock);
290 m_runningJob =
nullptr;
295#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())
Combined button and popup list for selecting options.
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept