Merge remote-tracking branch 'origin/dev' into scenegraphng

Change-Id: I35715e07b6f837f21cd8e8898f19d97af92c6b69
This commit is contained in:
Andy Nichols 2016-05-31 12:11:36 +02:00
commit 91e1a65cdb
70 changed files with 934 additions and 529 deletions

View File

@ -4628,6 +4628,7 @@ Module {
Property { name: "pixelDelta"; type: "QPoint"; isReadonly: true } Property { name: "pixelDelta"; type: "QPoint"; isReadonly: true }
Property { name: "buttons"; type: "int"; isReadonly: true } Property { name: "buttons"; type: "int"; isReadonly: true }
Property { name: "modifiers"; type: "int"; isReadonly: true } Property { name: "modifiers"; type: "int"; isReadonly: true }
Property { name: "inverted"; type: "bool" }
Property { name: "accepted"; type: "bool" } Property { name: "accepted"; type: "bool" }
} }
Component { Component {

View File

@ -145,7 +145,7 @@ void SignalTransition::invoke()
void SignalTransition::connectTriggered() void SignalTransition::connectTriggered()
{ {
if (!m_complete || !m_cdata) if (!m_complete || !m_compilationUnit)
return; return;
QObject *target = senderObject(); QObject *target = senderObject();
@ -165,7 +165,7 @@ void SignalTransition::connectTriggered()
QQmlBoundSignalExpression *expression = ctxtdata ? QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target, signalIndex, new QQmlBoundSignalExpression(target, signalIndex,
ctxtdata, this, m_cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0; ctxtdata, this, m_compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
if (expression) if (expression)
expression->setNotifyOnValueChanged(false); expression->setNotifyOnValueChanged(false);
m_signalExpression = expression; m_signalExpression = expression;
@ -190,10 +190,10 @@ void SignalTransitionParser::verifyBindings(const QV4::CompiledData::Unit *qmlUn
} }
} }
void SignalTransitionParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) void SignalTransitionParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
SignalTransition *st = qobject_cast<SignalTransition*>(object); SignalTransition *st = qobject_cast<SignalTransition*>(object);
st->m_cdata = cdata; st->m_compilationUnit = compilationUnit;
st->m_bindings = bindings; st->m_bindings = bindings;
} }

View File

@ -90,7 +90,7 @@ private:
QJSValue m_signal; QJSValue m_signal;
QQmlScriptString m_guard; QQmlScriptString m_guard;
bool m_complete; bool m_complete;
QQmlRefPointer<QQmlCompiledData> m_cdata; QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
QList<const QV4::CompiledData::Binding *> m_bindings; QList<const QV4::CompiledData::Binding *> m_bindings;
QQmlBoundSignalExpressionPointer m_signalExpression; QQmlBoundSignalExpressionPointer m_signalExpression;
}; };
@ -99,7 +99,7 @@ class SignalTransitionParser : public QQmlCustomParser
{ {
public: public:
void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) Q_DECL_OVERRIDE; void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) Q_DECL_OVERRIDE;
void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE; void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -114,7 +114,7 @@ void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
debugger->setBreakOnThrow(m_breakOnThrow); debugger->setBreakOnThrow(m_breakOnThrow);
foreach (const BreakPoint &breakPoint, m_breakPoints.values()) for (const BreakPoint &breakPoint : qAsConst(m_breakPoints))
if (breakPoint.enabled) if (breakPoint.enabled)
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);

View File

@ -55,7 +55,7 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
connect(this, SIGNAL(profilingDisabledWhileWaiting()), connect(this, SIGNAL(profilingDisabledWhileWaiting()),
engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection); engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection);
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
engine->profiler, SLOT(setTimer(QElapsedTimer))); engine->profiler, SLOT(setTimer(QElapsedTimer)));
connect(engine->profiler, connect(engine->profiler,
@ -68,49 +68,65 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
// use of QDataStream can skew results // use of QDataStream can skew results
// (see tst_qqmldebugtrace::trace() benchmark) // (see tst_qqmldebugtrace::trace() benchmark)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
const QQmlProfiler::LocationHash &locations, QQmlProfiler::LocationHash &locations,
QList<QByteArray> &messages) QList<QByteArray> &messages,
bool trackLocations)
{ {
QQmlDebugPacket ds; QQmlDebugPacket ds;
Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO, Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO,
"You can use at most 31 message types."); "You can use at most 31 message types.");
for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0; for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0;
++decodedMessageType) { ++decodedMessageType) {
if ((d.messageType & (1 << decodedMessageType)) == 0) if (decodedMessageType == QQmlProfilerDefinitions::RangeData
continue; || (d.messageType & (1 << decodedMessageType)) == 0) {
continue; // RangeData is sent together with RangeLocation
}
//### using QDataStream is relatively expensive if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); || decodedMessageType == QQmlProfilerDefinitions::RangeStart) {
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
QQmlProfiler::Location l = locations.value(d.locationId); if (trackLocations && d.locationId != 0)
ds << static_cast<qint64>(d.locationId);
switch (decodedMessageType) { } else {
case QQmlProfilerDefinitions::RangeStart: auto i = locations.find(d.locationId);
case QQmlProfilerDefinitions::RangeEnd: if (i != locations.end()) {
break; ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
case QQmlProfilerDefinitions::RangeData: ds << (i->url.isEmpty() ? i->location.sourceFile : i->url.toString())
ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile); << static_cast<qint32>(i->location.line)
break; << static_cast<qint32>(i->location.column);
case QQmlProfilerDefinitions::RangeLocation: if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) {
ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString()) // Send both, location and data ...
<< static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column); if (trackLocations)
break; ds << static_cast<qint64>(d.locationId);
default: messages.append(ds.squeezedData());
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); ds.clear();
break; ds << d.time << QQmlProfilerDefinitions::RangeData
<< static_cast<quint32>(d.detailType)
<< (i->location.sourceFile.isEmpty() ? i->url.toString() :
i->location.sourceFile);
}
if (trackLocations) {
ds << static_cast<qint64>(d.locationId);
locations.erase(i); // ... so that we can erase here without missing anything.
}
} else {
// Skip RangeData and RangeLocation: We've already sent them
continue;
}
} }
messages.append(ds.squeezedData()); messages.append(ds.squeezedData());
ds.clear(); ds.clear();
} }
} }
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations)
{ {
while (next != data.length()) { while (next != data.length()) {
const QQmlProfilerData &nextData = data.at(next); const QQmlProfilerData &nextData = data.at(next);
if (nextData.time > until || messages.length() > s_numMessagesPerBatch) if (nextData.time > until || messages.length() > s_numMessagesPerBatch)
return nextData.time; return nextData.time;
qQmlProfilerDataToByteArrays(nextData, locations, messages); qQmlProfilerDataToByteArrays(nextData, locations, messages, trackLocations);
++next; ++next;
} }

View File

@ -60,7 +60,8 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
Q_OBJECT Q_OBJECT
public: public:
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine); QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine);
qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE; qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations) Q_DECL_OVERRIDE;
public slots: public slots:
void receiveData(const QVector<QQmlProfilerData> &new_data, void receiveData(const QVector<QQmlProfilerData> &new_data,

View File

@ -57,7 +57,7 @@ Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) : QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QQmlProfilerService>(1, parent), QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
m_waitingForStop(false) m_waitingForStop(false), m_useMessageTypes(false)
{ {
m_timer.start(); m_timer.start();
QQmlAbstractProfilerAdapter *quickAdapter = QQmlAbstractProfilerAdapter *quickAdapter =
@ -309,7 +309,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
m_waitingForStop = true; m_waitingForStop = true;
foreach (QQmlAbstractProfilerAdapter *profiler, reporting) foreach (QQmlAbstractProfilerAdapter *profiler, reporting)
profiler->reportData(); profiler->reportData(m_useMessageTypes);
foreach (QQmlAbstractProfilerAdapter *profiler, stopping) foreach (QQmlAbstractProfilerAdapter *profiler, stopping)
profiler->stopProfiling(); profiler->stopProfiling();
@ -343,7 +343,8 @@ void QQmlProfilerServiceImpl::sendMessages()
m_startTimes.erase(m_startTimes.begin()); m_startTimes.erase(m_startTimes.begin());
qint64 next = first->sendMessages(m_startTimes.isEmpty() ? qint64 next = first->sendMessages(m_startTimes.isEmpty() ?
std::numeric_limits<qint64>::max() : std::numeric_limits<qint64>::max() :
m_startTimes.begin().key(), messages); m_startTimes.begin().key(), messages,
m_useMessageTypes);
if (next != -1) if (next != -1)
m_startTimes.insert(next, first); m_startTimes.insert(next, first);
@ -418,6 +419,8 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
disconnect(this, SIGNAL(stopFlushTimer()), &m_flushTimer, SLOT(stop())); disconnect(this, SIGNAL(stopFlushTimer()), &m_flushTimer, SLOT(stop()));
} }
} }
if (!stream.atEnd())
stream >> m_useMessageTypes;
// If engineId == -1 objectForId() and then the cast will return 0. // If engineId == -1 objectForId() and then the cast will return 0.
if (enabled) if (enabled)
@ -435,14 +438,14 @@ void QQmlProfilerServiceImpl::flush()
foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) { foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) {
if (profiler->isRunning()) { if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler); m_startTimes.insert(-1, profiler);
profiler->reportData(); profiler->reportData(m_useMessageTypes);
} }
} }
foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
if (profiler->isRunning()) { if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler); m_startTimes.insert(-1, profiler);
profiler->reportData(); profiler->reportData(m_useMessageTypes);
} }
} }
} }

View File

@ -116,6 +116,7 @@ private:
QElapsedTimer m_timer; QElapsedTimer m_timer;
QTimer m_flushTimer; QTimer m_flushTimer;
bool m_waitingForStop; bool m_waitingForStop;
bool m_useMessageTypes;
QList<QQmlAbstractProfilerAdapter *> m_globalProfilers; QList<QQmlAbstractProfilerAdapter *> m_globalProfilers;
QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers; QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers;

View File

@ -58,7 +58,7 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()), connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()),
Qt::DirectConnection); Qt::DirectConnection);
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
engine->profiler, SLOT(setTimer(QElapsedTimer))); engine->profiler, SLOT(setTimer(QElapsedTimer)));
connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash, connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash,
@ -105,13 +105,13 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes
return callNext == -1 ? memoryNext : qMin(callNext, memoryNext); return callNext == -1 ? memoryNext : qMin(callNext, memoryNext);
} }
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations)
{ {
QQmlDebugPacket d; QQmlDebugPacket d;
// Make it const, so that we cannot accidentally detach it. // Make it const, so that we cannot accidentally detach it.
const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData; const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData;
const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations;
while (true) { while (true) {
while (!m_stack.isEmpty() && while (!m_stack.isEmpty() &&
@ -133,17 +133,27 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
return finalizeMessages(until, messages, props.start, d); return finalizeMessages(until, messages, props.start, d);
appendMemoryEvents(props.start, messages, d); appendMemoryEvents(props.start, messages, d);
auto location = functionLocations.constFind(props.id); auto location = m_functionLocations.find(props.id);
Q_ASSERT(location != functionLocations.constEnd());
d << props.start << RangeStart << Javascript; d << props.start << RangeStart << Javascript;
messages.push_back(d.squeezedData()); if (trackLocations)
d.clear(); d << static_cast<qint64>(props.id);
d << props.start << RangeLocation << Javascript << location->file << location->line if (location != m_functionLocations.end()) {
<< location->column; messages.push_back(d.squeezedData());
messages.push_back(d.squeezedData()); d.clear();
d.clear(); d << props.start << RangeLocation << Javascript << location->file << location->line
d << props.start << RangeData << Javascript << location->name; << location->column;
if (trackLocations)
d << static_cast<qint64>(props.id);
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeData << Javascript << location->name;
if (trackLocations) {
d << static_cast<qint64>(props.id);
m_functionLocations.erase(location);
}
}
messages.push_back(d.squeezedData()); messages.push_back(d.squeezedData());
d.clear(); d.clear();
m_stack.push(props.end); m_stack.push(props.end);

View File

@ -67,7 +67,8 @@ class QV4ProfilerAdapter : public QQmlAbstractProfilerAdapter {
public: public:
QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine); QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine);
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages); virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations) override;
signals: signals:
void v4ProfilingEnabled(quint64 v4Features); void v4ProfilingEnabled(quint64 v4Features);

View File

@ -61,8 +61,8 @@ QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) :
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection); QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabledWhileWaiting()), connect(this, SIGNAL(profilingDisabledWhileWaiting()),
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection); QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
connect(this, SIGNAL(dataRequested()), connect(this, SIGNAL(dataRequested(bool)),
QQuickProfiler::s_instance, SLOT(reportDataImpl()), Qt::DirectConnection); QQuickProfiler::s_instance, SLOT(reportDataImpl(bool)), Qt::DirectConnection);
connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)), connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)),
this, SLOT(receiveData(QVector<QQuickProfilerData>)), Qt::DirectConnection); this, SLOT(receiveData(QVector<QQuickProfilerData>)), Qt::DirectConnection);
} }
@ -150,8 +150,10 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
} }
} }
qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations)
{ {
Q_UNUSED(trackLocations);
while (next < m_data.size()) { while (next < m_data.size()) {
if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch) if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch)
qQuickProfilerDataToByteArrays(m_data[next++], messages); qQuickProfilerDataToByteArrays(m_data[next++], messages);

View File

@ -61,7 +61,7 @@ class QQuickProfilerAdapter : public QQmlAbstractProfilerAdapter {
public: public:
QQuickProfilerAdapter(QObject *parent = 0); QQuickProfilerAdapter(QObject *parent = 0);
~QQuickProfilerAdapter(); ~QQuickProfilerAdapter();
qint64 sendMessages(qint64 until, QList<QByteArray> &messages); qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) override;
public slots: public slots:
void receiveData(const QVector<QQuickProfilerData> &new_data); void receiveData(const QVector<QQuickProfilerData> &new_data);

View File

@ -1089,7 +1089,7 @@ void QSGD3D12RenderLoop::polishAndSync(WindowData *w, bool inExpose)
} }
// Flush pending touch events. // Flush pending touch events.
QQuickWindowPrivate::get(window)->flushDelayedTouchEvent(); QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
// The delivery of the event might have caused the window to stop rendering // The delivery of the event might have caused the window to stop rendering
w = windowFor(windows, window); w = windowFor(windows, window);
if (!w || !w->thread || !w->thread->exposedWindow) { if (!w || !w->thread || !w->thread->exposedWindow) {

View File

@ -72,23 +72,24 @@ using namespace QmlIR;
return false; \ return false; \
} }
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &loc) void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
{ {
inheritedTypeNameIndex = typeNameIndex; inheritedTypeNameIndex = typeNameIndex;
location.line = loc.startLine; location.line = loc.startLine;
location.column = loc.startColumn; location.column = loc.startColumn;
idIndex = id; idNameIndex = idIndex;
id = -1;
indexOfDefaultPropertyOrAlias = -1; indexOfDefaultPropertyOrAlias = -1;
defaultPropertyIsAlias = false; defaultPropertyIsAlias = false;
flags = QV4::CompiledData::Object::NoFlag;
properties = pool->New<PoolList<Property> >(); properties = pool->New<PoolList<Property> >();
aliases = pool->New<PoolList<Alias> >(); aliases = pool->New<PoolList<Alias> >();
qmlSignals = pool->New<PoolList<Signal> >(); qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >(); bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >(); functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >(); functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
runtimeFunctionIndices = 0;
declarationsOverride = 0; declarationsOverride = 0;
} }
@ -1237,10 +1238,10 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
if (illegalNames.contains(idQString)) if (illegalNames.contains(idQString))
COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property")); COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
if (_object->idIndex != emptyStringIndex) if (_object->idNameIndex != emptyStringIndex)
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times")); COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
_object->idIndex = registerString(idQString); _object->idNameIndex = registerString(idQString);
_object->locationOfIdProperty.line = idLocation.startLine; _object->locationOfIdProperty.line = idLocation.startLine;
_object->locationOfIdProperty.column = idLocation.startColumn; _object->locationOfIdProperty.column = idLocation.startColumn;
@ -1368,12 +1369,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count(); const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
const int objectOffsetTableSize = output.objects.count() * sizeof(quint32); const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
QHash<Object*, quint32> objectOffsets; QHash<const Object*, quint32> objectOffsets;
int objectsSize = 0; int objectsSize = 0;
foreach (Object *o, output.objects) { foreach (Object *o, output.objects) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize); objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
int signalTableSize = 0; int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next) for (const Signal *s = o->firstSignal(); s; s = s->next)
@ -1413,14 +1414,17 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
// write objects // write objects
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects); quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize; char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
foreach (Object *o, output.objects) { for (int i = 0; i < output.objects.count(); ++i) {
const Object *o = output.objects.at(i);
*objectTable++ = objectOffsets.value(o); *objectTable++ = objectOffsets.value(o);
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr); QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex; objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias; objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias; objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
objectToWrite->idIndex = o->idIndex; objectToWrite->flags = o->flags;
objectToWrite->idNameIndex = o->idNameIndex;
objectToWrite->id = o->id;
objectToWrite->location = o->location; objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty; objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@ -1446,9 +1450,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectToWrite->offsetToBindings = nextOffset; objectToWrite->offsetToBindings = nextOffset;
nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding); nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.count;
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions); quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next) for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = o->runtimeFunctionIndices->at(f->index); *functionsTable++ = o->runtimeFunctionIndices.at(f->index);
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties; char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
for (const Property *p = o->firstProperty(); p; p = p->next) { for (const Property *p = o->firstProperty(); p; p = p->next) {
@ -1492,7 +1500,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
signalPtr += size; signalPtr += size;
} }
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); quint32 *namedObjectInComponentPtr = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
for (int i = 0; i < o->namedObjectsInComponent.count; ++i) {
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
}
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
objectPtr += signalTableSize; objectPtr += signalTableSize;
} }
@ -1509,7 +1522,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
return qmlUnit; return qmlUnit;
} }
char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
{ {
for (const Binding *b = o->firstBinding(); b; b = b->next) { for (const Binding *b = o->firstBinding(); b; b = b->next) {
if (!(b->*(filter))()) if (!(b->*(filter))())
@ -1517,7 +1530,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr); QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b; *bindingToWrite = *b;
if (b->type == QV4::CompiledData::Binding::Type_Script) if (b->type == QV4::CompiledData::Binding::Type_Script)
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices->at(b->value.compiledScriptIndex); bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding); bindingPtr += sizeof(QV4::CompiledData::Binding);
} }
return bindingPtr; return bindingPtr;

