8#include <private/qqmlcontext_p.h>
9#include <private/qqmlengine_p.h>
10#include <private/qv4identifierhash_p.h>
11#include <private/qv4identifiertable_p.h>
12#include <private/qv4objectiterator_p.h>
13#include <private/qv4runtime_p.h>
14#include <private/qv4script_p.h>
15#include <private/qv4stackframe_p.h>
16#include <private/qv4string_p.h>
18#include <QtCore/qjsonarray.h>
19#include <QtCore/qjsonobject.h>
23QV4::CppStackFrame *QV4DataCollector::findFrame(
int frame)
25 QV4::CppStackFrame *f = engine()->currentStackFrame;
35 QV4::CppStackFrame *f = findFrame(frame);
37 return f ? f->context()->d() :
nullptr;
40QV4::Heap::ExecutionContext *
QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctx,
int scope)
42 for (; scope > 0 && ctx; --scope)
50 QVector<QV4::Heap::ExecutionContext::ContextType> types;
52 QV4::Heap::ExecutionContext *it = findFrame(frame)->context()->d();
54 for (; it; it = it->outer)
55 types.append(QV4::Heap::ExecutionContext::ContextType(it->type));
60int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
63 case QV4::Heap::ExecutionContext::Type_GlobalContext:
65 case QV4::Heap::ExecutionContext::Type_WithContext:
67 case QV4::Heap::ExecutionContext::Type_CallContext:
69 case QV4::Heap::ExecutionContext::Type_QmlContext:
71 case QV4::Heap::ExecutionContext::Type_BlockContext:
80 m_values.set(engine, engine->newArrayObject());
91 QV4::Scope scope(engine);
92 QV4::ScopedValue typeString(scope, QV4::Runtime::TypeofValue::call(engine, value));
93 dict.insert(QStringLiteral(
"type"), typeString->toQStringNoThrow());
95 const QLatin1String valueKey(
"value");
96 switch (value->type()) {
97 case QV4::Value::Empty_Type:
98 Q_ASSERT(!
"empty Value encountered");
100 case QV4::Value::Undefined_Type:
101 dict.insert(valueKey, QJsonValue::Undefined);
103 case QV4::Value::Null_Type:
104 dict.insert(valueKey, QJsonValue::Null);
106 case QV4::Value::Boolean_Type:
107 dict.insert(valueKey, value->booleanValue());
109 case QV4::Value::Managed_Type:
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>()) {
115 dict.insert(valueKey, qint64(a->getLength()));
117 }
else if (
const QV4::Object *o = value->as<QV4::Object>()) {
118 int numProperties = 0;
119 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
120 QV4::PropertyAttributes attrs;
121 QV4::ScopedPropertyKey name(scope);
123 name = it.next(
nullptr, &attrs);
124 if (!name->isValid())
128 dict.insert(valueKey, numProperties);
134 case QV4::Value::Integer_Type:
135 dict.insert(valueKey, value->integerValue());
138 const double val = value->doubleValue();
140 dict.insert(valueKey, val);
141 else if (qIsNaN(val))
142 dict.insert(valueKey, QStringLiteral(
"NaN"));
144 dict.insert(valueKey, QStringLiteral(
"-Infinity"));
146 dict.insert(valueKey, QStringLiteral(
"Infinity"));
156 dict.insert(QStringLiteral(
"handle"), qint64(ref));
157 QV4::Scope scope(engine());
158 QV4::ScopedValue value(scope, getValue(ref));
160 const QV4::Object *object = collectProperty(value, engine(), dict);
162 dict.insert(QStringLiteral(
"properties"), collectProperties(object));
169 QV4::Scope scope(engine());
170 QV4::ScopedObject array(scope, m_values.value());
171 return ref < array->getLength();
176 QV4::Scope scope(engine());
178 QV4::Scoped<QV4::ExecutionContext> ctxt(scope, findScope(findContext(frameNr), scopeNr));
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) {
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));
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))));
206 *dict = lookupRef(addRef(scopeObject));
213 dict.insert(QStringLiteral(
"ref"), qint64(ref));
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;
229 QV4::Scope scope(engine());
230 QV4::ScopedContext ctxt(scope, findContext(frameNr));
232 if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
233 if (cCtxt->d()->activation)
236 ctxt = ctxt->d()->outer;
240 QV4::ScopedValue o(scope, ctxt->d()->activation);
241 frame[QLatin1String(
"receiver")] = toRef(addValueRef(o));
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]);
252 scope[QLatin1String(
"index")] = i;
253 scope[QLatin1String(
"type")] = type;
254 scopes.push_back(scope);
257 frame[QLatin1String(
"scopes")] = scopes;
264 m_values.set(engine(), engine()->newArrayObject());
269 class ExceptionStateSaver
271 quint8 *hasExceptionLoc;
275 ExceptionStateSaver(QV4::ExecutionEngine *engine)
276 : hasExceptionLoc(&engine->hasException)
277 , hadException(
false)
278 { std::swap(*hasExceptionLoc, hadException); }
280 ~ExceptionStateSaver()
281 { std::swap(*hasExceptionLoc, hadException); }
285 ExceptionStateSaver resetExceptionState(engine());
286 QV4::Scope scope(engine());
287 QV4::ScopedObject array(scope, m_values.value());
289 for (
Ref i = 0; i < array->getLength(); ++i) {
290 if (array->get(i) == value.rawValue())
294 Ref ref = array->getLength();
295 array->put(ref, value);
296 Q_ASSERT(array->getLength() - 1 == ref);
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);
313 if (QQmlEngine *e = engine->qmlEngine()) {
314 m_engine = QQmlEnginePrivate::get(e);
315 m_capture = m_engine->propertyCapture;
316 m_engine->propertyCapture =
nullptr;
322 if (m_engine && m_capture) {
323 Q_ASSERT(!m_engine->propertyCapture);
324 m_engine->propertyCapture = m_capture;
329 QQmlEnginePrivate *m_engine =
nullptr;
330 QQmlPropertyCapture *m_capture =
nullptr;
336 Q_UNUSED(capturePreventer);
340 QV4::Scope scope(engine());
341 QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
342 QV4::ScopedValue name(scope);
343 QV4::ScopedValue value(scope);
346 name = it.nextPropertyNameAsString(&v);
349 QString key = name->toQStringNoThrow();
351 res.append(collectAsJson(key, value));
357QJsonObject
QV4DataCollector::collectAsJson(
const QString &name,
const QV4::ScopedValue &value)
361 dict.insert(QStringLiteral(
"name"), name);
362 if (value->isManaged() && !value->isString()) {
363 Ref ref = addRef(value);
364 dict.insert(QStringLiteral(
"ref"), qint64(ref));
367 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)
QJsonObject toRef(QV4DataCollector::Ref ref)
const QV4::Object * collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine, QJsonObject &dict)