9#include <private/qqmlcontext_p.h>
10#include <private/qqmlengine_p.h>
11#include <private/qv4identifierhash_p.h>
12#include <private/qv4identifiertable_p.h>
13#include <private/qv4objectiterator_p.h>
14#include <private/qv4runtime_p.h>
15#include <private/qv4script_p.h>
16#include <private/qv4stackframe_p.h>
17#include <private/qv4string_p.h>
19#include <QtCore/qjsonarray.h>
20#include <QtCore/qjsonobject.h>
24QV4::CppStackFrame *QV4DataCollector::findFrame(
int frame)
26 QV4::CppStackFrame *f = engine()->currentStackFrame;
36 QV4::CppStackFrame *f = findFrame(frame);
38 return f ? f->context()->d() :
nullptr;
41QV4::Heap::ExecutionContext *
QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctx,
int scope)
43 for (; scope > 0 && ctx; --scope)
51 QVector<QV4::Heap::ExecutionContext::ContextType> types;
53 QV4::Heap::ExecutionContext *it = findFrame(frame)->context()->d();
55 for (; it; it = it->outer)
56 types.append(QV4::Heap::ExecutionContext::ContextType(it->type));
61int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
64 case QV4::Heap::ExecutionContext::Type_GlobalContext:
66 case QV4::Heap::ExecutionContext::Type_WithContext:
68 case QV4::Heap::ExecutionContext::Type_CallContext:
70 case QV4::Heap::ExecutionContext::Type_QmlContext:
72 case QV4::Heap::ExecutionContext::Type_BlockContext:
81 m_values.set(engine, engine->newArrayObject());
92 QV4::Scope scope(engine);
93 QV4::ScopedValue typeString(scope, QV4::Runtime::TypeofValue::call(engine, value));
94 dict.insert(QStringLiteral(
"type"), typeString->toQStringNoThrow());
96 const QLatin1String valueKey(
"value");
97 switch (value->type()) {
98 case QV4::Value::Empty_Type:
99 Q_ASSERT(!
"empty Value encountered");
101 case QV4::Value::Undefined_Type:
102 dict.insert(valueKey, QJsonValue::Undefined);
104 case QV4::Value::Null_Type:
105 dict.insert(valueKey, QJsonValue::Null);
107 case QV4::Value::Boolean_Type:
108 dict.insert(valueKey, value->booleanValue());
110 case QV4::Value::Managed_Type:
111 if (
const QV4::String *s = value->as<QV4::String>()) {
112 dict.insert(valueKey, s->toQString());
113 }
else if (
const QV4::ArrayObject *a = value->as<QV4::ArrayObject>()) {
116 dict.insert(valueKey, qint64(a->getLength()));
118 }
else if (
const QV4::Object *o = value->as<QV4::Object>()) {
119 int numProperties = 0;
120 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
121 QV4::PropertyAttributes attrs;
122 QV4::ScopedPropertyKey name(scope);
124 name = it.next(
nullptr, &attrs);
125 if (!name->isValid())
129 dict.insert(valueKey, numProperties);
135 case QV4::Value::Integer_Type:
136 dict.insert(valueKey, value->integerValue());
139 const double val = value->doubleValue();
141 dict.insert(valueKey, val);
142 else if (qIsNaN(val))
143 dict.insert(valueKey, QStringLiteral(
"NaN"));
145 dict.insert(valueKey, QStringLiteral(
"-Infinity"));
147 dict.insert(valueKey, QStringLiteral(
"Infinity"));
157 dict.insert(QStringLiteral(
"handle"), qint64(ref));
158 QV4::Scope scope(engine());
159 QV4::ScopedValue value(scope, getValue(ref));
161 const QV4::Object *object = collectProperty(value, engine(), dict);
163 dict.insert(QStringLiteral(
"properties"), collectProperties(object));
170 QV4::Scope scope(engine());
171 QV4::ScopedObject array(scope, m_values.value());
172 return ref < array->getLength();
177 QV4::Scope scope(engine());
179 QV4::Scoped<QV4::ExecutionContext> ctxt(scope, findScope(findContext(frameNr), scopeNr));
183 QV4::ScopedObject scopeObject(scope, engine()->newObject());
184 if (ctxt->d()->type == QV4::Heap::ExecutionContext::Type_CallContext ||
185 ctxt->d()->type == QV4::Heap::ExecutionContext::Type_BlockContext) {
189 QV4::ScopedValue v(scope);
190 QV4::Heap::InternalClass *ic = ctxt->internalClass();
191 for (uint i = 0; i < ic->size; ++i) {
192 QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i));
193 QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine));
194 names.append(propName->toQString());
195 v = ctxt->getProperty(propName);
196 collectedRefs.append(addValueRef(v));
199 Q_ASSERT(names.size() == collectedRefs.size());
200 QV4::ScopedString propName(scope);
201 for (
int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
202 propName = engine()->newString(names.at(i));
203 scopeObject->put(propName, (v = getValue(collectedRefs.at(i))));
207 *dict = lookupRef(addRef(scopeObject));
214 dict.insert(QStringLiteral(
"ref"), qint64(ref));
221 frame[QLatin1String(
"index")] = frameNr;
222 frame[QLatin1String(
"debuggerFrame")] =
false;
223 frame[QLatin1String(
"func")] = stackFrame.function;
224 frame[QLatin1String(
"script")] = stackFrame.source;
225 frame[QLatin1String(
"line")] = qAbs(stackFrame.line) - 1;
226 if (stackFrame.column >= 0)
227 frame[QLatin1String(
"column")] = stackFrame.column;
230 QV4::Scope scope(engine());
231 QV4::ScopedContext ctxt(scope, findContext(frameNr));
233 if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
234 if (cCtxt->d()->activation)
237 ctxt = ctxt->d()->outer;
241 QV4::ScopedValue o(scope, ctxt->d()->activation);
242 frame[QLatin1String(
"receiver")] = toRef(addValueRef(o));
246 QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = getScopeTypes(frameNr);
247 for (
int i = 0, ei = scopeTypes.size(); i != ei; ++i) {
248 int type = encodeScopeType(scopeTypes[i]);
253 scope[QLatin1String(
"index")] = i;
254 scope[QLatin1String(
"type")] = type;
255 scopes.push_back(scope);
258 frame[QLatin1String(
"scopes")] = scopes;
265 m_values.set(engine(), engine()->newArrayObject());
270 class ExceptionStateSaver
272 quint8 *hasExceptionLoc;
276 ExceptionStateSaver(QV4::ExecutionEngine *engine)
277 : hasExceptionLoc(&engine->hasException)
278 , hadException(
false)
279 { std::swap(*hasExceptionLoc, hadException); }
281 ~ExceptionStateSaver()
282 { std::swap(*hasExceptionLoc, hadException); }
286 ExceptionStateSaver resetExceptionState(engine());
287 QV4::Scope scope(engine());
288 QV4::ScopedObject array(scope, m_values.value());
290 for (
Ref i = 0; i < array->getLength(); ++i) {
291 if (array->get(i) == value.rawValue())
295 Ref ref = array->getLength();
296 array->put(ref, value);
297 Q_ASSERT(array->getLength() - 1 == ref);
303 QV4::Scope scope(engine());
304 QV4::ScopedObject array(scope, m_values.value());
305 Q_ASSERT(ref < array->getLength());
306 return array->get(ref,
nullptr);
314 if (QQmlEngine *e = engine->qmlEngine()) {
315 m_engine = QQmlEnginePrivate::get(e);
316 m_capture = m_engine->propertyCapture;
317 m_engine->propertyCapture =
nullptr;
323 if (m_engine && m_capture) {
324 Q_ASSERT(!m_engine->propertyCapture);
325 m_engine->propertyCapture = m_capture;
330 QQmlEnginePrivate *m_engine =
nullptr;
331 QQmlPropertyCapture *m_capture =
nullptr;
337 Q_UNUSED(capturePreventer);
341 QV4::Scope scope(engine());
342 QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
343 QV4::ScopedValue name(scope);
344 QV4::ScopedValue value(scope);
347 name = it.nextPropertyNameAsString(&v);
350 QString key = name->toQStringNoThrow();
352 res.append(collectAsJson(key, value));
358QJsonObject
QV4DataCollector::collectAsJson(
const QString &name,
const QV4::ScopedValue &value)
362 dict.insert(QStringLiteral(
"name"), name);
363 if (value->isManaged() && !value->isString()) {
364 Ref ref = addRef(value);
365 dict.insert(QStringLiteral(
"ref"), qint64(ref));
368 collectProperty(value, engine(), dict);
CapturePreventer(QV4::ExecutionEngine *engine)
bool collectScope(QJsonObject *dict, int frameNr, int scopeNr)
bool isValidRef(Ref ref) const
Ref addValueRef(const QV4::ScopedValue &value)
QJsonObject lookupRef(Ref ref)
QV4DataCollector(QV4::ExecutionEngine *engine)
QVector< QV4::Heap::ExecutionContext::ContextType > getScopeTypes(int frame)
QV4::Heap::ExecutionContext * findContext(int frame)
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
Combined button and popup list for selecting options.
QJsonObject toRef(QV4DataCollector::Ref ref)
const QV4::Object * collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine, QJsonObject &dict)