View File

@ -170,7 +170,12 @@ class FixedPoolArray
public: public:
int count; int count;
void init(QQmlJS::MemoryPool *pool, const QVector<T> &vector) FixedPoolArray()
: data(0)
, count(0)
{}
void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
{ {
count = vector.count(); count = vector.count();
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
@ -183,6 +188,16 @@ public:
} }
} }
template <typename Container>
void allocate(QQmlJS::MemoryPool *pool, const Container &container)
{
count = container.count();
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
typename Container::ConstIterator it = container.constBegin();
for (int i = 0; i < count; ++i)
new (data + i) T(*it++);
}
const T &at(int index) const { const T &at(int index) const {
Q_ASSERT(index >= 0 && index < count); Q_ASSERT(index >= 0 && index < count);
return data[index]; return data[index];
@ -274,9 +289,11 @@ struct Q_QML_PRIVATE_EXPORT Object
Q_DECLARE_TR_FUNCTIONS(Object) Q_DECLARE_TR_FUNCTIONS(Object)
public: public:
quint32 inheritedTypeNameIndex; quint32 inheritedTypeNameIndex;
quint32 idIndex; quint32 idNameIndex;
int indexOfDefaultPropertyOrAlias : 31; int id;
int defaultPropertyIsAlias : 1; int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias;
int flags;
QV4::CompiledData::Location location; QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty; QV4::CompiledData::Location locationOfIdProperty;
@ -296,7 +313,7 @@ public:
// specified object. Used for declarations inside group properties. // specified object. Used for declarations inside group properties.
Object *declarationsOverride; Object *declarationsOverride;
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation()); void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation); QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
@ -312,7 +329,9 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const; QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions; PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
FixedPoolArray<int> *runtimeFunctionIndices; FixedPoolArray<int> runtimeFunctionIndices;
FixedPoolArray<quint32> namedObjectsInComponent;
private: private:
friend struct IRLoader; friend struct IRLoader;
@ -467,7 +486,7 @@ struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
private: private:
typedef bool (Binding::*BindingFilter)() const; typedef bool (Binding::*BindingFilter)() const;
char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const; char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
}; };
#ifndef V4_BOOTSTRAP #ifndef V4_BOOTSTRAP

View File

