Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
48QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes(int frame)
49{
50 QVector<QV4::Heap::ExecutionContext::ContextType> types;
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
82
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 QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i));
192 QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine));
193 names.append(propName->toQString());
194 v = ctxt->getProperty(propName);
195 collectedRefs.append(addValueRef(v));
196 }
197
198 Q_ASSERT(names.size() == collectedRefs.size());
199 QV4::ScopedString propName(scope);
200 for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
201 propName = engine()->newString(names.at(i));
202 scopeObject->put(propName, (v = getValue(collectedRefs.at(i))));
203 }
204 }
205
206 *dict = lookupRef(addRef(scopeObject));
207
208 return true;
209}
210
212 QJsonObject dict;
213 dict.insert(QStringLiteral("ref"), qint64(ref));
214 return dict;
215}
216
218{
220 frame[QLatin1String("index")] = frameNr;
221 frame[QLatin1String("debuggerFrame")] = false;
222 frame[QLatin1String("func")] = stackFrame.function;
223 frame[QLatin1String("script")] = stackFrame.source;
224 frame[QLatin1String("line")] = qAbs(stackFrame.line) - 1;
225 if (stackFrame.column >= 0)
226 frame[QLatin1String("column")] = stackFrame.column;
227
228 QJsonArray scopes;
229 QV4::Scope scope(engine());
230 QV4::ScopedContext ctxt(scope, findContext(frameNr));
231 while (ctxt) {
232 if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
233 if (cCtxt->d()->activation)
234 break;
235 }
236 ctxt = ctxt->d()->outer;
237 }
238
239 if (ctxt) {
240 QV4::ScopedValue o(scope, ctxt->d()->activation);
241 frame[QLatin1String("receiver")] = toRef(addValueRef(o));
242 }
243
244 // Only type and index are used by Qt Creator, so we keep it easy:
245 QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = getScopeTypes(frameNr);
246 for (int i = 0, ei = scopeTypes.size(); i != ei; ++i) {
247 int type = encodeScopeType(scopeTypes[i]);
248 if (type == -1)
249 continue;
250
251 QJsonObject scope;
252 scope[QLatin1String("index")] = i;
253 scope[QLatin1String("type")] = type;
254 scopes.push_back(scope);
255 }
256
257 frame[QLatin1String("scopes")] = scopes;
258
259 return frame;
260}
261
263{
264 m_values.set(engine(), engine()->newArrayObject());
265}
266
267QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
268{
269 class ExceptionStateSaver
270 {
271 quint8 *hasExceptionLoc;
272 quint8 hadException;
273
274 public:
275 ExceptionStateSaver(QV4::ExecutionEngine *engine)
276 : hasExceptionLoc(&engine->hasException)
277 , hadException(false)
278 { std::swap(*hasExceptionLoc, hadException); }
279
280 ~ExceptionStateSaver()
281 { std::swap(*hasExceptionLoc, hadException); }
282 };
283
284 // if we wouldn't do this, the put won't work.
285 ExceptionStateSaver resetExceptionState(engine());
286 QV4::Scope scope(engine());
287 QV4::ScopedObject array(scope, m_values.value());
288 if (deduplicate) {
289 for (Ref i = 0; i < array->getLength(); ++i) {
290 if (array->get(i) == value.rawValue())
291 return i;
292 }
293 }
294 Ref ref = array->getLength();
295 array->put(ref, value);
296 Q_ASSERT(array->getLength() - 1 == ref);
297 return ref;
298}
299
300QV4::ReturnedValue QV4DataCollector::getValue(Ref ref)
301{
302 QV4::Scope scope(engine());
303 QV4::ScopedObject array(scope, m_values.value());
304 Q_ASSERT(ref < array->getLength());
305 return array->get(ref, nullptr);
306}
307
309{
310public:
312 {
313 if (QQmlEngine *e = engine->qmlEngine()) {
314 m_engine = QQmlEnginePrivate::get(e);
315 m_capture = m_engine->propertyCapture;
316 m_engine->propertyCapture = nullptr;
317 }
318 }
319
321 {
322 if (m_engine && m_capture) {
323 Q_ASSERT(!m_engine->propertyCapture);
324 m_engine->propertyCapture = m_capture;
325 }
326 }
327
328private:
329 QQmlEnginePrivate *m_engine = nullptr;
330 QQmlPropertyCapture *m_capture = nullptr;
331};
332
333QJsonArray QV4DataCollector::collectProperties(const QV4::Object *object)
334{
335 CapturePreventer capturePreventer(engine());
336 Q_UNUSED(capturePreventer);
337
339
340 QV4::Scope scope(engine());
342 QV4::ScopedValue name(scope);
343 QV4::ScopedValue value(scope);
344 while (true) {
346 name = it.nextPropertyNameAsString(&v);
347 if (name->isNull())
348 break;
349 QString key = name->toQStringNoThrow();
350 value = v;
351 res.append(collectAsJson(key, value));
352 }
353
354 return res;
355}
356
357QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::ScopedValue &value)
358{
359 QJsonObject dict;
360 if (!name.isNull())
361 dict.insert(QStringLiteral("name"), name);
362 if (value->isManaged() && !value->isString()) {
363 Ref ref = addRef(value);
364 dict.insert(QStringLiteral("ref"), qint64(ref));
365 }
366
367 collectProperty(value, engine(), dict);
368 return dict;
369}
370
CapturePreventer(QV4::ExecutionEngine *engine)
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\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.
QQmlPropertyCapture * propertyCapture
static QQmlEnginePrivate * get(QQmlEngine *e)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & append(QChar c)
Definition qstring.cpp:3252
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)
QVector< uint > Refs
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
QSet< QString >::iterator it
Combined button and popup list for selecting options.
quint64 ReturnedValue
Scoped< String > ScopedString
Scoped< ExecutionContext > ScopedContext
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qIsFinite(qfloat16 f) noexcept
Definition qfloat16.h:285
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:284
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
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
GLuint GLfloat * val
GLuint GLuint * names
GLenum array
#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:34
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
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(char16_t c)
Heap::ArrayObject * newArrayObject(int count=0)
Q_QML_EXPORT ReturnedValue keyAt(uint index) const
bool put(StringOrSymbol *name, const Value &v, Value *receiver=nullptr)
static ReturnedValue call(ExecutionEngine *, const Value &)
ExecutionEngine * engine
const T * as() const
Definition qv4value_p.h:132