Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4debugjob.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4debugjob.h"
5
6#include <private/qqmlcontext_p.h>
7#include <private/qqmldebugservice_p.h>
8#include <private/qv4jscall_p.h>
9#include <private/qv4qmlcontext_p.h>
10#include <private/qv4qobjectwrapper_p.h>
11#include <private/qv4script_p.h>
12#include <private/qv4stackframe_p.h>
13
14#include <QtQml/qqmlengine.h>
15
16#include <QtCore/qpointer.h>
17
19
20QV4DebugJob::~QV4DebugJob()
21{
22}
23
24JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context,
25 const QString &script) :
26 engine(engine), frameNr(frameNr), context(context), script(script),
27 resultIsException(false)
28{}
29
31{
32 QV4::Scope scope(engine);
33
34 QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext()
35 : engine->scriptContext());
36
37 QV4::CppStackFrame *frame = engine->currentStackFrame;
38
39 for (int i = 0; frame && i < frameNr; ++i)
40 frame = frame->parentFrame();
41 if (frameNr > 0 && frame)
42 ctx = frame->context();
43
44 if (context >= 0) {
45 QObject *forId = QQmlDebugService::objectForId(context);
46 QQmlContext *extraContext = qmlContext(forId);
47 if (extraContext)
48 ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), forId);
49 } else if (frameNr < 0) { // Use QML context if available
50 QQmlEngine *qmlEngine = engine->qmlEngine();
51 if (qmlEngine) {
52 QQmlContext *qmlRootContext = qmlEngine->rootContext();
53 QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext);
54
55 QV4::ScopedObject withContext(scope, engine->newObject());
56 QV4::ScopedString k(scope);
57 QV4::ScopedValue v(scope);
58 const QList<QPointer<QObject>> instances = ctxtPriv->instances();
59 for (const QPointer<QObject> &object : instances) {
60 if (QQmlContext *context = qmlContext(object.data())) {
61 if (QQmlRefPointer<QQmlContextData> cdata = QQmlContextData::get(context)) {
62 v = QV4::QObjectWrapper::wrap(engine, object);
63 k = engine->newString(cdata->findObjectId(object));
64 withContext->put(k, v);
65 }
66 }
67 }
68 if (!engine->qmlContext())
69 ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), nullptr);
70 }
71 }
72
73 QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, this->script);
74 if (const QV4::Function *function = frame ? frame->v4Function : engine->globalCode)
75 script.setStrictMode(function->isStrict());
76
77 // In order for property lookups in QML to work, we need to disable fast v4 lookups. That
78 // is a side-effect of inheritContext.
79 script.setInheritContext();
80 script.parse();
81 QV4::ScopedValue result(scope);
82 if (!scope.hasException()) {
83 if (frame) {
84 QV4::ScopedValue thisObject(scope, frame->thisObject());
85 result = script.run(thisObject);
86 } else {
87 result = script.run();
88 }
89 }
90 if (scope.hasException()) {
91 result = scope.engine->catchException();
92 resultIsException = true;
93 }
94 handleResult(result);
95}
96
98{
99 return resultIsException;
100}
101
102BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) :
103 CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame)
104{
105}
106
108{
109 QJsonArray frameArray;
110 QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame);
111 for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
112 frameArray.push_back(collector->buildFrame(frames[i], i));
113 if (frameArray.isEmpty()) {
114 result.insert(QStringLiteral("totalFrames"), 0);
115 } else {
116 result.insert(QStringLiteral("fromFrame"), fromFrame);
117 result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
118 result.insert(QStringLiteral("frames"), frameArray);
119 }
120}
121
122FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) :
123 CollectJob(collector), frameNr(frameNr), success(false)
124{
125}
126
128{
129 QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1);
130 if (frameNr >= frames.size()) {
131 success = false;
132 } else {
133 result = collector->buildFrame(frames[frameNr], frameNr);
134 success = true;
135 }
136}
137
139{
140 return success;
141}
142
143ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) :
144 CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false)
145{
146}
147
149{
150 QJsonObject object;
151 success = collector->collectScope(&object, frameNr, scopeNr);
152
153 if (success) {
154 QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
155 collector->getScopeTypes(frameNr);
156 result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]);
157 } else {
158 result[QLatin1String("type")] = -1;
159 }
160 result[QLatin1String("index")] = scopeNr;
161 result[QLatin1String("frameIndex")] = frameNr;
162 result[QLatin1String("object")] = object;
163}
164
166{
167 return success;
168}
169
170ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) :
171 CollectJob(collector), handles(handles) {}
172
174{
175 // Open a QML context if we don't have one, yet. We might run into QML objects when looking up
176 // refs and that will crash without a valid QML context. Mind that engine->qmlContext() is only
177 // set if the engine is currently executing QML code.
178 QScopedPointer<QObject> scopeObject;
179 QV4::ExecutionEngine *engine = collector->engine();
180 QV4::Scope scope(engine);
181 QV4::Heap::ExecutionContext *qmlContext = engine->qmlContext();
182 if (engine->qmlEngine() && !qmlContext) {
183 scopeObject.reset(new QObject);
184 qmlContext = QV4::QmlContext::create(engine->currentContext(),
185 QQmlContextData::get(engine->qmlEngine()->rootContext()),
186 scopeObject.data());
187 }
188 QV4::Scoped<QV4::ExecutionContext> scopedContext(scope, qmlContext);
189 QV4::ScopedStackFrame frame(scope, scopedContext);
190 for (const QJsonValue handle : handles) {
191 QV4DataCollector::Ref ref = handle.toInt();
192 if (!collector->isValidRef(ref)) {
193 exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
194 break;
195 }
196 result[QString::number(ref)] = collector->lookupRef(ref);
197 }
198}
199
201{
202 return exception;
203}
204
205ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr,
206 int context, const QString &expression,
207 QV4DataCollector *collector) :
208 JavaScriptJob(engine, frameNr, context, expression), collector(collector)
209{
210}
211
212void ExpressionEvalJob::handleResult(QV4::ScopedValue &value)
213{
214 if (hasExeption())
215 exception = value->toQStringNoThrow();
216 result = collector->lookupRef(collector->addValueRef(value));
217}
218
220{
221 return exception;
222}
223
225{
226 return result;
227}
228
229GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine)
230 : engine(engine)
231{}
232
234{
235 const auto compilationUnits = engine->compilationUnits();
236 for (const auto &unit : compilationUnits) {
237 QString fileName = unit->fileName();
238 if (!fileName.isEmpty())
239 sources.append(fileName);
240 }
241}
242
244{
245 return sources;
246}
247
248EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) :
249 JavaScriptJob(engine, /*frameNr*/-1, /*context*/ -1, script), result(false)
250{}
251
252void EvalJob::handleResult(QV4::ScopedValue &result)
253{
254 this->result = result->toBoolean();
255}
256
258{
259 return result;
260}
261
262QT_END_NAMESPACE
BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame)
void run() override
QV4DataCollector * collector
Definition qv4debugjob.h:43
CollectJob(QV4DataCollector *collector)
Definition qv4debugjob.h:47
EvalJob(QV4::ExecutionEngine *engine, const QString &script)
bool resultAsBoolean() const
void handleResult(QV4::ScopedValue &result) override
const QJsonObject & returnValue() const
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context, const QString &expression, QV4DataCollector *collector)
void handleResult(QV4::ScopedValue &value) override
const QString & exceptionMessage() const
void run() override
bool wasSuccessful() const
FrameJob(QV4DataCollector *collector, int frameNr)
const QStringList & result() const
void run() override
GatherSourcesJob(QV4::ExecutionEngine *engine)
bool hasExeption() const
JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context, const QString &script)
void run() override
bool wasSuccessful() const
ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr)
void run() override
const QString & exceptionMessage() const
ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector)
void run() override