@ -65,16 +65,16 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *
bool QQmlTypeCompiler::compile() bool QQmlTypeCompiler::compile()
{ {
compiledData->importCache = new QQmlTypeNameCache; importCache = new QQmlTypeNameCache;
foreach (const QString &ns, typeData->namespaces()) foreach (const QString &ns, typeData->namespaces())
compiledData->importCache->add(ns); importCache->add(ns);
// Add any Composite Singletons that were used to the import cache // Add any Composite Singletons that were used to the import cache
foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons()) foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons())
compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
typeData->imports().populateCache(compiledData->importCache); typeData->imports().populateCache(importCache.data());
const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs(); const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
@ -137,8 +137,6 @@ bool QQmlTypeCompiler::compile()
customParsers.insert(it.key(), customParser); customParsers.insert(it.key(), customParser);
} }
compiledData->propertyCaches.reserve(document->objects.count());
{ {
QQmlPropertyCacheCreator propertyCacheBuilder(this); QQmlPropertyCacheCreator propertyCacheBuilder(this);
if (!propertyCacheBuilder.buildMetaObjects()) if (!propertyCacheBuilder.buildMetaObjects())
@ -174,7 +172,8 @@ bool QQmlTypeCompiler::compile()
// Collect imported scripts // Collect imported scripts
const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts(); const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
compiledData->scripts.reserve(scripts.count()); QVector<QQmlScriptData *> dependentScripts;
dependentScripts.reserve(scripts.count());
for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) { for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex); const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
@ -187,10 +186,10 @@ bool QQmlTypeCompiler::compile()
qualifier = qualifier.mid(lastDotIndex+1); qualifier = qualifier.mid(lastDotIndex+1);
} }
compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData(); QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref(); scriptData->addref();
compiledData->scripts << scriptData; dependentScripts << scriptData;
} }
// Resolve component boundaries and aliases // Resolve component boundaries and aliases
@ -202,6 +201,12 @@ bool QQmlTypeCompiler::compile()
return false; return false;
} }
{
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
if (!deferredAndCustomParserBindingScanner.scanObject())
return false;
}
// Compile JS binding expressions and signal handlers // Compile JS binding expressions and signal handlers
if (!document->javaScriptCompilationUnit) { if (!document->javaScriptCompilationUnit) {
{ {
@ -211,7 +216,7 @@ bool QQmlTypeCompiler::compile()
sss.scan(); sss.scan();
} }
QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable); QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents()) if (!jsCodeGen.generateCodeForComponents())
return false; return false;
@ -236,9 +241,12 @@ bool QQmlTypeCompiler::compile()
document->javaScriptCompilationUnit->data = qmlUnit; document->javaScriptCompilationUnit->data = qmlUnit;
compiledData->compilationUnit = document->javaScriptCompilationUnit; compiledData->compilationUnit = document->javaScriptCompilationUnit;
compiledData->compilationUnit->propertyCaches = m_propertyCaches;
compiledData->compilationUnit->importCache = importCache;
compiledData->compilationUnit->dependentScripts = dependentScripts;
// Add to type registry of composites // Add to type registry of composites
if (compiledData->isCompositeType()) if (compiledData->compilationUnit->isCompositeType())
engine->registerInternalCompositeType(compiledData); engine->registerInternalCompositeType(compiledData);
else { else {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
@ -272,18 +280,18 @@ bool QQmlTypeCompiler::compile()
} }
++objectCount; ++objectCount;
if (typeRef->component) { if (typeRef->component) {
bindingCount += typeRef->component->totalBindingsCount; bindingCount += typeRef->component->compilationUnit->totalBindingsCount;
parserStatusCount += typeRef->component->totalParserStatusCount; parserStatusCount += typeRef->component->compilationUnit->totalParserStatusCount;
objectCount += typeRef->component->totalObjectCount; objectCount += typeRef->component->compilationUnit->totalObjectCount;
} }
} }
} }
compiledData->totalBindingsCount = bindingCount; compiledData->compilationUnit->totalBindingsCount = bindingCount;
compiledData->totalParserStatusCount = parserStatusCount; compiledData->compilationUnit->totalParserStatusCount = parserStatusCount;
compiledData->totalObjectCount = objectCount; compiledData->compilationUnit->totalObjectCount = objectCount;
Q_ASSERT(compiledData->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects)); Q_ASSERT(compiledData->compilationUnit->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects));
return errors.isEmpty(); return errors.isEmpty();
} }
@ -337,28 +345,13 @@ int QQmlTypeCompiler::rootObjectIndex() const
void QQmlTypeCompiler::setPropertyCaches(const QQmlPropertyCacheVector &caches) void QQmlTypeCompiler::setPropertyCaches(const QQmlPropertyCacheVector &caches)
{ {
compiledData->propertyCaches = caches; m_propertyCaches = caches;
Q_ASSERT(caches.count() >= document->indexOfRootObject); Q_ASSERT(caches.count() >= document->indexOfRootObject);
} }
const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const
{ {
return compiledData->propertyCaches; return m_propertyCaches;
}
QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot()
{
return &compiledData->objectIndexToIdForRoot;
}
QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent()
{
return &compiledData->objectIndexToIdPerComponent;
}
QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings()
{
return &compiledData->customParserBindings;
} }
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool() QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
@ -376,11 +369,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
return &document->jsGenerator.stringTable; return &document->jsGenerator.stringTable;
} }
void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject)
{
compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
}
void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData) void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
{ {
compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData; compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData;
@ -1324,11 +1312,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, qmlObjects(typeCompiler->qmlObjects()) , qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex()) , indexOfRootObject(typeCompiler->rootObjectIndex())
, _componentIndex(-1) , _componentIndex(-1)
, _objectIndexToIdInScope(0)
, resolvedTypes(typeCompiler->resolvedTypes()) , resolvedTypes(typeCompiler->resolvedTypes())
, propertyCaches(typeCompiler->propertyCaches()) , propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
, objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent())
{ {
} }
@ -1351,7 +1336,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (targetType->metaObject() == &QQmlComponent::staticMetaObject) if (targetType->metaObject() == &QQmlComponent::staticMetaObject)
continue; continue;
} else if (tr->component) { } else if (tr->component) {
if (tr->component->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject) if (tr->component->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
continue; continue;
} }
@ -1382,6 +1367,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>(); QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString())); syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
syntheticComponent->location = binding->valueLocation; syntheticComponent->location = binding->valueLocation;
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) { if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference; QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
@ -1408,7 +1394,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
binding->value.objectIndex = componentIndex; binding->value.objectIndex = componentIndex;
componentRoots.append(componentIndex); componentRoots.append(componentIndex);
componentBoundaries.append(syntheticBinding->value.objectIndex);
} }
} }
@ -1420,7 +1405,7 @@ bool QQmlComponentAndAliasResolver::resolve()
// on the left hand side is of QQmlComponent type. // on the left hand side is of QQmlComponent type.
const int objCountWithoutSynthesizedComponents = qmlObjects->count(); const int objCountWithoutSynthesizedComponents = qmlObjects->count();
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) { for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
const QmlIR::Object *obj = qmlObjects->at(i); QmlIR::Object *obj = qmlObjects->at(i);
QQmlPropertyCache *cache = propertyCaches.at(i).data(); QQmlPropertyCache *cache = propertyCaches.at(i).data();
if (obj->inheritedTypeNameIndex == 0 && !cache) if (obj->inheritedTypeNameIndex == 0 && !cache)
continue; continue;
@ -1439,7 +1424,7 @@ bool QQmlComponentAndAliasResolver::resolve()
continue; continue;
} }
componentRoots.append(i); obj->flags |= QV4::CompiledData::Object::IsComponent;
if (obj->functionCount() > 0) if (obj->functionCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
@ -1461,20 +1446,20 @@ bool QQmlComponentAndAliasResolver::resolve()
if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object) if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
componentBoundaries.append(rootBinding->value.objectIndex); // We are going to collect ids/aliases and resolve them for the root object as a separate
// last pass.
if (i != indexOfRootObject)
componentRoots.append(i);
} }
std::sort(componentBoundaries.begin(), componentBoundaries.end());
for (int i = 0; i < componentRoots.count(); ++i) { for (int i = 0; i < componentRoots.count(); ++i) {
const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
const QmlIR::Binding *rootBinding = component->firstBinding(); const QmlIR::Binding *rootBinding = component->firstBinding();
_componentIndex = i; _componentIndex = i;
_idToObjectIndex.clear(); _idToObjectIndex.clear();
_objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
_objectsWithAliases.clear(); _objectsWithAliases.clear();
if (!collectIdsAndAliases(rootBinding->value.objectIndex)) if (!collectIdsAndAliases(rootBinding->value.objectIndex))
@ -1482,51 +1467,56 @@ bool QQmlComponentAndAliasResolver::resolve()
if (!resolveAliases()) if (!resolveAliases())
return false; return false;
component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
} }
// Collect ids and aliases for root // Collect ids and aliases for root
_componentIndex = -1; _componentIndex = -1;
_idToObjectIndex.clear(); _idToObjectIndex.clear();
_objectIndexToIdInScope = objectIndexToIdForRoot;
_objectsWithAliases.clear(); _objectsWithAliases.clear();
collectIdsAndAliases(indexOfRootObject); collectIdsAndAliases(indexOfRootObject);
resolveAliases(); resolveAliases();
QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
// Implicit component insertion may have added objects and thus we also need // Implicit component insertion may have added objects and thus we also need
// to extend the symmetric propertyCaches. // to extend the symmetric propertyCaches.
compiler->setPropertyCaches(propertyCaches); compiler->setPropertyCaches(propertyCaches);
compiler->setComponentRoots(componentRoots);
return true; return true;
} }
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{ {
const QmlIR::Object *obj = qmlObjects->at(objectIndex); QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idIndex != 0) { if (obj->idNameIndex != 0) {
if (_idToObjectIndex.contains(obj->idIndex)) { if (_idToObjectIndex.contains(obj->idNameIndex)) {
recordError(obj->locationOfIdProperty, tr("id is not unique")); recordError(obj->locationOfIdProperty, tr("id is not unique"));
return false; return false;
} }
_idToObjectIndex.insert(obj->idIndex, objectIndex); obj->id = _idToObjectIndex.count();
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count()); _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
} }
if (obj->aliasCount() > 0) if (obj->aliasCount() > 0)
_objectsWithAliases.append(objectIndex); _objectsWithAliases.append(objectIndex);
// Stop at Component boundary
if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != compiler->rootObjectIndex())
return true;
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty) && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
continue; continue;
// Stop at Component boundary
if (std::binary_search(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex))
continue;
if (!collectIdsAndAliases(binding->value.objectIndex)) if (!collectIdsAndAliases(binding->value.objectIndex))
return false; return false;
} }
@ -1555,8 +1545,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
} }
Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved)); Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved));
alias->flags |= QV4::CompiledData::Alias::Resolved; alias->flags |= QV4::CompiledData::Alias::Resolved;
Q_ASSERT(_objectIndexToIdInScope->contains(targetObjectIndex)); const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
alias->targetObjectId = _objectIndexToIdInScope->value(targetObjectIndex); Q_ASSERT(targetObject->id >= 0);
alias->targetObjectId = targetObject->id;
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex); const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
@ -1668,6 +1659,126 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
return true; return true;
} }
QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, qmlObjects(typeCompiler->qmlObjects())
, propertyCaches(typeCompiler->propertyCaches())
, customParsers(typeCompiler->customParserCache())
, _seenObjectWithId(false)
{
}
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
return scanObject(compiler->rootObjectIndex());
}
bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
{
QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idNameIndex != 0)
_seenObjectWithId = true;
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
return scanObject(componentBinding->value.objectIndex);
}
QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
if (!propertyCache)
return true;
QString defaultPropertyName;
QQmlPropertyData *defaultProperty = 0;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
QQmlPropertyCache *cache = propertyCache->parent();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
defaultPropertyName = propertyCache->defaultPropertyName();
defaultProperty = propertyCache->defaultProperty();
}
QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
QmlIR::PropertyResolver propertyResolver(propertyCache);
QStringList deferredPropertyNames;
{
const QMetaObject *mo = propertyCache->firstCppMetaObject();
const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
if (namesIndex != -1) {
QMetaClassInfo classInfo = mo->classInfo(namesIndex);
deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
}
}
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
QQmlPropertyData *pd = 0;
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
continue;
}
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
continue;
}
}
if (name.isEmpty()) {
pd = defaultProperty;
name = defaultPropertyName;
} else {
if (name.constData()->isUpper())
continue;
bool notInRevision = false;
pd = propertyResolver.property(name, &notInRevision, QmlIR::PropertyResolver::CheckRevision);
}
bool seenSubObjectWithId = false;
if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
const bool subObjectValid = scanObject(binding->value.objectIndex);
qSwap(_seenObjectWithId, seenSubObjectWithId);
if (!subObjectValid)
return false;
_seenObjectWithId |= seenSubObjectWithId;
}
if (!seenSubObjectWithId
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
}
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
|| binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
continue;
if (!pd) {
if (customParser) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
}
}
}
return true;
}
QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler) : QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate()) , enginePrivate(typeCompiler->enginePrivate())
@ -1675,9 +1786,6 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
, resolvedTypes(*typeCompiler->resolvedTypes()) , resolvedTypes(*typeCompiler->resolvedTypes())
, customParsers(typeCompiler->customParserCache()) , customParsers(typeCompiler->customParserCache())
, propertyCaches(typeCompiler->propertyCaches()) , propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, customParserBindingsPerObject(typeCompiler->customParserBindings())
, _seenObjectWithId(false)
{ {
} }
@ -1686,7 +1794,6 @@ bool QQmlPropertyValidator::validate()
_bindingPropertyDataPerObject.resize(qmlUnit->nObjects); _bindingPropertyDataPerObject.resize(qmlUnit->nObjects);
if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
return false; return false;
compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject);
compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject); compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject);
return true; return true;
} }
@ -1717,10 +1824,8 @@ struct BindingFinder
bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{ {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
if (obj->idIndex != 0)
_seenObjectWithId = true;
if (isComponent(objectIndex)) { if (obj->flags & QV4::CompiledData::Object::IsComponent) {
Q_ASSERT(obj->nBindings == 1); Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable(); const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
@ -1764,9 +1869,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
groupProperties.insert(pos, binding); groupProperties.insert(pos, binding);
} }
QBitArray customParserBindings(obj->nBindings);
QBitArray deferredBindings;
QmlIR::PropertyResolver propertyResolver(propertyCache); QmlIR::PropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName; QString defaultPropertyName;
@ -1790,13 +1892,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) { if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding; customBindings << binding;
customParserBindings.setBit(i);
continue; continue;
} }
} else if (QmlIR::IRBuilder::isSignalPropertyName(name) } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) { && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding; customBindings << binding;
customParserBindings.setBit(i);
continue; continue;
} }
} }
@ -1845,24 +1945,10 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
return false; return false;
} }
bool seenSubObjectWithId = false;
if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)); const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType));
qSwap(_seenObjectWithId, seenSubObjectWithId);
if (!subObjectValid) if (!subObjectValid)
return false; return false;
_seenObjectWithId |= seenSubObjectWithId;
}
if (!seenSubObjectWithId
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
if (deferredBindings.isEmpty())
deferredBindings.resize(obj->nBindings);
deferredBindings.setBit(i);
} }
// Signal handlers were resolved and checked earlier in the signal handler conversion pass. // Signal handlers were resolved and checked earlier in the signal handler conversion pass.
@ -1947,7 +2033,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
} else { } else {
if (customParser) { if (customParser) {
customBindings << binding; customBindings << binding;
customParserBindings.setBit(i);
continue; continue;
} }
if (bindingToDefaultProperty) { if (bindingToDefaultProperty) {
@ -1958,7 +2043,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
} }
} }
if (obj->idIndex) { if (obj->idNameIndex) {
bool notInRevision = false; bool notInRevision = false;
collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision); collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
} }
@ -1972,7 +2057,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
customParser->validator = 0; customParser->validator = 0;
customParser->engine = 0; customParser->engine = 0;
customParser->imports = (QQmlImports*)0; customParser->imports = (QQmlImports*)0;
customParserBindingsPerObject->insert(objectIndex, customParserBindings);
const QList<QQmlError> parserErrors = customParser->errors(); const QList<QQmlError> parserErrors = customParser->errors();
if (!parserErrors.isEmpty()) { if (!parserErrors.isEmpty()) {
foreach (const QQmlError &error, parserErrors) foreach (const QQmlError &error, parserErrors)
@ -1981,9 +2065,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
} }
} }
if (!deferredBindings.isEmpty())
_deferredBindingsPerObject.insert(objectIndex, deferredBindings);
_bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData; _bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData;
return true; return true;
@ -2328,7 +2409,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
} }
} }
return true; return true;
} else if (isComponent(binding->value.objectIndex)) { } else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
return true; return true;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) { } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return true; return true;
@ -2365,7 +2446,6 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen) QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
: QQmlCompilePass(typeCompiler) : QQmlCompilePass(typeCompiler)
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, resolvedTypes(*typeCompiler->resolvedTypes()) , resolvedTypes(*typeCompiler->resolvedTypes())
, customParsers(typeCompiler->customParserCache()) , customParsers(typeCompiler->customParserCache())
, qmlObjects(*typeCompiler->qmlObjects()) , qmlObjects(*typeCompiler->qmlObjects())
@ -2376,46 +2456,40 @@ QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::
bool QQmlJSCodeGenerator::generateCodeForComponents() bool QQmlJSCodeGenerator::generateCodeForComponents()
{ {
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent(); const QVector<quint32> &componentRoots = compiler->componentRoots();
for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd(); for (int i = 0; i < componentRoots.count(); ++i) {
component != end; ++component) { if (!compileComponent(componentRoots.at(i)))
if (!compileComponent(component.key(), component.value()))
return false; return false;
} }
return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot()); return compileComponent(compiler->rootObjectIndex());
} }
bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId) bool QQmlJSCodeGenerator::compileComponent(int contextObject)
{ {
if (isComponent(contextObject)) { const QmlIR::Object *obj = qmlObjects.at(contextObject);
const QmlIR::Object *component = qmlObjects.at(contextObject); if (obj->flags & QV4::CompiledData::Object::IsComponent) {
Q_ASSERT(component->bindingCount() == 1); Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = component->firstBinding(); const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
contextObject = componentBinding->value.objectIndex; contextObject = componentBinding->value.objectIndex;
} }
QmlIR::JSCodeGen::ObjectIdMapping idMapping; QmlIR::JSCodeGen::ObjectIdMapping idMapping;
if (!objectIndexToId.isEmpty()) { idMapping.reserve(obj->namedObjectsInComponent.count);
idMapping.reserve(objectIndexToId.count()); for (int i = 0; i < obj->namedObjectsInComponent.count; ++i) {
const int objectIndex = obj->namedObjectsInComponent.at(i);
QmlIR::JSCodeGen::IdMapping m;
const QmlIR::Object *obj = qmlObjects.at(objectIndex);
m.name = stringAt(obj->idNameIndex);
m.idIndex = obj->id;
m.type = propertyCaches.at(objectIndex).data();
for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd(); QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
idIt != end; ++idIt) { if (tref && tref->isFullyDynamicType)
m.type = 0;
const int objectIndex = idIt.key(); idMapping << m;
QmlIR::JSCodeGen::IdMapping m;
const QmlIR::Object *obj = qmlObjects.at(objectIndex);
m.name = stringAt(obj->idIndex);
m.idIndex = idIt.value();
m.type = propertyCaches.at(objectIndex).data();
QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
if (tref && tref->isFullyDynamicType)
m.type = 0;
idMapping << m;
}
} }
v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject).data()); v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject).data());
@ -2427,10 +2501,10 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, i
bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex) bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
{ {
if (isComponent(objectIndex)) QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->flags & QV4::CompiledData::Object::IsComponent)
return true; return true;
QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->functionsAndExpressions->count > 0) { if (object->functionsAndExpressions->count > 0) {
QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex).data(); QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex).data();
v4CodeGen->beginObjectScope(scopeObject); v4CodeGen->beginObjectScope(scopeObject);
@ -2451,8 +2525,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
} }
QQmlJS::MemoryPool *pool = compiler->memoryPool(); QQmlJS::MemoryPool *pool = compiler->memoryPool();
object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >(); object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
} }
for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) { for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
@ -2551,7 +2624,7 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding
if (binding->type != QV4::CompiledData::Binding::Type_Script) if (binding->type != QV4::CompiledData::Binding::Type_Script)
continue; continue;
const int irFunctionIndex = obj->runtimeFunctionIndices->at(binding->value.compiledScriptIndex); const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
if (simplifyBinding(irFunction, binding)) { if (simplifyBinding(irFunction, binding)) {
irFunctionsToRemove.append(irFunctionIndex); irFunctionsToRemove.append(irFunctionIndex);
@ -2838,10 +2911,8 @@ void QQmlIRFunctionCleanser::clean()
} }
foreach (QmlIR::Object *obj, *compiler->qmlObjects()) { foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
if (!obj->runtimeFunctionIndices) for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
continue; obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i)
(*obj->runtimeFunctionIndices)[i] = newFunctionIndices[obj->runtimeFunctionIndices->at(i)];
} }
} }

View File

@ -101,13 +101,11 @@ public:
int rootObjectIndex() const; int rootObjectIndex() const;
void setPropertyCaches(const QQmlPropertyCacheVector &caches); void setPropertyCaches(const QQmlPropertyCacheVector &caches);
const QQmlPropertyCacheVector &propertyCaches() const; const QQmlPropertyCacheVector &propertyCaches() const;
QHash<int, int> *objectIndexToIdForRoot(); void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent(); const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QHash<int, QBitArray> *customParserBindings();
QQmlJS::MemoryPool *memoryPool(); QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string); QStringRef newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const; const QV4::Compiler::StringTableGenerator *stringPool() const;
void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData); void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; } const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
@ -119,9 +117,14 @@ private:
QQmlEnginePrivate *engine; QQmlEnginePrivate *engine;
QQmlCompiledData *compiledData; QQmlCompiledData *compiledData;
QQmlTypeData *typeData; QQmlTypeData *typeData;
QQmlRefPointer<QQmlTypeNameCache> importCache;
QmlIR::Document *document; QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex) // index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers; QHash<int, QQmlCustomParser*> customParsers;
// index in first hash is component index, vector inside contains object indices of objects with id property
QVector<quint32> m_componentRoots;
QQmlPropertyCacheVector m_propertyCaches;
}; };
struct QQmlCompilePass struct QQmlCompilePass
@ -268,20 +271,31 @@ protected:
const int indexOfRootObject; const int indexOfRootObject;
// indices of the objects that are actually Component {} // indices of the objects that are actually Component {}
QVector<int> componentRoots; QVector<quint32> componentRoots;
// indices of objects that are the beginning of a new component
// scope. This is sorted and used for binary search.
QVector<quint32> componentBoundaries;
int _componentIndex; int _componentIndex;
QHash<int, int> _idToObjectIndex; QHash<int, int> _idToObjectIndex;
QHash<int, int> *_objectIndexToIdInScope;
QList<int> _objectsWithAliases; QList<int> _objectsWithAliases;
QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes; QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
QQmlPropertyCacheVector propertyCaches; QQmlPropertyCacheVector propertyCaches;
QHash<int, int> *objectIndexToIdForRoot; };
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
{
public:
QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
bool scanObject();
private:
bool scanObject(int objectIndex);
QList<QmlIR::Object*> *qmlObjects;
QQmlPropertyCacheVector propertyCaches;
const QHash<int, QQmlCustomParser*> &customParsers;
bool _seenObjectWithId;
}; };
class QQmlPropertyValidator : public QQmlCompilePass class QQmlPropertyValidator : public QQmlCompilePass
@ -300,8 +314,6 @@ private:
bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const; bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const; bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool canCoerce(int to, QQmlPropertyCache *fromMo) const; bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
QQmlEnginePrivate *enginePrivate; QQmlEnginePrivate *enginePrivate;
@ -309,12 +321,8 @@ private:
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes; const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers; const QHash<int, QQmlCustomParser*> &customParsers;
const QQmlPropertyCacheVector &propertyCaches; const QQmlPropertyCacheVector &propertyCaches;
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, QBitArray> *customParserBindingsPerObject;
// collected state variables, essentially write-only // collected state variables, essentially write-only
mutable QHash<int, QBitArray> _deferredBindingsPerObject;
mutable bool _seenObjectWithId;
mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject; mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject;
}; };
@ -327,12 +335,9 @@ public:
bool generateCodeForComponents(); bool generateCodeForComponents();
private: private:
bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId); bool compileComponent(int componentRoot);
bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex); bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes; const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers; const QHash<int, QQmlCustomParser*> &customParsers;
const QList<QmlIR::Object*> &qmlObjects; const QList<QmlIR::Object*> &qmlObjects;

View File

