Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4datacollector.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 "qv4datacollector.h"
5#include "qv4debugger.h"
6#include "qv4debugjob.h"
7
8#include <private/qv4script_p.h>
9#include <private/qv4string_p.h>
10#include <private/qv4objectiterator_p.h>
11#include <private/qv4identifierhash_p.h>
12#include <private/qv4runtime_p.h>
13#include <private/qv4identifiertable_p.h>
14
15#include <private/qqmlcontext_p.h>
16#include <private/qqmlengine_p.h>
17
18#include <QtCore/qjsonarray.h>
19#include <QtCore/qjsonobject.h>
20
22
24{
26 while (f && frame) {
27 --frame;
28 f = f->parentFrame();
29 }
30 return f;
31}
32
33QV4::Heap::ExecutionContext *QV4DataCollector::findContext(int frame)
34{
36
37 return f ? f->context()->d() : nullptr;
38}
39
40QV4::Heap::ExecutionContext *QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctx, int scope)
41{
42 for (; scope > 0 && ctx; --scope)
43 ctx = ctx->outer;
44
45 return ctx;
46}
47
49{
51
52 QV4::Heap::ExecutionContext *it = findFrame(frame)->context()->d();
53
54 for (; it; it = it->outer)
55 types.append(QV4::Heap::ExecutionContext::ContextType(it->type));
56
57 return types;
58}
59
60int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
61{
62 switch (scopeType) {
63 case QV4::Heap::ExecutionContext::Type_GlobalContext:
64 break;
65 case QV4::Heap::ExecutionContext::Type_WithContext:
66 return 2;
67 case QV4::Heap::ExecutionContext::Type_CallContext:
68 return 1;
69 case QV4::Heap::ExecutionContext::Type_QmlContext:
70 return 3;
71 case QV4::Heap::ExecutionContext::Type_BlockContext:
72 return 4;
73 }
74 return 0;
75}
76
78 : m_engine(engine)
79{
80 m_values.set(engine, engine->newArrayObject());
81}
82
84{
85 return addRef(value);
86}
87
89 QJsonObject &dict)
90{
91 QV4::Scope scope(engine);
93 dict.insert(QStringLiteral("type"), typeString->toQStringNoThrow());
94
95 const QLatin1String valueKey("value");
96 switch (value->type()) {
98 Q_ASSERT(!"empty Value encountered");
99 return nullptr;
101 dict.insert(valueKey, QJsonValue::Undefined);
102 return nullptr;
104 dict.insert(valueKey, QJsonValue::Null);
105 return nullptr;
107 dict.insert(valueKey, value->booleanValue());
108 return nullptr;
110 if (const QV4::String *s = value->as<QV4::String>()) {
111 dict.insert(valueKey, s->toQString());
112 } else if (const QV4::ArrayObject *a = value->as<QV4::ArrayObject>()) {
113 // size of an array is number of its numerical properties; We don't consider free form
114 // object properties here.
115 dict.insert(valueKey, qint64(a->getLength()));
116 return a;
117 } else if (const QV4::Object *o = value->as<QV4::Object>()) {
118 int numProperties = 0;
122 while (true) {
123 name = it.next(nullptr, &attrs);
124 if (!name->isValid())
125 break;
126 ++numProperties;
127 }
128 dict.insert(valueKey, numProperties);
129 return o;
130 } else {
131 Q_UNREACHABLE();
132 }
133 return nullptr;
135 dict.insert(valueKey, value->integerValue());
136 return nullptr;
137 default: {// double
138 const double val = value->doubleValue();
139 if (qIsFinite(val))
140 dict.insert(valueKey, val);
141 else if (qIsNaN(val))
142 dict.insert(valueKey, QStringLiteral("NaN"));
143 else if (val < 0)
144 dict.insert(valueKey, QStringLiteral("-Infinity"));
145 else
146 dict.insert(valueKey, QStringLiteral("Infinity"));
147 return nullptr;
148 }
149 }
150}
151
153{
154 QJsonObject dict;
155
156 dict.insert(QStringLiteral("handle"), qint64(ref));
157 QV4::Scope scope(engine());
158 QV4::ScopedValue value(scope, getValue(ref));
159
160 const QV4::Object *object = collectProperty(value, engine(), dict);
161 if (object)
162 dict.insert(QStringLiteral("properties"), collectProperties(object));
163
164 return dict;
165}
166
168{
169 QV4::Scope scope(engine());
170 QV4::ScopedObject array(scope, m_values.value());
171 return ref < array->getLength();
172}
173
174bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
175{
176 QV4::Scope scope(engine());
177
178 QV4::Scoped<QV4::ExecutionContext> ctxt(scope, findScope(findContext(frameNr), scopeNr));
179 if (!ctxt)
180 return false;
181
182 QV4::ScopedObject scopeObject(scope, engine()->newObject());
183 if (ctxt->d()->type == QV4::Heap::ExecutionContext::Type_CallContext ||
184 ctxt->d()->type == QV4::Heap::ExecutionContext::Type_BlockContext) {
186 Refs collectedRefs;
187
188 QV4::ScopedValue v(scope);
189 QV4::Heap::InternalClass *ic = ctxt->internalClass();
190 for (uint i = 0; i < ic->size; ++i) {
191 QString name = ic->keyAt(i);
193 v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i];
194 collectedRefs.append(addValueRef(v));
195 }
196
197 Q_ASSERT(names.size() == collectedRefs.size());
198 QV4::ScopedString propName(scope);
199 for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
200 propName = engine()->newString(names.at(i));
201 scopeObject->put(propName, (v = getValue(collectedRefs.at(i))));
202 }
203 }
204
205 *dict = lookupRef(addRef(scopeObject));
206
207 return true;
208}
209
211 QJsonObject dict;
212 dict.insert(QStringLiteral("ref"), qint64(ref));
213 return dict;
214}
215
217{
219 frame[QLatin1String("index")] = frameNr;
220 frame[QLatin1String("debuggerFrame")] = false;
221 frame[QLatin1String("func")] = stackFrame.function;
222 frame[QLatin1String("script")] = stackFrame.source;
223 frame[QLatin1String("line")] = qAbs(stackFrame.line) - 1;
224 if (stackFrame.column >= 0)
225 frame[QLatin1String("column")] = stackFrame.column;
226
227 QJsonArray scopes;
228 QV4::Scope scope(engine());
229 QV4::ScopedContext ctxt(scope, findContext(frameNr));
230 while (ctxt) {
231 if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
232 if (cCtxt->d()->activation)
233 break;
234 }
235 ctxt = ctxt->d()->outer;
236 }
237
238 if (ctxt) {
239 QV4::ScopedValue o(scope, ctxt->d()->activation);
240 frame[QLatin1String("receiver")] = toRef(addValueRef(o));
241 }
242
243 // Only type and index are used by Qt Creator, so we keep it easy:
245 for (int i = 0, ei = scopeTypes.size(); i != ei; ++i) {
246 int type = encodeScopeType(scopeTypes[i]);
247 if (type == -1)
248 continue;
249
250 QJsonObject scope;
251 scope[QLatin1String("index")] = i;
252 scope[QLatin1String("type")] = type;
253 scopes.push_back(scope);
254 }
255
256 frame[QLatin1String("scopes")] = scopes;
257
258 return frame;
259}
260
262{
263 m_values.set(engine(), engine()->newArrayObject());
264}
265
266QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
267{
268 class ExceptionStateSaver
269 {
270 quint8 *hasExceptionLoc;
271 quint8 hadException;
272
273 public:
274 ExceptionStateSaver(QV4::ExecutionEngine *engine)
275 : hasExceptionLoc(&engine->hasException)
276 , hadException(false)
277 { std::swap(*hasExceptionLoc, hadException); }
278
279 ~ExceptionStateSaver()
280 { std::swap(*hasExceptionLoc, hadException); }
281 };
282
283 // if we wouldn't do this, the put won't work.
284 ExceptionStateSaver resetExceptionState(engine());
285 QV4::Scope scope(engine());
286 QV4::ScopedObject array(scope, m_values.value());
287 if (deduplicate) {
288 for (Ref i = 0; i < array->getLength(); ++i) {
289 if (array->get(i) == value.rawValue())
290 return i;
291 }
292 }
293 Ref ref = array->getLength();
294 array->put(ref, value);
295 Q_ASSERT(array->getLength() - 1 == ref);
296 return ref;
297}
298
299QV4::ReturnedValue QV4DataCollector::getValue(Ref ref)
300{
301 QV4::Scope scope(engine());
302 QV4::ScopedObject array(scope, m_values.value());
303 Q_ASSERT(ref < array->getLength());
304 return array->get(ref, nullptr);
305}
306
308{
309public:
311 {
312 if (QQmlEngine *e = engine->qmlEngine()) {
313 m_engine = QQmlEnginePrivate::get(e);
314 m_capture = m_engine->propertyCapture;
315 m_engine->propertyCapture = nullptr;
316 }
317 }
318
320 {
321 if (m_engine && m_capture) {
322 Q_ASSERT(!m_engine->propertyCapture);
323 m_engine->propertyCapture = m_capture;
324 }
325 }
326
327private:
328 QQmlEnginePrivate *m_engine = nullptr;
329 QQmlPropertyCapture *m_capture = nullptr;
330};
331
332QJsonArray QV4DataCollector::collectProperties(const QV4::Object *object)
333{
334 CapturePreventer capturePreventer(engine());
335 Q_UNUSED(capturePreventer);
336
338
339 QV4::Scope scope(engine());
341 QV4::ScopedValue name(scope);
342 QV4::ScopedValue value(scope);
343 while (true) {
345 name = it.nextPropertyNameAsString(&v);
346 if (name->isNull())
347 break;
348 QString key = name->toQStringNoThrow();
349 value = v;
350 res.append(collectAsJson(key, value));
351 }
352
353 return res;
354}
355
356QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::ScopedValue &value)
357{
358 QJsonObject dict;
359 if (!name.isNull())
360 dict.insert(QStringLiteral("name"), name);
361 if (value->isManaged() && !value->isString()) {
362 Ref ref = addRef(value);
363 dict.insert(QStringLiteral("ref"), qint64(ref));
364 }
365
366 collectProperty(value, engine(), dict);
367 return dict;
368}
369
CapturePreventer(QV4::ExecutionEngine *engine)
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
void push_back(const QJsonValue &t)
This function is provided for STL compatibility.
Definition qjsonarray.h:206
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
iterator insert(const QString &key, const QJsonValue &value)
Inserts a new item with the key key and a value of value.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
QQmlPropertyCapture * propertyCapture
static QQmlEnginePrivate * get(QQmlEngine *e)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & append(QChar c)
Definition qstring.cpp:3227
bool collectScope(QJsonObject *dict, int frameNr, int scopeNr)
bool isValidRef(Ref ref) const
Ref addValueRef(const QV4::ScopedValue &value)
static QV4::Heap::ExecutionContext * findScope(QV4::Heap::ExecutionContext *ctxt, int scope)
static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
QJsonObject lookupRef(Ref ref)
QV4::CppStackFrame * findFrame(int frame)
QV4DataCollector(QV4::ExecutionEngine *engine)
QV4::ExecutionEngine * engine() const
QVector< QV4::Heap::ExecutionContext::ContextType > getScopeTypes(int frame)
QV4::Heap::ExecutionContext * findContext(int frame)
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
ReturnedValue value() const
void set(ExecutionEngine *engine, const Value &value)
EGLContext ctx
double e
QSet< QString >::iterator it
Combined button and popup list for selecting options.
quint64 ReturnedValue
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qIsFinite(qfloat16 f) noexcept
Definition qfloat16.h:239
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:238
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLsizei const GLfloat * v
[13]
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLsizei GLenum GLenum * types
GLfloat GLfloat f
GLenum type
GLint ref
GLuint name
GLuint res
GLuint GLfloat * val
GLuint GLuint * names
GLenum array
GLdouble s
[6]
Definition qopenglext.h:235
void deduplicate(Container &container)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned char quint8
Definition qtypes.h:41
QJsonObject toRef(QV4DataCollector::Ref ref)
const QV4::Object * collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine, QJsonObject &dict)
QFrame frame
[0]
QJSEngine engine
[0]
ExecutionContext * context() const
CppStackFrame * currentStackFrame
Heap::String * newString(const QString &s=QString())
Heap::ArrayObject * newArrayObject(int count=0)
Q_QML_PRIVATE_EXPORT QString keyAt(uint index) const
static ReturnedValue call(ExecutionEngine *, const Value &)
const T * as() const
Definition qv4value_p.h:132
QString toQStringNoThrow() const
Definition qv4value.cpp:122