@ -47,6 +47,7 @@
#include <private/qv4lookup_p.h> #include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h> #include <private/qv4regexpobject_p.h>
#include <private/qqmlpropertycache_p.h> #include <private/qqmlpropertycache_p.h>
#include <private/qqmltypeloader_p.h>
#endif #endif
#include <private/qqmlirbuilder_p.h> #include <private/qqmlirbuilder_p.h>
#include <QCoreApplication> #include <QCoreApplication>
@ -67,6 +68,9 @@ CompilationUnit::CompilationUnit()
, runtimeLookups(0) , runtimeLookups(0)
, runtimeRegularExpressions(0) , runtimeRegularExpressions(0)
, runtimeClasses(0) , runtimeClasses(0)
, totalBindingsCount(0)
, totalParserStatusCount(0)
, totalObjectCount(0)
{} {}
CompilationUnit::~CompilationUnit() CompilationUnit::~CompilationUnit()
@ -165,6 +169,18 @@ void CompilationUnit::unlink()
{ {
if (engine) if (engine)
engine->compilationUnits.erase(engine->compilationUnits.find(this)); engine->compilationUnits.erase(engine->compilationUnits.find(this));
for (int ii = 0; ii < propertyCaches.count(); ++ii)
if (propertyCaches.at(ii).data())
propertyCaches.at(ii)->release();
propertyCaches.clear();
for (int ii = 0; ii < dependentScripts.count(); ++ii)
dependentScripts.at(ii)->release();
dependentScripts.clear();
importCache = nullptr;
engine = 0; engine = 0;
free(runtimeStrings); free(runtimeStrings);
runtimeStrings = 0; runtimeStrings = 0;
@ -189,6 +205,22 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
} }
} }
IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
{
auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
if (it == namedObjectsPerComponentCache.end()) {
IdentifierHash<int> namedObjectCache(engine);
const CompiledData::Object *component = data->objectAt(componentObjectIndex);
const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
}
it = namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
return *it;
}
#endif // V4_BOOTSTRAP #endif // V4_BOOTSTRAP
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)

View File

@ -60,11 +60,22 @@
#include <private/qv4executableallocator_p.h> #include <private/qv4executableallocator_p.h>
#include <private/qqmlrefcount_p.h> #include <private/qqmlrefcount_p.h>
#include <private/qqmlnullablevalue_p.h> #include <private/qqmlnullablevalue_p.h>
#include <private/qv4identifier_p.h>
#include <private/qflagpointer_p.h>
#ifndef V4_BOOTSTRAP
#include <private/qqmltypenamecache_p.h>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQmlPropertyCache; class QQmlPropertyCache;
class QQmlPropertyData; class QQmlPropertyData;
class QQmlTypeNameCache;
class QQmlScriptData;
// The vector is indexed by QV4::CompiledData::Object index and the flag
// indicates whether instantiation of the object requires a VME meta-object.
typedef QVector<QFlagPointer<QQmlPropertyCache>> QQmlPropertyCacheVector;
namespace QmlIR { namespace QmlIR {
struct Document; struct Document;
@ -234,7 +245,9 @@ struct Q_QML_PRIVATE_EXPORT Binding
InitializerForReadOnlyDeclaration = 0x8, InitializerForReadOnlyDeclaration = 0x8,
IsResolvedEnum = 0x10, IsResolvedEnum = 0x10,
IsListItem = 0x20, IsListItem = 0x20,
IsBindingToAlias = 0x40 IsBindingToAlias = 0x40,
IsDeferredBinding = 0x80,
IsCustomParserBinding = 0x100,
}; };
quint32 flags : 16; quint32 flags : 16;
@ -391,13 +404,22 @@ struct Alias {
struct Object struct Object
{ {
enum Flags {
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
HasCustomParserBindings = 0x4
};
// Depending on the use, this may be the type name to instantiate before instantiating this // Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties // object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type. // it will be the name of the attached type.
quint32 inheritedTypeNameIndex; quint32 inheritedTypeNameIndex;
quint32 idIndex; quint32 idNameIndex;
qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object qint32 id : 16;
qint32 flags : 15;
quint32 defaultPropertyIsAlias : 1; quint32 defaultPropertyIsAlias : 1;
qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint32 nFunctions; quint32 nFunctions;
quint32 offsetToFunctions; quint32 offsetToFunctions;
quint32 nProperties; quint32 nProperties;
@ -408,6 +430,8 @@ struct Object
quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
quint32 nBindings; quint32 nBindings;
quint32 offsetToBindings; quint32 offsetToBindings;
quint32 nNamedObjectsInComponent;
quint32 offsetToNamedObjectsInComponent;
Location location; Location location;
Location locationOfIdProperty; Location locationOfIdProperty;
// Function[] // Function[]
@ -415,7 +439,7 @@ struct Object
// Signal[] // Signal[]
// Binding[] // Binding[]
static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings) static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent)
{ {
return ( sizeof(Object) return ( sizeof(Object)
+ nFunctions * sizeof(quint32) + nFunctions * sizeof(quint32)
@ -423,6 +447,7 @@ struct Object
+ nAliases * sizeof(Alias) + nAliases * sizeof(Alias)
+ nSignals * sizeof(quint32) + nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding) + nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
+ 0x7 + 0x7
) & ~0x7; ) & ~0x7;
} }
@ -453,6 +478,11 @@ struct Object
const uint offset = offsetTable[idx]; const uint offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset); return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
} }
const quint32 *namedObjectsInComponentTable() const
{
return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
}; };
struct Import struct Import
@ -641,11 +671,29 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QVector<QV4::Function *> runtimeFunctions; QVector<QV4::Function *> runtimeFunctions;
mutable QQmlNullableValue<QUrl> m_url; mutable QQmlNullableValue<QUrl> m_url;
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject).data(); }
bool isCompositeType() const { return propertyCaches.at(data->indexOfRootObject).flag(); }
QQmlRefPointer<QQmlTypeNameCache> importCache;
// index is object index. This allows fast access to the // index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive // property data when initializing bindings, avoiding expensive
// lookups by string (property name). // lookups by string (property name).
QVector<BindingPropertyData> bindingPropertyDataPerObject; QVector<BindingPropertyData> bindingPropertyDataPerObject;
// mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
// this is initialized on-demand by QQmlContextData
QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache;
IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex);
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
int totalObjectCount; // Number of objects explicitly instantiated
QVector<QQmlScriptData *> dependentScripts;
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink(); void unlink();

View File

@ -71,13 +71,13 @@ public:
virtual ~QQmlAbstractProfilerAdapter() {} virtual ~QQmlAbstractProfilerAdapter() {}
void setService(QQmlProfilerService *new_service) { service = new_service; } void setService(QQmlProfilerService *new_service) { service = new_service; }
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0; virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) = 0;
void startProfiling(quint64 features); void startProfiling(quint64 features);
void stopProfiling(); void stopProfiling();
void reportData() { emit dataRequested(); } void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
void stopWaiting() { waiting = false; } void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; } void startWaiting() { waiting = true; }
@ -94,7 +94,7 @@ signals:
void profilingDisabled(); void profilingDisabled();
void profilingDisabledWhileWaiting(); void profilingDisabledWhileWaiting();
void dataRequested(); void dataRequested(bool trackLocations);
void referenceTimeKnown(const QElapsedTimer &timer); void referenceTimeKnown(const QElapsedTimer &timer);
protected: protected:

View File

@ -59,19 +59,21 @@ void QQmlProfiler::startProfiling(quint64 features)
void QQmlProfiler::stopProfiling() void QQmlProfiler::stopProfiling()
{ {
featuresEnabled = false; featuresEnabled = false;
reportData(); reportData(true);
m_locations.clear();
} }
void QQmlProfiler::reportData() void QQmlProfiler::reportData(bool trackLocations)
{ {
LocationHash resolved; LocationHash resolved;
resolved.reserve(m_locations.size()); resolved.reserve(m_locations.size());
for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it) for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
resolved.insert(it.key(), it.value()); if (!trackLocations || !it->sent) {
resolved.insert(it.key(), it.value());
// This unrefs all the objects. We have to make sure we do this in the GUI thread. Also, it's if (trackLocations)
// a good idea to release the memory before creating the packets to be sent. it->sent = true;
m_locations.clear(); }
}
QVector<QQmlProfilerData> data; QVector<QQmlProfilerData> data;
data.swap(m_data); data.swap(m_data);

View File

@ -146,26 +146,27 @@ public:
// Unfortunately we have to resolve the locations right away because the QML context might not // Unfortunately we have to resolve the locations right away because the QML context might not
// be available anymore when we send the data. // be available anymore when we send the data.
struct RefLocation : public Location { struct RefLocation : public Location {
RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr) RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false)
{} {}
RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) : RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) :
Location(function->sourceLocation()), locationType(Binding), Location(function->sourceLocation()), locationType(Binding),
ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt) ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false)
{} {}
RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj, RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
const QString &type) : const QString &type) :
Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
locationType(Creating), ref(ref) locationType(Creating), ref(ref), sent(false)
{} {}
RefLocation(QQmlBoundSignalExpression *ref) : RefLocation(QQmlBoundSignalExpression *ref) :
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref) Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref), sent(false)
{} {}
RefLocation(QQmlDataBlob *ref) : RefLocation(QQmlDataBlob *ref) :
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref) Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref),
sent(false)
{} {}
bool isValid() const bool isValid() const
@ -175,6 +176,7 @@ public:
RangeType locationType; RangeType locationType;
QQmlRefPointer<QQmlRefCount> ref; QQmlRefPointer<QQmlRefCount> ref;
bool sent;
}; };
typedef QHash<quintptr, Location> LocationHash; typedef QHash<quintptr, Location> LocationHash;
@ -217,11 +219,6 @@ public:
location = RefLocation(expression); location = RefLocation(expression);
} }
void startCreating()
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating));
}
void startCreating(const QV4::CompiledData::Object *obj) void startCreating(const QV4::CompiledData::Object *obj)
{ {
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
@ -233,10 +230,6 @@ public:
const QUrl &url, const QString &type) const QUrl &url, const QString &type)
{ {
quintptr locationId(id(obj)); quintptr locationId(id(obj));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeLocation | 1 << RangeData),
Creating, locationId));
RefLocation &location = m_locations[locationId]; RefLocation &location = m_locations[locationId];
if (!location.isValid()) if (!location.isValid())
location = RefLocation(ref, url, obj, type); location = RefLocation(ref, url, obj, type);
@ -261,7 +254,7 @@ public:
public slots: public slots:
void startProfiling(quint64 features); void startProfiling(quint64 features);
void stopProfiling(); void stopProfiling();
void reportData(); void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; } void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals: signals:
@ -363,9 +356,10 @@ private:
class QQmlObjectCreationProfiler { class QQmlObjectCreationProfiler {
public: public:
QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler) QQmlObjectCreationProfiler(QQmlProfiler *profiler, const QV4::CompiledData::Object *obj)
: profiler(profiler)
{ {
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating()); Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating(obj));
} }
~QQmlObjectCreationProfiler() ~QQmlObjectCreationProfiler()

View File

@ -64,12 +64,33 @@ IdentifierHashData::IdentifierHashData(int numBits)
memset(entries, 0, alloc*sizeof(IdentifierHashEntry)); memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
} }
IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
: size(other->size)
, numBits(other->numBits)
, identifierTable(other->identifierTable)
{
refCount.store(1);
alloc = other->alloc;
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
}
IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine) IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine)
{ {
d = new IdentifierHashData(3); d = new IdentifierHashData(3);
d->identifierTable = engine->identifierTable; d->identifierTable = engine->identifierTable;
} }
void IdentifierHashBase::detach()
{
if (!d || d->refCount == 1)
return;
IdentifierHashData *newData = new IdentifierHashData(d);
if (d && !d->refCount.deref())
delete d;
d = newData;
}
IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier) IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier)
{ {

View File

@ -85,6 +85,7 @@ struct IdentifierHashEntry {
struct IdentifierHashData struct IdentifierHashData
{ {
IdentifierHashData(int numBits); IdentifierHashData(int numBits);
explicit IdentifierHashData(IdentifierHashData *other);
~IdentifierHashData() { ~IdentifierHashData() {
free(entries); free(entries);
} }
@ -115,6 +116,8 @@ struct IdentifierHashBase
bool contains(const QString &str) const; bool contains(const QString &str) const;
bool contains(String *str) const; bool contains(String *str) const;
void detach();
protected: protected:
IdentifierHashEntry *addEntry(const Identifier *i); IdentifierHashEntry *addEntry(const Identifier *i);
const IdentifierHashEntry *lookup(const Identifier *identifier) const; const IdentifierHashEntry *lookup(const Identifier *identifier) const;
@ -141,6 +144,7 @@ struct IdentifierHash : public IdentifierHashBase
} }
void add(const QString &str, const T &value); void add(const QString &str, const T &value);
void add(Heap::String *str, const T &value);
inline T value(const QString &str) const; inline T value(const QString &str) const;
inline T value(String *str) const; inline T value(String *str) const;
@ -197,6 +201,13 @@ void IdentifierHash<T>::add(const QString &str, const T &value)
e->value = value; e->value = value;
} }
template<typename T>
void IdentifierHash<T>::add(Heap::String *str, const T &value)
{
IdentifierHashEntry *e = addEntry(toIdentifier(str));
e->value = value;
}
template<typename T> template<typename T>
inline T IdentifierHash<T>::value(const QString &str) const inline T IdentifierHash<T>::value(const QString &str) const
{ {
@ -223,7 +234,6 @@ QString IdentifierHash<T>::findId(T value) const
return QString(); return QString();
} }
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -78,7 +78,8 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(
void Profiler::stopProfiling() void Profiler::stopProfiling()
{ {
featuresEnabled = 0; featuresEnabled = 0;
reportData(); reportData(true);
m_sentLocations.clear();
} }
bool operator<(const FunctionCall &call1, const FunctionCall &call2) bool operator<(const FunctionCall &call1, const FunctionCall &call2)
@ -88,7 +89,7 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
(call1.m_end == call2.m_end && call1.m_function < call2.m_function))); (call1.m_end == call2.m_end && call1.m_function < call2.m_function)));
} }
void Profiler::reportData() void Profiler::reportData(bool trackLocations)
{ {
std::sort(m_data.begin(), m_data.end()); std::sort(m_data.begin(), m_data.end());
QVector<FunctionCallProperties> properties; QVector<FunctionCallProperties> properties;
@ -97,9 +98,15 @@ void Profiler::reportData()
foreach (const FunctionCall &call, m_data) { foreach (const FunctionCall &call, m_data) {
properties.append(call.properties()); properties.append(call.properties());
FunctionLocation &location = locations[properties.constLast().id]; Function *function = call.function();
if (!location.isValid()) SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
location = call.resolveLocation(); if (!trackLocations || !marker.isValid()) {
FunctionLocation &location = locations[properties.constLast().id];
if (!location.isValid())
location = call.resolveLocation();
if (trackLocations)
marker.setFunction(function);
}
} }
emit dataReady(locations, properties, m_memory_data); emit dataReady(locations, properties, m_memory_data);

View File

@ -134,6 +134,11 @@ public:
return *this; return *this;
} }
Function *function() const
{
return m_function;
}
FunctionLocation resolveLocation() const; FunctionLocation resolveLocation() const;
FunctionCallProperties properties() const; FunctionCallProperties properties() const;
@ -165,6 +170,46 @@ class Q_QML_EXPORT Profiler : public QObject {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(Profiler) Q_DISABLE_COPY(Profiler)
public: public:
struct SentMarker {
SentMarker() : m_function(nullptr) {}
SentMarker(const SentMarker &other) : m_function(other.m_function)
{
if (m_function)
m_function->compilationUnit->addref();
}
~SentMarker()
{
if (m_function)
m_function->compilationUnit->release();
}
SentMarker &operator=(const SentMarker &other)
{
if (&other != this) {
if (m_function)
m_function->compilationUnit->release();
m_function = other.m_function;
m_function->compilationUnit->addref();
}
return *this;
}
void setFunction(Function *function)
{
Q_ASSERT(m_function == nullptr);
m_function = function;
m_function->compilationUnit->addref();
}
bool isValid() const
{ return m_function != nullptr; }
private:
Function *m_function;
};
Profiler(QV4::ExecutionEngine *engine); Profiler(QV4::ExecutionEngine *engine);
size_t trackAlloc(size_t size, MemoryType type) size_t trackAlloc(size_t size, MemoryType type)
@ -186,7 +231,7 @@ public:
public slots: public slots:
void stopProfiling(); void stopProfiling();
void startProfiling(quint64 features); void startProfiling(quint64 features);
void reportData(); void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; } void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals: signals:
@ -199,6 +244,7 @@ private:
QElapsedTimer m_timer; QElapsedTimer m_timer;
QVector<FunctionCall> m_data; QVector<FunctionCall> m_data;
QVector<MemoryAllocationProperties> m_memory_data; QVector<MemoryAllocationProperties> m_memory_data;
QHash<quintptr, SentMarker> m_sentLocations;
friend class FunctionCallProfiler; friend class FunctionCallProfiler;
}; };
@ -237,6 +283,7 @@ Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_MOVABLE_TYPE);
QT_END_NAMESPACE QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash) Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)

View File

@ -68,7 +68,7 @@
#include <pthread_np.h> #include <pthread_np.h>
#endif #endif
#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT (std::size_t)128*1024 #define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT std::size_t(128 * 1024)
using namespace WTF; using namespace WTF;
@ -108,29 +108,20 @@ using namespace QV4;
struct MemoryManager::Data struct MemoryManager::Data
{ {
const size_t pageSize;
struct ChunkHeader { struct ChunkHeader {
Heap::Base freeItems; Heap::Base freeItems;
ChunkHeader *nextNonFull; ChunkHeader *nextNonFull;
char *itemStart; char *itemStart;
char *itemEnd; char *itemEnd;
int itemSize; unsigned itemSize;
}; };
bool gcBlocked;
bool aggressiveGC;
bool gcStats;
ExecutionEngine *engine; ExecutionEngine *engine;
enum { MaxItemSize = 512 };
ChunkHeader *nonFullChunks[MaxItemSize/16];
uint nChunks[MaxItemSize/16];
uint availableItems[MaxItemSize/16];
uint allocCount[MaxItemSize/16];
int totalItems;
int totalAlloc;
uint maxShift;
std::size_t maxChunkSize; std::size_t maxChunkSize;
QVector<PageAllocation> heapChunks; std::vector<PageAllocation> heapChunks;
std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit; std::size_t unmanagedHeapSizeGCLimit;
@ -147,24 +138,39 @@ struct MemoryManager::Data
LargeItem *largeItems; LargeItem *largeItems;
std::size_t totalLargeItemsAllocated; std::size_t totalLargeItemsAllocated;
enum { MaxItemSize = 512 };
ChunkHeader *nonFullChunks[MaxItemSize/16];
uint nChunks[MaxItemSize/16];
uint availableItems[MaxItemSize/16];
uint allocCount[MaxItemSize/16];
int totalItems;
int totalAlloc;
uint maxShift;
bool gcBlocked;
bool aggressiveGC;
bool gcStats;
bool unused; // suppress padding warning
// statistics: // statistics:
#ifdef DETAILED_MM_STATS #ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters; QVector<unsigned> allocSizeCounters;
#endif // DETAILED_MM_STATS #endif // DETAILED_MM_STATS
Data() Data()
: gcBlocked(false) : pageSize(WTF::pageSize())
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
, gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
, engine(0) , engine(0)
, totalItems(0)
, totalAlloc(0)
, maxShift(maxShiftValue())
, maxChunkSize(maxChunkSizeValue()) , maxChunkSize(maxChunkSizeValue())
, unmanagedHeapSize(0) , unmanagedHeapSize(0)
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
, largeItems(0) , largeItems(0)
, totalLargeItemsAllocated(0) , totalLargeItemsAllocated(0)
, totalItems(0)
, totalAlloc(0)
, maxShift(maxShiftValue())
, gcBlocked(false)
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
, gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
{ {
memset(nonFullChunks, 0, sizeof(nonFullChunks)); memset(nonFullChunks, 0, sizeof(nonFullChunks));
memset(nChunks, 0, sizeof(nChunks)); memset(nChunks, 0, sizeof(nChunks));
@ -174,7 +180,7 @@ struct MemoryManager::Data
~Data() ~Data()
{ {
for (QVector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) { for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage); Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage);
i->deallocate(); i->deallocate();
} }
@ -198,7 +204,7 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
// qDebug("chunk @ %p, in use: %s, mark bit: %s", // qDebug("chunk @ %p, in use: %s, mark bit: %s",
// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false")); // item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
Q_ASSERT((qintptr) item % 16 == 0); Q_ASSERT(qintptr(item) % 16 == 0);
if (m->isMarked()) { if (m->isMarked()) {
Q_ASSERT(m->inUse()); Q_ASSERT(m->inUse());
@ -324,14 +330,15 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
if (shift > m_d->maxShift) if (shift > m_d->maxShift)
shift = m_d->maxShift; shift = m_d->maxShift;
std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift); std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize); allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
PageAllocation allocation = PageAllocation::allocate( PageAllocation allocation = PageAllocation::allocate(
Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage), Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage),
OSAllocator::JSGCHeapPages); OSAllocator::JSGCHeapPages);
m_d->heapChunks.append(allocation); m_d->heapChunks.push_back(allocation);
header = reinterpret_cast<Data::ChunkHeader *>(allocation.base()); header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
header->itemSize = int(size); Q_ASSERT(size <= UINT_MAX);
header->itemSize = unsigned(size);
header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader)); header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize; header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
@ -347,7 +354,8 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
} }
last->setNextFree(0); last->setNextFree(0);
m = header->freeItems.nextFree(); m = header->freeItems.nextFree();
const size_t increase = (header->itemEnd - header->itemStart) / header->itemSize; Q_ASSERT(header->itemEnd >= header->itemStart);
const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
m_d->availableItems[pos] += uint(increase); m_d->availableItems[pos] += uint(increase);
m_d->totalItems += int(increase); m_d->totalItems += int(increase);
#ifdef V4_USE_VALGRIND #ifdef V4_USE_VALGRIND
@ -465,22 +473,23 @@ void MemoryManager::sweep(bool lastSweep)
} }
} }
bool *chunkIsEmpty = (bool *)alloca(m_d->heapChunks.size() * sizeof(bool)); bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool)));
uint itemsInUse[MemoryManager::Data::MaxItemSize/16]; uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
memset(itemsInUse, 0, sizeof(itemsInUse)); memset(itemsInUse, 0, sizeof(itemsInUse));
memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks)); memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
for (int i = 0; i < m_d->heapChunks.size(); ++i) { for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base()); Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize); chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize);
} }
QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin(); std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
for (int i = 0; i < m_d->heapChunks.size(); ++i) { for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
Q_ASSERT(chunkIter != m_d->heapChunks.end()); Q_ASSERT(chunkIter != m_d->heapChunks.end());
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base()); Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
const size_t pos = header->itemSize >> 4; const size_t pos = header->itemSize >> 4;
const size_t decrease = (header->itemEnd - header->itemStart) / header->itemSize; Q_ASSERT(header->itemEnd >= header->itemStart);
const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
// Release that chunk if it could have been spared since the last GC run without any difference. // Release that chunk if it could have been spared since the last GC run without any difference.
if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) { if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
@ -561,7 +570,7 @@ void MemoryManager::runGC()
t.restart(); t.restart();
const size_t usedBefore = getUsedMem(); const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem(); const size_t largeItemsBefore = getLargeItemsMem();
int chunksBefore = m_d->heapChunks.size(); size_t chunksBefore = m_d->heapChunks.size();
sweep(); sweep();
const size_t usedAfter = getUsedMem(); const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem(); const size_t largeItemsAfter = getLargeItemsMem();
@ -589,11 +598,11 @@ void MemoryManager::runGC()
size_t MemoryManager::getUsedMem() const size_t MemoryManager::getUsedMem() const
{ {
size_t usedMem = 0; size_t usedMem = 0;
for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) { for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base()); Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
Heap::Base *m = reinterpret_cast<Heap::Base *>(item); Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
Q_ASSERT((qintptr) item % 16 == 0); Q_ASSERT(qintptr(item) % 16 == 0);
if (m->inUse()) if (m->inUse())
usedMem += header->itemSize; usedMem += header->itemSize;
} }
@ -604,7 +613,7 @@ size_t MemoryManager::getUsedMem() const
size_t MemoryManager::getAllocatedMem() const size_t MemoryManager::getAllocatedMem() const
{ {
size_t total = 0; size_t total = 0;
for (int i = 0; i < m_d->heapChunks.size(); ++i) for (size_t i = 0; i < m_d->heapChunks.size(); ++i)
total += m_d->heapChunks.at(i).size(); total += m_d->heapChunks.at(i).size();
return total; return total;
} }

View File

@ -55,8 +55,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false), : engine(engine), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false)
totalBindingsCount(0), totalParserStatusCount(0)
{ {
Q_ASSERT(engine); Q_ASSERT(engine);
} }
@ -85,16 +84,6 @@ QQmlCompiledData::~QQmlCompiledData()
} }
qDeleteAll(resolvedTypes); qDeleteAll(resolvedTypes);
resolvedTypes.clear(); resolvedTypes.clear();
for (int ii = 0; ii < scripts.count(); ++ii)
scripts.at(ii)->release();
if (importCache)
importCache->release();
for (int ii = 0; ii < propertyCaches.count(); ++ii)
if (propertyCaches.at(ii).data())
propertyCaches.at(ii)->release();
} }
void QQmlCompiledData::clear() void QQmlCompiledData::clear()
@ -109,7 +98,7 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const
if (type) if (type)
return typePropertyCache; return typePropertyCache;
else else
return component->rootPropertyCache(); return component->compilationUnit->rootPropertyCache();
} }
/*! /*!
@ -124,7 +113,7 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngi
typePropertyCache->addref(); typePropertyCache->addref();
return typePropertyCache; return typePropertyCache;
} else { } else {
return component->rootPropertyCache(); return component->compilationUnit->rootPropertyCache();
} }
} }
@ -146,7 +135,7 @@ void QQmlCompiledData::TypeReference::doDynamicTypeCheck()
else if (type) else if (type)
mo = type->metaObject(); mo = type->metaObject();
else if (component) else if (component)
mo = component->rootPropertyCache()->firstCppMetaObject(); mo = component->compilationUnit->rootPropertyCache()->firstCppMetaObject();
isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo); isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
} }

View File

@ -80,10 +80,6 @@ class QQmlComponent;
class QQmlContext; class QQmlContext;
class QQmlContextData; class QQmlContextData;
// The vector is indexed by QV4::CompiledData::Object index and the flag
// indicates whether instantiation of the object requires a VME meta-object.
typedef QVector<QFlagPointer<QQmlPropertyCache>> QQmlPropertyCacheVector;
// ### Merge with QV4::CompiledData::CompilationUnit // ### Merge with QV4::CompiledData::CompilationUnit
class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
{ {
@ -93,8 +89,6 @@ public:
QQmlEngine *engine; QQmlEngine *engine;
QQmlTypeNameCache *importCache;
int metaTypeId; int metaTypeId;
int listMetaTypeId; int listMetaTypeId;
bool isRegisteredWithEngine; bool isRegisteredWithEngine;
@ -126,23 +120,7 @@ public:
// map from name index // map from name index
QHash<int, TypeReference*> resolvedTypes; QHash<int, TypeReference*> resolvedTypes;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(compilationUnit->data->indexOfRootObject).data(); }
QQmlPropertyCacheVector propertyCaches;
QList<QQmlScriptData *> scripts;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
// index in first hash is component index, hash inside maps from object index in that scope to integer id
QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, int> objectIndexToIdForRoot;
// hash key is object index, value is indicies of bindings covered by custom parser
QHash<int, QBitArray> customParserBindings;
QHash<int, QBitArray> deferredBindingsPerObject; // index is object index
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
int totalObjectCount; // Number of objects explicitly instantiated
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return propertyCaches.at(compilationUnit->data->indexOfRootObject).flag(); }
bool isInitialized() const { return hasEngine(); } bool isInitialized() const { return hasEngine(); }
void initialize(QQmlEngine *); void initialize(QQmlEngine *);

View File

@ -310,7 +310,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
} }
} }
QV4::IdentifierHash<int> &properties = data->propertyNames(); QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
int idx = properties.value(name); int idx = properties.value(name);
if (idx == -1) { if (idx == -1) {
properties.add(name, data->idValueCount + d->propertyValues.count()); properties.add(name, data->idValueCount + d->propertyValues.count());
@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
return; return;
} }
QV4::IdentifierHash<int> &properties = data->propertyNames(); QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
int idx = properties.value(name); int idx = properties.value(name);
if (idx == -1) { if (idx == -1) {
@ -523,7 +523,7 @@ QQmlContextData::QQmlContextData()
QQmlContextData::QQmlContextData(QQmlContext *ctxt) QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
publicContext(ctxt), activeVMEData(0), publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1),
contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0) componentAttached(0)
@ -760,15 +760,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj)
idValues[idx].context = this; idValues[idx].context = this;
} }
void QQmlContextData::setIdPropertyData(const QHash<int, int> &data)
{
Q_ASSERT(objectIndexToId.isEmpty());
objectIndexToId = data;
Q_ASSERT(propertyNameCache.isEmpty());
idValueCount = data.count();
idValues = new ContextGuard[idValueCount];
}
QString QQmlContextData::findObjectId(const QObject *obj) const QString QQmlContextData::findObjectId(const QObject *obj) const
{ {
const QV4::IdentifierHash<int> &properties = propertyNames(); const QV4::IdentifierHash<int> &properties = propertyNames();
@ -804,21 +795,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
return QQmlContextPrivate::get(asQQmlContext()); return QQmlContextPrivate::get(asQQmlContext());
} }
QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex)
{
typeCompilationUnit = unit;
componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex;
Q_ASSERT(!idValues);
idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
idValues = new ContextGuard[idValueCount];
}
const QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const
{ {
if (propertyNameCache.isEmpty()) { if (propertyNameCache.isEmpty()) {
propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle())); if (typeCompilationUnit)
for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend(); propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
it != end; ++it) { else
const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key()); propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine));
const QString name = typeCompilationUnit->data->stringAt(obj->idIndex);
propertyNameCache.add(name, it.value());
}
objectIndexToId.clear();
} }
return propertyNameCache; return propertyNameCache;
} }
QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames()
{
propertyNames();
propertyNameCache.detach();
return propertyNameCache;
}
QUrl QQmlContextData::url() const QUrl QQmlContextData::url() const
{ {
if (typeCompilationUnit) if (typeCompilationUnit)

View File

@ -151,9 +151,15 @@ public:
// Compilation unit for contexts that belong to a compiled type. // Compilation unit for contexts that belong to a compiled type.
QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit; QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit;
mutable QHash<int, int> objectIndexToId; // object index in CompiledData::Unit to component that created this context
int componentObjectIndex;
void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex);
// flag indicates whether the context owns the cache (after mutation) or not.
mutable QV4::IdentifierHash<int> propertyNameCache; mutable QV4::IdentifierHash<int> propertyNameCache;
QV4::IdentifierHash<int> &propertyNames() const; const QV4::IdentifierHash<int> &propertyNames() const;
QV4::IdentifierHash<int> &detachedPropertyNames();
// Context object // Context object
QObject *contextObject; QObject *contextObject;
@ -201,7 +207,6 @@ public:
ContextGuard *idValues; ContextGuard *idValues;
int idValueCount; int idValueCount;
void setIdProperty(int, QObject *); void setIdProperty(int, QObject *);
void setIdPropertyData(const QHash<int, int> &);
// Linked contexts. this owns linkedContext. // Linked contexts. this owns linkedContext.
QQmlContextData *linkedContext; QQmlContextData *linkedContext;

View File

@ -82,7 +82,7 @@ public:
Flags flags() const { return m_flags; } Flags flags() const { return m_flags; }
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0; virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0; virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
QList<QQmlError> errors() const { return exceptions; } QList<QQmlError> errors() const { return exceptions; }

View File

@ -2227,7 +2227,7 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
Locker locker(this); Locker locker(this);
QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) { if (iter != m_compositeTypes.cend()) {
return QQmlMetaObject((*iter)->rootPropertyCache()); return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
} else { } else {
QQmlType *type = QQmlMetaType::qmlType(t); QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->baseMetaObject():0); return QQmlMetaObject(type?type->baseMetaObject():0);
@ -2239,7 +2239,7 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
Locker locker(this); Locker locker(this);
QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) { if (iter != m_compositeTypes.cend()) {
return QQmlMetaObject((*iter)->rootPropertyCache()); return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
} else { } else {
QQmlType *type = QQmlMetaType::qmlType(t); QQmlType *type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type?type->metaObject():0); return QQmlMetaObject(type?type->metaObject():0);
@ -2251,7 +2251,7 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
Locker locker(this); Locker locker(this);
QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) { if (iter != m_compositeTypes.cend()) {
return (*iter)->rootPropertyCache(); return (*iter)->compilationUnit->rootPropertyCache();
} else { } else {
QQmlType *type = QQmlMetaType::qmlType(t); QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock(); locker.unlock();
@ -2264,7 +2264,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
Locker locker(this); Locker locker(this);
QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) { if (iter != m_compositeTypes.cend()) {
return (*iter)->rootPropertyCache(); return (*iter)->compilationUnit->rootPropertyCache();
} else { } else {
QQmlType *type = QQmlMetaType::qmlType(t); QQmlType *type = QQmlMetaType::qmlType(t);
locker.unlock(); locker.unlock();
@ -2274,7 +2274,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data) void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
{ {
QByteArray name = data->rootPropertyCache()->className(); QByteArray name = data->compilationUnit->rootPropertyCache()->className();
QByteArray ptr = name + '*'; QByteArray ptr = name + '*';
QByteArray lst = "QQmlListProperty<" + name + '>'; QByteArray lst = "QQmlListProperty<" + name + '>';

View File

@ -494,7 +494,7 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
if (!td || !td->isComplete()) if (!td || !td->isComplete())
return 0; return 0;
QQmlCompiledData *cd = td->compiledData(); QQmlCompiledData *cd = td->compiledData();
const QMetaObject *mo = cd->rootPropertyCache()->firstCppMetaObject(); const QMetaObject *mo = cd->compilationUnit->rootPropertyCache()->firstCppMetaObject();
return QQmlMetaType::qmlType(mo); return QQmlMetaType::qmlType(mo);
} }

View File

@ -73,7 +73,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
: phase(Startup) : phase(Startup)
, compiledData(compiledData) , compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes) , resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches) , propertyCaches(compiledData->compilationUnit->propertyCaches)
, activeVMEDataForRootContext(activeVMEDataForRootContext) , activeVMEDataForRootContext(activeVMEDataForRootContext)
{ {
init(parentContext); init(parentContext);
@ -81,23 +81,23 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
sharedState = new QQmlObjectCreatorSharedState; sharedState = new QQmlObjectCreatorSharedState;
topLevelCreator = true; topLevelCreator = true;
sharedState->componentAttached = 0; sharedState->componentAttached = 0;
sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); sharedState->allCreatedBindings.allocate(compiledData->compilationUnit->totalBindingsCount);
sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); sharedState->allParserStatusCallbacks.allocate(compiledData->compilationUnit->totalParserStatusCount);
sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount); sharedState->allCreatedObjects.allocate(compiledData->compilationUnit->totalObjectCount);
sharedState->allJavaScriptObjects = 0; sharedState->allJavaScriptObjects = 0;
sharedState->creationContext = creationContext; sharedState->creationContext = creationContext;
sharedState->rootContext = 0; sharedState->rootContext = 0;
QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler; QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
sharedState->profiler.init(profiler, compiledData->totalParserStatusCount)); sharedState->profiler.init(profiler, compiledData->compilationUnit->totalParserStatusCount));
} }
QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState) QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
: phase(Startup) : phase(Startup)
, compiledData(compiledData) , compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes) , resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches) , propertyCaches(compiledData->compilationUnit->propertyCaches)
, activeVMEDataForRootContext(0) , activeVMEDataForRootContext(0)
{ {
init(parentContext); init(parentContext);
@ -158,19 +158,17 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
int objectToCreate; int objectToCreate;
if (subComponentIndex == -1) { if (subComponentIndex == -1) {
objectIndexToId = compiledData->objectIndexToIdForRoot;
objectToCreate = qmlUnit->indexOfRootObject; objectToCreate = qmlUnit->indexOfRootObject;
} else { } else {
objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex); const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
objectToCreate = compObj->bindingTable()->value.objectIndex; objectToCreate = compObj->bindingTable()->value.objectIndex;
} }
context = new QQmlContextData; context = new QQmlContextData;
context->isInternal = true; context->isInternal = true;
context->imports = compiledData->importCache; context->imports = compiledData->compilationUnit->importCache;
context->imports->addref(); context->imports->addref();
context->typeCompilationUnit = compiledData->compilationUnit; context->initFromTypeCompilationUnit(compiledData->compilationUnit, subComponentIndex);
context->setParent(parentContext); context->setParent(parentContext);
if (!sharedState->rootContext) { if (!sharedState->rootContext) {
@ -183,16 +181,14 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator); Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
if (topLevelCreator) if (topLevelCreator)
sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount); sharedState->allJavaScriptObjects = scope.alloc(compiledData->compilationUnit->totalObjectCount);
context->setIdPropertyData(objectIndexToId); if (subComponentIndex == -1 && compiledData->compilationUnit->dependentScripts.count()) {
QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->compilationUnit->dependentScripts.count()));
if (subComponentIndex == -1 && compiledData->scripts.count()) {
QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
context->importedScripts.set(v4, scripts); context->importedScripts.set(v4, scripts);
QV4::ScopedValue v(scope); QV4::ScopedValue v(scope);
for (int i = 0; i < compiledData->scripts.count(); ++i) { for (int i = 0; i < compiledData->compilationUnit->dependentScripts.count(); ++i) {
QQmlScriptData *s = compiledData->scripts.at(i); QQmlScriptData *s = compiledData->compilationUnit->dependentScripts.at(i);
scripts->putIndexed(i, (v = s->scriptValueForContext(context))); scripts->putIndexed(i, (v = s->scriptValueForContext(context)));
} }
} else if (sharedState->creationContext) { } else if (sharedState->creationContext) {
@ -240,7 +236,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
Q_ASSERT(topLevelCreator); Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects); Q_ASSERT(!sharedState->allJavaScriptObjects);
sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount); sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1)); QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
@ -259,11 +255,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
qSwap(_bindingTarget, bindingTarget); qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex); setupBindings(/*applyDeferredBindings=*/true);
for (int i = 0; i < bindingSkipList.count(); ++i)
bindingSkipList.setBit(i, !bindingSkipList.testBit(i));
setupBindings(bindingSkipList);
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget); qSwap(_bindingTarget, bindingTarget);
@ -630,14 +622,14 @@ static QQmlType *qmlTypeForObject(QObject *object)
return type; return type;
} }
void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
{ {
QQmlListProperty<void> savedList; QQmlListProperty<void> savedList;
qSwap(_currentList, savedList); qSwap(_currentList, savedList);
const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex); const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
if (_compiledObject->idIndex) { if (_compiledObject->idNameIndex) {
const QQmlPropertyData *idProperty = propertyData.last(); const QQmlPropertyData *idProperty = propertyData.last();
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id")); Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) { if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) {
@ -645,7 +637,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
idBinding.propertyNameIndex = 0; // Not used idBinding.propertyNameIndex = 0; // Not used
idBinding.flags = 0; idBinding.flags = 0;
idBinding.type = QV4::CompiledData::Binding::Type_String; idBinding.type = QV4::CompiledData::Binding::Type_String;
idBinding.stringIndex = _compiledObject->idIndex; idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ### idBinding.location = _compiledObject->location; // ###
setPropertyValue(idProperty, &idBinding); setPropertyValue(idProperty, &idBinding);
} }
@ -681,9 +673,17 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i)) if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
continue; continue;
if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
if (!applyDeferredBindings)
continue;
} else {
if (applyDeferredBindings)
continue;
}
const QQmlPropertyData *property = propertyData.at(i); const QQmlPropertyData *property = propertyData.at(i);
if (property && property->isQList()) { if (property && property->isQList()) {
@ -1005,11 +1005,10 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
errors << error; errors << error;
} }
void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject *instance) const void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{ {
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(objectIndex); if (object->id >= 0)
if (idEntry != objectIndexToId.constEnd()) context->setIdProperty(object->id, instance);
context->setIdProperty(idEntry.value(), instance);
} }
QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
@ -1022,7 +1021,9 @@ QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
{ {
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler); const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
bool isComponent = false; bool isComponent = false;
@ -1032,8 +1033,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = 0; QQmlParserStatus *parserStatus = 0;
bool installPropertyCache = true; bool installPropertyCache = true;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); if (obj->flags & QV4::CompiledData::Object::IsComponent) {
if (compiledData->isComponent(index)) {
isComponent = true; isComponent = true;
QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
@ -1125,28 +1125,26 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (isContextObject) if (isContextObject)
context->contextObject = instance; context->contextObject = instance;
QBitArray bindingsToSkip; if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
if (customParser) { customParser->engine = QQmlEnginePrivate::get(engine);
QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); customParser->imports = compiledData->compilationUnit->importCache;
if (customParserBindings != compiledData->customParserBindings.constEnd()) {
customParser->engine = QQmlEnginePrivate::get(engine);
customParser->imports = compiledData->importCache;
QList<const QV4::CompiledData::Binding *> bindings; QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
for (int i = 0; i < customParserBindings->count(); ++i) const QV4::CompiledData::Binding *binding = obj->bindingTable();
if (customParserBindings->testBit(i)) for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
bindings << obj->bindingTable() + i; if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
customParser->applyBindings(instance, compiledData, bindings); bindings << binding;
}
customParser->engine = 0;
customParser->imports = (QQmlTypeNameCache*)0;
bindingsToSkip = *customParserBindings;
} }
customParser->applyBindings(instance, compiledData->compilationUnit.data(), bindings);
customParser->engine = 0;
customParser->imports = (QQmlTypeNameCache*)0;
} }
if (isComponent) { if (isComponent) {
registerObjectWithContextById(index, instance); registerObjectWithContextById(obj, instance);
return instance; return instance;
} }
@ -1171,7 +1169,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
qSwap(_qmlContext, qmlContext); qSwap(_qmlContext, qmlContext);
bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip); bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0);
qSwap(_qmlContext, qmlContext); qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject); qSwap(_scopeObject, scopeObject);
@ -1266,7 +1264,7 @@ void QQmlObjectCreator::clear()
phase = Done; phase = Done;
} }
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
{ {
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
@ -1298,33 +1296,23 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
vmeMetaObject = QQmlVMEMetaObject::get(_qobject); vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
} }
registerObjectWithContextById(_compiledObjectIndex, _qobject); registerObjectWithContextById(_compiledObject, _qobject);
qSwap(_propertyCache, cache); qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
QBitArray bindingSkipList = bindingsToSkip; if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
{ QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); deferData->deferredIdx = _compiledObjectIndex;
if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { deferData->compiledData = compiledData;
if (bindingSkipList.isEmpty()) deferData->compiledData->addref();
bindingSkipList.resize(deferredBindings->count()); deferData->context = context;
_ddata->deferredData = deferData;
for (int i = 0; i < deferredBindings->count(); ++i)
if (deferredBindings->testBit(i))
bindingSkipList.setBit(i);
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = _compiledObjectIndex;
deferData->compiledData = compiledData;
deferData->compiledData->addref();
deferData->context = context;
_ddata->deferredData = deferData;
}
} }
if (_compiledObject->nFunctions > 0) if (_compiledObject->nFunctions > 0)
setupFunctions(); setupFunctions();
setupBindings(bindingSkipList); setupBindings();
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget); qSwap(_bindingTarget, bindingTarget);

View File

@ -111,10 +111,9 @@ private:
QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false); QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false);
bool populateInstance(int index, QObject *instance, bool populateInstance(int index, QObject *instance,
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
const QBitArray &bindingsToSkip = QBitArray());
void setupBindings(const QBitArray &bindingsToSkip); void setupBindings(bool applyDeferredBindings = false);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions(); void setupFunctions();
@ -122,7 +121,7 @@ private:
QString stringAt(int idx) const { return qmlUnit->stringAt(idx); } QString stringAt(int idx) const { return qmlUnit->stringAt(idx); }
void recordError(const QV4::CompiledData::Location &location, const QString &description); void recordError(const QV4::CompiledData::Location &location, const QString &description);
void registerObjectWithContextById(int objectIndex, QObject *instance) const; void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
QV4::Heap::QmlContext *currentQmlContext(); QV4::Heap::QmlContext *currentQmlContext();
@ -143,7 +142,6 @@ private:
QQmlContextData *context; QQmlContextData *context;
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes; const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QQmlPropertyCacheVector &propertyCaches; const QQmlPropertyCacheVector &propertyCaches;
QHash<int, int> objectIndexToId;
QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState; QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator; bool topLevelCreator;
void *activeVMEDataForRootContext; void *activeVMEDataForRootContext;

View File

@ -452,7 +452,12 @@ QQmlPropertyCache *QQmlPropertyCache::parent() const
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent) void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
{ {
if (_parent == newParent)
return;
if (_parent)
_parent->release();
_parent = newParent; _parent = newParent;
_parent->addref();
} }
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by

View File

@ -67,7 +67,7 @@ public:
bool ignoreUnknownSignals; bool ignoreUnknownSignals;
bool componentcomplete; bool componentcomplete;
QQmlRefPointer<QQmlCompiledData> cdata; QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings; QList<const QV4::CompiledData::Binding *> bindings;
}; };
@ -258,11 +258,11 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni
} }
} }
void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) void QQmlConnectionsParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
QQmlConnectionsPrivate *p = QQmlConnectionsPrivate *p =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object)); static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
p->cdata = cdata; p->compilationUnit = compilationUnit;
p->bindings = bindings; p->bindings = bindings;
} }
@ -278,7 +278,7 @@ void QQmlConnections::connectSignals()
QQmlData *ddata = QQmlData::get(this); QQmlData *ddata = QQmlData::get(this);
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0; QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0;
const QV4::CompiledData::Unit *qmlUnit = d->cdata->compilationUnit->data; const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data;
foreach (const QV4::CompiledData::Binding *binding, d->bindings) { foreach (const QV4::CompiledData::Binding *binding, d->bindings) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
QString propName = qmlUnit->stringAt(binding->propertyNameIndex); QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
@ -291,7 +291,7 @@ void QQmlConnections::connectSignals()
QQmlBoundSignalExpression *expression = ctxtdata ? QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target, signalIndex, new QQmlBoundSignalExpression(target, signalIndex,
ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0; ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
signal->takeExpression(expression); signal->takeExpression(expression);
d->boundsignals += signal; d->boundsignals += signal;
} else { } else {

View File

@ -99,7 +99,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
{ {
public: public:
virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); virtual void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
}; };

View File

@ -2401,7 +2401,7 @@ bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit,
listElementTypeName = objName; // cache right name for next time listElementTypeName = objName; // cache right name for next time
} }
if (!qmlUnit->stringAt(target->idIndex).isEmpty()) { if (!qmlUnit->stringAt(target->idNameIndex).isEmpty()) {
error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property")); error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
return false; return false;
} }
@ -2508,13 +2508,13 @@ void QQmlListModelParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit,
} }
} }
void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
QQmlListModel *rv = static_cast<QQmlListModel *>(obj); QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
rv->m_engine = QV8Engine::getV4(qmlEngine(rv)); rv->m_engine = QV8Engine::getV4(qmlEngine(rv));
const QV4::CompiledData::Unit *qmlUnit = cdata->compilationUnit->data; const QV4::CompiledData::Unit *qmlUnit = compilationUnit->data;
bool setRoles = false; bool setRoles = false;

View File

@ -188,7 +188,7 @@ public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {} QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE; void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE; void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
private: private:
bool verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding); bool verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);

View File

@ -70,7 +70,7 @@ void QQmlProfilerClient::sendRecordingStatus(bool record, int engineId, quint32
Q_D(const QQmlProfilerClient); Q_D(const QQmlProfilerClient);
QPacket stream(d->connection->currentDataStreamVersion()); QPacket stream(d->connection->currentDataStreamVersion());
stream << record << engineId << d->features << flushInterval; stream << record << engineId << d->features << flushInterval << true;
sendMessage(stream.data()); sendMessage(stream.data());
} }
@ -205,7 +205,7 @@ inline QQmlProfilerDefinitions::ProfileFeature featureFromRangeType(
void QQmlProfilerClient::messageReceived(const QByteArray &data) void QQmlProfilerClient::messageReceived(const QByteArray &data)
{ {
Q_D(const QQmlProfilerClient); Q_D(QQmlProfilerClient);
QPacket stream(d->connection->currentDataStreamVersion(), data); QPacket stream(d->connection->currentDataStreamVersion(), data);
@ -333,12 +333,25 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
!(d->features & one << featureFromRangeType(rangeType))) !(d->features & one << featureFromRangeType(rangeType)))
return; return;
qint64 typeId = 0;
if (messageType == QQmlProfilerDefinitions::RangeStart) { if (messageType == QQmlProfilerDefinitions::RangeStart) {
rangeStart(rangeType, time); rangeStart(rangeType, time);
if (!stream.atEnd()) {
stream >> typeId;
auto i = d->types.constFind(typeId);
if (i != d->types.constEnd()) {
rangeLocation(rangeType, time, i->location);
rangeData(rangeType, time, i->name);
}
}
} else if (messageType == QQmlProfilerDefinitions::RangeData) { } else if (messageType == QQmlProfilerDefinitions::RangeData) {
QString data; QString data;
stream >> data; stream >> data;
rangeData(rangeType, time, data); rangeData(rangeType, time, data);
if (!stream.atEnd()) {
stream >> typeId;
d->types[typeId].name = data;
}
} else if (messageType == QQmlProfilerDefinitions::RangeLocation) { } else if (messageType == QQmlProfilerDefinitions::RangeLocation) {
QQmlEventLocation location; QQmlEventLocation location;
stream >> location.filename >> location.line; stream >> location.filename >> location.line;
@ -347,6 +360,10 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
stream >> location.column; stream >> location.column;
rangeLocation(rangeType, time, location); rangeLocation(rangeType, time, location);
if (!stream.atEnd()) {
stream >> typeId;
d->types[typeId].location = location;
}
} else if (messageType == QQmlProfilerDefinitions::RangeEnd) { } else if (messageType == QQmlProfilerDefinitions::RangeEnd) {
rangeEnd(rangeType, time); rangeEnd(rangeType, time);
} else { } else {

View File

@ -56,12 +56,20 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
struct QQmlProfilerRangeType
{
QQmlEventLocation location;
QString name;
};
class QQmlProfilerClientPrivate : public QQmlDebugClientPrivate class QQmlProfilerClientPrivate : public QQmlDebugClientPrivate
{ {
Q_DECLARE_PUBLIC(QQmlProfilerClient) Q_DECLARE_PUBLIC(QQmlProfilerClient)
public: public:
QQmlProfilerClientPrivate(QQmlDebugConnection *connection); QQmlProfilerClientPrivate(QQmlDebugConnection *connection);
quint64 features; quint64 features;
QHash<qint64, QQmlProfilerRangeType> types;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -415,4 +415,26 @@ Item {
\endqml \endqml
*/ */
/*!
\qmlproperty int QtQuick::WheelEvent::inverted
Returns whether the delta values delivered with the event are inverted.
Normally, a vertical wheel will produce a WheelEvent with positive delta
values if the top of the wheel is rotating away from the hand operating it.
Similarly, a horizontal wheel movement will produce a QWheelEvent with
positive delta values if the top of the wheel is moved to the left.
However, on some platforms this is configurable, so that the same
operations described above will produce negative delta values (but with the
same magnitude). For instance, in a QML component (such as a tumbler or a
slider) where it is appropriate to synchronize the movement or rotation of
an item with the direction of the wheel, regardless of the system settings,
the wheel event handler can use the inverted property to decide whether to
negate the angleDelta or pixelDelta values.
\note Many platforms provide no such information. On such platforms
\l inverted always returns false.
*/
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -73,10 +73,22 @@ class QQuickKeyEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public: public:
QQuickKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1) QQuickKeyEvent()
: event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); } : event(QEvent::None, 0, 0)
QQuickKeyEvent(const QKeyEvent &ke) {}
: event(ke) { event.setAccepted(false); }
void reset(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
const QString &text = QString(), bool autorep = false, ushort count = 1)
{
event = QKeyEvent(type, key, modifiers, text, autorep, count);
event.setAccepted(false);
}
void reset(const QKeyEvent &ke)
{
event = ke;
event.setAccepted(false);
}
int key() const { return event.key(); } int key() const { return event.key(); }
QString text() const { return event.text(); } QString text() const { return event.text(); }
@ -109,10 +121,21 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public: public:
QQuickMouseEvent(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers QQuickMouseEvent() {}
, bool isClick=false, bool wasHeld=false)
: _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers) void reset(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons,
, _source(Qt::MouseEventNotSynthesized), _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {} Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false)
{
_x = x;
_y = y;
_button = button;
_buttons = buttons;
_modifiers = modifiers;
_source = Qt::MouseEventNotSynthesized;
_wasHeld = wasHeld;
_isClick = isClick;
_accepted = true;
}
qreal x() const { return _x; } qreal x() const { return _x; }
qreal y() const { return _y; } qreal y() const { return _y; }
@ -139,9 +162,9 @@ private:
Qt::MouseButtons _buttons; Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers; Qt::KeyboardModifiers _modifiers;
Qt::MouseEventSource _source; Qt::MouseEventSource _source;
bool _wasHeld; bool _wasHeld : 1;
bool _isClick; bool _isClick : 1;
bool _accepted; bool _accepted : 1;
}; };
class QQuickWheelEvent : public QObject class QQuickWheelEvent : public QObject
@ -153,13 +176,24 @@ class QQuickWheelEvent : public QObject
Q_PROPERTY(QPoint pixelDelta READ pixelDelta) Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
Q_PROPERTY(int buttons READ buttons) Q_PROPERTY(int buttons READ buttons)
Q_PROPERTY(int modifiers READ modifiers) Q_PROPERTY(int modifiers READ modifiers)
Q_PROPERTY(bool inverted READ inverted)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public: public:
QQuickWheelEvent(qreal x, qreal y, const QPoint& angleDelta, const QPoint& pixelDelta, QQuickWheelEvent() {}
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
: _x(x), _y(y), _angleDelta(angleDelta), _pixelDelta(pixelDelta), _buttons(buttons), void reset(qreal x, qreal y, const QPoint &angleDelta, const QPoint &pixelDelta,
_modifiers(modifiers), _accepted(true) {} Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, bool inverted)
{
_x = x;
_y = y;
_angleDelta = angleDelta;
_pixelDelta = pixelDelta;
_buttons = buttons;
_modifiers = modifiers;
_accepted = true;
_inverted = inverted;
}
qreal x() const { return _x; } qreal x() const { return _x; }
qreal y() const { return _y; } qreal y() const { return _y; }
@ -167,7 +201,7 @@ public:
QPoint pixelDelta() const { return _pixelDelta; } QPoint pixelDelta() const { return _pixelDelta; }
int buttons() const { return _buttons; } int buttons() const { return _buttons; }
int modifiers() const { return _modifiers; } int modifiers() const { return _modifiers; }
bool inverted() const { return _inverted; }
bool isAccepted() { return _accepted; } bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; } void setAccepted(bool accepted) { _accepted = accepted; }
@ -178,6 +212,7 @@ private:
QPoint _pixelDelta; QPoint _pixelDelta;
Qt::MouseButtons _buttons; Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers; Qt::KeyboardModifiers _modifiers;
bool _inverted;
bool _accepted; bool _accepted;
}; };

View File

@ -1355,7 +1355,8 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
d->inPress = false; d->inPress = false;
} }
QQuickKeyEvent ke(*event); QQuickKeyEvent &ke = d->theKeyEvent;
ke.reset(*event);
QByteArray keySignal = keyToSignal(event->key()); QByteArray keySignal = keyToSignal(event->key());
if (!keySignal.isEmpty()) { if (!keySignal.isEmpty()) {
keySignal += "(QQuickKeyEvent*)"; keySignal += "(QQuickKeyEvent*)";
@ -1398,7 +1399,8 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
d->inRelease = false; d->inRelease = false;
} }
QQuickKeyEvent ke(*event); QQuickKeyEvent &ke = d->theKeyEvent;
ke.reset(*event);
emit released(&ke); emit released(&ke);
event->setAccepted(ke.isAccepted()); event->setAccepted(ke.isAccepted());

View File

@ -56,6 +56,7 @@
#include "qquickanchors_p.h" #include "qquickanchors_p.h"
#include "qquickanchors_p_p.h" #include "qquickanchors_p_p.h"
#include "qquickitemchangelistener_p.h" #include "qquickitemchangelistener_p.h"
#include "qquickevents_p_p.h"
#include "qquickwindow_p.h" #include "qquickwindow_p.h"
@ -777,6 +778,7 @@ public:
QQuickItem *imeItem; QQuickItem *imeItem;
QList<QQuickItem *> targets; QList<QQuickItem *> targets;
QQuickItem *item; QQuickItem *item;
QQuickKeyEvent theKeyEvent;
}; };
class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter

View File

@ -40,7 +40,6 @@
#include "qquickmousearea_p.h" #include "qquickmousearea_p.h"
#include "qquickmousearea_p_p.h" #include "qquickmousearea_p_p.h"
#include "qquickwindow.h" #include "qquickwindow.h"
#include "qquickevents_p_p.h"
#include "qquickdrag_p.h" #include "qquickdrag_p.h"
#include <private/qqmldata_p.h> #include <private/qqmldata_p.h>
@ -761,7 +760,8 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
} }
#endif #endif
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
me.setSource(event->source()); me.setSource(event->source());
emit mouseXChanged(&me); emit mouseXChanged(&me);
me.setPosition(d->lastPos); me.setPosition(d->lastPos);
@ -802,7 +802,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
Q_D(QQuickMouseArea); Q_D(QQuickMouseArea);
if (d->enabled) { if (d->enabled) {
d->saveEvent(event); d->saveEvent(event);
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
me.setSource(event->source()); me.setSource(event->source());
me.setAccepted(d->isDoubleClickConnected()); me.setAccepted(d->isDoubleClickConnected());
emit this->doubleClicked(&me); emit this->doubleClicked(&me);
@ -822,7 +823,8 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
d->lastPos = event->posF(); d->lastPos = event->posF();
d->lastModifiers = event->modifiers(); d->lastModifiers = event->modifiers();
setHovered(true); setHovered(true);
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
emit mouseXChanged(&me); emit mouseXChanged(&me);
me.setPosition(d->lastPos); me.setPosition(d->lastPos);
emit mouseYChanged(&me); emit mouseYChanged(&me);
@ -835,10 +837,11 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
Q_D(QQuickMouseArea); Q_D(QQuickMouseArea);
if (!d->enabled && !d->pressed) { if (!d->enabled && !d->pressed) {
QQuickItem::hoverMoveEvent(event); QQuickItem::hoverMoveEvent(event);
} else { } else if (d->lastPos != event->posF()) {
d->lastPos = event->posF(); d->lastPos = event->posF();
d->lastModifiers = event->modifiers(); d->lastModifiers = event->modifiers();
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
emit mouseXChanged(&me); emit mouseXChanged(&me);
me.setPosition(d->lastPos); me.setPosition(d->lastPos);
emit mouseYChanged(&me); emit mouseYChanged(&me);
@ -865,8 +868,9 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event)
return; return;
} }
QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(), QQuickWheelEvent &we = d->quickWheelEvent;
event->pixelDelta(), event->buttons(), event->modifiers()); we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(),
event->buttons(), event->modifiers(), event->inverted());
we.setAccepted(d->isWheelConnected()); we.setAccepted(d->isWheelConnected());
emit wheel(&we); emit wheel(&we);
if (!we.isAccepted()) if (!we.isAccepted())
@ -997,7 +1001,8 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
#endif #endif
if (d->pressed && dragged == false && d->hovered == true) { if (d->pressed && dragged == false && d->hovered == true) {
d->longPress = true; d->longPress = true;
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
me.setSource(Qt::MouseEventSynthesizedByQt); me.setSource(Qt::MouseEventSynthesizedByQt);
me.setAccepted(d->isPressAndHoldConnected()); me.setAccepted(d->isPressAndHoldConnected());
emit pressAndHold(&me); emit pressAndHold(&me);
@ -1078,8 +1083,7 @@ void QQuickMouseArea::setHoverEnabled(bool h)
\qmlproperty bool QtQuick::MouseArea::containsMouse \qmlproperty bool QtQuick::MouseArea::containsMouse
This property holds whether the mouse is currently inside the mouse area. This property holds whether the mouse is currently inside the mouse area.
\warning This property is not updated if the area moves under the mouse: \e containsMouse will not change. \warning If hoverEnabled is false, containsMouse will only be valid
In addition, if hoverEnabled is false, containsMouse will only be valid
when the mouse is pressed while the mouse cursor is inside the MouseArea. when the mouse is pressed while the mouse cursor is inside the MouseArea.
*/ */
bool QQuickMouseArea::hovered() const bool QQuickMouseArea::hovered() const
@ -1175,7 +1179,8 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
Qt::MouseButtons oldPressed = d->pressed; Qt::MouseButtons oldPressed = d->pressed;
if (wasPressed != p) { if (wasPressed != p) {
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress); QQuickMouseEvent &me = d->quickMouseEvent;
me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
me.setSource(source); me.setSource(source);
if (p) { if (p) {
d->pressed |= button; d->pressed |= button;

View File

@ -52,6 +52,7 @@
// //
#include "qquickitem_p.h" #include "qquickitem_p.h"
#include "qquickevents_p_p.h"
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include <QtCore/qbasictimer.h> #include <QtCore/qbasictimer.h>
@ -107,6 +108,8 @@ public:
#ifndef QT_NO_CURSOR #ifndef QT_NO_CURSOR
QCursor *cursor; QCursor *cursor;
#endif #endif
QQuickMouseEvent quickMouseEvent;
QQuickWheelEvent quickWheelEvent;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -456,7 +456,7 @@ void QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache()
{ {
QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get(false); QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get(false);
if (cache) { if (cache) {
qDeleteAll(cache->cache.values()); qDeleteAll(cache->cache);
delete cache; delete cache;
} }
} }

View File

@ -254,7 +254,7 @@ void QQuickRenderControl::polishItems()
return; return;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window); QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
cd->flushDelayedTouchEvent(); cd->flushFrameSynchronousEvents();
if (!d->window) if (!d->window)
return; return;
cd->polishItems(); cd->polishItems();

View File

@ -2028,7 +2028,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
} }
} }
void QQuickWindowPrivate::flushDelayedTouchEvent() void QQuickWindowPrivate::flushFrameSynchronousEvents()
{ {
if (delayedTouch) { if (delayedTouch) {
deliverDelayedTouchEvent(); deliverDelayedTouchEvent();
@ -2039,6 +2039,17 @@ void QQuickWindowPrivate::flushDelayedTouchEvent()
if (ut && ut->hasStartAnimationPending()) if (ut && ut->hasStartAnimationPending())
ut->startAnimations(); ut->startAnimations();
} }
// Once per frame, send a synthetic hover, in case items have changed position.
// For instance, during animation (including the case of a ListView
// whose delegates contain MouseAreas), a MouseArea needs to know
// whether it has moved into a position where it is now under the cursor.
if (!mouseGrabberItem && !lastMousePosition.isNull()) {
bool accepted = false;
bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), accepted);
if (!delivered)
clearHover(); // take care of any exits
}
} }
void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event) void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)

View File

@ -160,7 +160,7 @@ public:
void reallyDeliverTouchEvent(QTouchEvent *); void reallyDeliverTouchEvent(QTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *); bool deliverTouchCancelEvent(QTouchEvent *);
void deliverDelayedTouchEvent(); void deliverDelayedTouchEvent();
void flushDelayedTouchEvent(); void flushFrameSynchronousEvents();
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false); static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false);

View File

@ -126,7 +126,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
data.updatePending = false; data.updatePending = false;
if (!data.grabOnly) { if (!data.grabOnly) {
cd->flushDelayedTouchEvent(); cd->flushFrameSynchronousEvents();
// Event delivery/processing triggered the window to be deleted or stop rendering. // Event delivery/processing triggered the window to be deleted or stop rendering.
if (!m_windows.contains(window)) if (!m_windows.contains(window))
return; return;

View File

@ -846,7 +846,7 @@ Renderer::~Renderer()
for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this); for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
} }
foreach (Node *n, m_nodes.values()) for (Node *n : qAsConst(m_nodes))
m_nodeAllocator.release(n); m_nodeAllocator.release(n);
// Remaining elements... // Remaining elements...

View File

@ -382,7 +382,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
return; return;
if (!data.grabOnly) { if (!data.grabOnly) {
cd->flushDelayedTouchEvent(); cd->flushFrameSynchronousEvents();
// Event delivery/processing triggered the window to be deleted or stop rendering. // Event delivery/processing triggered the window to be deleted or stop rendering.
if (!m_windows.contains(window)) if (!m_windows.contains(window))
return; return;

View File

@ -1142,7 +1142,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
} }
// Flush pending touch events. // Flush pending touch events.
QQuickWindowPrivate::get(window)->flushDelayedTouchEvent(); QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
// The delivery of the event might have caused the window to stop rendering // The delivery of the event might have caused the window to stop rendering
w = windowFor(m_windows, window); w = windowFor(m_windows, window);
if (!w || !w->thread || !w->thread->window) { if (!w || !w->thread || !w->thread->window) {

View File

@ -445,7 +445,7 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
} }
} }
d->flushDelayedTouchEvent(); d->flushFrameSynchronousEvents();
// Event delivery or processing has caused the window to stop rendering. // Event delivery or processing has caused the window to stop rendering.
if (!windowData(window)) if (!windowData(window))
return; return;

View File

@ -922,15 +922,13 @@ QQuickPixmapStore::~QQuickPixmapStore()
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
int leakedPixmaps = 0; int leakedPixmaps = 0;
#endif #endif
QList<QQuickPixmapData*> cachedData = m_cache.values();
// Prevent unreferencePixmap() from assuming it needs to kick // Prevent unreferencePixmap() from assuming it needs to kick
// off the cache expiry timer, as we're shrinking the cache // off the cache expiry timer, as we're shrinking the cache
// manually below after releasing all the pixmaps. // manually below after releasing all the pixmaps.
m_timerId = -2; m_timerId = -2;
// unreference all (leaked) pixmaps // unreference all (leaked) pixmaps
foreach (QQuickPixmapData* pixmap, cachedData) { for (auto *pixmap : qAsConst(m_cache)) {
int currRefCount = pixmap->refCount; int currRefCount = pixmap->refCount;
if (currRefCount) { if (currRefCount) {
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -110,8 +110,9 @@ void QQuickProfiler::stopProfilingImpl()
m_data.clear(); m_data.clear();
} }
void QQuickProfiler::reportDataImpl() void QQuickProfiler::reportDataImpl(bool trackLocations)
{ {
Q_UNUSED(trackLocations);
QMutexLocker lock(&m_dataMutex); QMutexLocker lock(&m_dataMutex);
emit dataReady(m_data); emit dataReady(m_data);
m_data.clear(); m_data.clear();

View File

@ -353,7 +353,7 @@ signals:
protected slots: protected slots:
void startProfilingImpl(quint64 features); void startProfilingImpl(quint64 features);
void stopProfilingImpl(); void stopProfilingImpl();
void reportDataImpl(); void reportDataImpl(bool trackLocations);
void setTimer(const QElapsedTimer &t); void setTimer(const QElapsedTimer &t);
}; };

View File

@ -202,7 +202,7 @@ public:
QPointer<QObject> object; QPointer<QObject> object;
QList<const QV4::CompiledData::Binding *> bindings; QList<const QV4::CompiledData::Binding *> bindings;
QQmlRefPointer<QQmlCompiledData> cdata; QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
bool decoded : 1; bool decoded : 1;
bool restore : 1; bool restore : 1;
@ -258,7 +258,7 @@ void QQuickPropertyChangesPrivate::decode()
return; return;
foreach (const QV4::CompiledData::Binding *binding, bindings) foreach (const QV4::CompiledData::Binding *binding, bindings)
decodeBinding(QString(), cdata->compilationUnit->data, binding); decodeBinding(QString(), compilationUnit->data, binding);
bindings.clear(); bindings.clear();
@ -288,7 +288,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler; QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
handler->property = prop; handler->property = prop;
handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(), handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
QQmlContextData::get(qmlContext(q)), object, cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex])); QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
signalReplacements << handler; signalReplacements << handler;
return; return;
} }
@ -338,12 +338,12 @@ void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::Unit *
verifyList(qmlUnit, props.at(ii)); verifyList(qmlUnit, props.at(ii));
} }
void QQuickPropertyChangesParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) void QQuickPropertyChangesParser::applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
QQuickPropertyChangesPrivate *p = QQuickPropertyChangesPrivate *p =
static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj)); static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj));
p->bindings = bindings; p->bindings = bindings;
p->cdata = cdata; p->compilationUnit = compilationUnit;
p->decoded = false; p->decoded = false;
} }
@ -456,7 +456,7 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
QQmlBinding *newBinding = 0; QQmlBinding *newBinding = 0;
if (e.id != QQmlBinding::Invalid) { if (e.id != QQmlBinding::Invalid) {
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->cdata->compilationUnit->runtimeFunctions[e.id])); QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->compilationUnit->runtimeFunctions[e.id]));
newBinding = new QQmlBinding(function, object(), context); newBinding = new QQmlBinding(function, object(), context);
} }
// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0; // QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;

View File

@ -104,7 +104,7 @@ public:
void verifyList(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding); void verifyList(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); virtual void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
}; };

View File

@ -392,7 +392,7 @@ QQuickSmoothedAnimationPrivate::~QQuickSmoothedAnimationPrivate()
void QQuickSmoothedAnimationPrivate::updateRunningAnimations() void QQuickSmoothedAnimationPrivate::updateRunningAnimations()
{ {
foreach(QSmoothedAnimation* ease, activeAnimations.values()){ for (QSmoothedAnimation *ease : qAsConst(activeAnimations)) {
ease->maximumEasingTime = anim->maximumEasingTime; ease->maximumEasingTime = anim->maximumEasingTime;
ease->reversingMode = anim->reversingMode; ease->reversingMode = anim->reversingMode;
ease->velocity = anim->velocity; ease->velocity = anim->velocity;
@ -444,7 +444,8 @@ QAbstractAnimationJob* QQuickSmoothedAnimation::transition(QQuickStateActions &a
anims.insert(ease); anims.insert(ease);
} }
foreach (QSmoothedAnimation *ease, d->activeAnimations.values()){ const auto copy = d->activeAnimations;
for (QSmoothedAnimation *ease : copy) {
if (!anims.contains(ease)) { if (!anims.contains(ease)) {
ease->clearTemplate(); ease->clearTemplate();
d->activeAnimations.remove(ease->target); d->activeAnimations.remove(ease->target);

View File

@ -585,7 +585,8 @@ QAbstractAnimationJob* QQuickSpringAnimation::transition(QQuickStateActions &act
animation->restart(); animation->restart();
anims.insert(animation); anims.insert(animation);
} }
foreach (QSpringAnimation *anim, d->activeAnimations.values()){ const auto copy = d->activeAnimations;
for (QSpringAnimation *anim : copy) {
if (!anims.contains(anim)) { if (!anims.contains(anim)) {
anim->clearTemplate(); anim->clearTemplate();
d->activeAnimations.remove(anim->target); d->activeAnimations.remove(anim->target);

View File

@ -0,0 +1,6 @@
import QtQml 2.0
Component {
QtObject {
id: blah
}
}

View File

@ -110,11 +110,11 @@ QVariant myCustomVariantTypeConverter(const QString &data)
} }
void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) void CustomBindingParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
Q_ASSERT(customBinding); Q_ASSERT(customBinding);
customBinding->cdata = cdata; customBinding->compilationUnit = compilationUnit;
customBinding->bindings = bindings; customBinding->bindings = bindings;
} }
@ -123,14 +123,14 @@ void CustomBinding::componentComplete()
Q_ASSERT(m_target); Q_ASSERT(m_target);
foreach (const QV4::CompiledData::Binding *binding, bindings) { foreach (const QV4::CompiledData::Binding *binding, bindings) {
QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex); QString name = compilationUnit->data->stringAt(binding->propertyNameIndex);
int bindingId = binding->value.compiledScriptIndex; int bindingId = binding->value.compiledScriptIndex;
QQmlContextData *context = QQmlContextData::get(qmlContext(this)); QQmlContextData *context = QQmlContextData::get(qmlContext(this));
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId])); QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId]));
QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context);
QQmlProperty property(m_target, name, qmlContext(this)); QQmlProperty property(m_target, name, qmlContext(this));
@ -169,7 +169,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q
} }
} }
void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings) void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &bindings)
{ {
SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
Q_ASSERT(o); Q_ASSERT(o);

View File

@ -733,14 +733,14 @@ class MyCustomParserTypeParser : public QQmlCustomParser
{ {
public: public:
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
}; };
class EnumSupportingCustomParser : public QQmlCustomParser class EnumSupportingCustomParser : public QQmlCustomParser
{ {
public: public:
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &); virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &);
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
}; };
class MyParserStatus : public QObject, public QQmlParserStatus class MyParserStatus : public QObject, public QQmlParserStatus
@ -1170,7 +1170,7 @@ public:
void setTarget(QObject *newTarget) { m_target = newTarget; } void setTarget(QObject *newTarget) { m_target = newTarget; }
QPointer<QObject> m_target; QPointer<QObject> m_target;
QQmlRefPointer<QQmlCompiledData> cdata; QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding*> bindings; QList<const QV4::CompiledData::Binding*> bindings;
QByteArray m_bindingData; QByteArray m_bindingData;
}; };
@ -1178,7 +1178,7 @@ public:
class CustomBindingParser : public QQmlCustomParser class CustomBindingParser : public QQmlCustomParser
{ {
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
}; };
class SimpleObjectWithCustomParser : public QObject class SimpleObjectWithCustomParser : public QObject
@ -1224,7 +1224,7 @@ private:
class SimpleObjectCustomParser : public QQmlCustomParser class SimpleObjectCustomParser : public QQmlCustomParser
{ {
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
}; };
class RootObjectInCreationTester : public QObject class RootObjectInCreationTester : public QObject

View File

@ -108,6 +108,7 @@ private slots:
void bindTypeToJSValue(); void bindTypeToJSValue();
void customParserTypes(); void customParserTypes();
void rootAsQmlComponent(); void rootAsQmlComponent();
void rootItemIsComponent();
void inlineQmlComponents(); void inlineQmlComponents();
void idProperty(); void idProperty();
void autoNotifyConnection(); void autoNotifyConnection();
@ -1195,6 +1196,19 @@ void tst_qqmllanguage::rootAsQmlComponent()
QCOMPARE(object->getChildren()->count(), 2); QCOMPARE(object->getChildren()->count(), 2);
} }
void tst_qqmllanguage::rootItemIsComponent()
{
QQmlComponent component(&engine, testFileUrl("rootItemIsComponent.qml"));
VERIFY_ERRORS(0);
QScopedPointer<QObject> root(component.create());
QVERIFY(qobject_cast<QQmlComponent*>(root.data()));
QScopedPointer<QObject> other(qobject_cast<QQmlComponent*>(root.data())->create());
QVERIFY(!other.isNull());
QQmlContext *context = qmlContext(other.data());
QVERIFY(context);
QCOMPARE(context->nameForObject(other.data()), QStringLiteral("blah"));
}
// Tests that components can be specified inline // Tests that components can be specified inline
void tst_qqmllanguage::inlineQmlComponents() void tst_qqmllanguage::inlineQmlComponents()
{ {

@ -1 +1 @@
Subproject commit 9741ac4655808ac46c127e3d1d8ba3d27ada618e Subproject commit 0b5af3dcec772bb06b4d685a20b2859cda59d189