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: "buttons"; type: "int"; isReadonly: true }
Property { name: "modifiers"; type: "int"; isReadonly: true }
Property { name: "inverted"; type: "bool" }
Property { name: "accepted"; type: "bool" }
}
Component {

View File

@ -145,7 +145,7 @@ void SignalTransition::invoke()
void SignalTransition::connectTriggered()
{
if (!m_complete || !m_cdata)
if (!m_complete || !m_compilationUnit)
return;
QObject *target = senderObject();
@ -165,7 +165,7 @@ void SignalTransition::connectTriggered()
QQmlBoundSignalExpression *expression = ctxtdata ?
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)
expression->setNotifyOnValueChanged(false);
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);
st->m_cdata = cdata;
st->m_compilationUnit = compilationUnit;
st->m_bindings = bindings;
}

View File

@ -90,7 +90,7 @@ private:
QJSValue m_signal;
QQmlScriptString m_guard;
bool m_complete;
QQmlRefPointer<QQmlCompiledData> m_cdata;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
QList<const QV4::CompiledData::Binding *> m_bindings;
QQmlBoundSignalExpressionPointer m_signalExpression;
};
@ -99,7 +99,7 @@ class SignalTransitionParser : public QQmlCustomParser
{
public:
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

View File

@ -114,7 +114,7 @@ void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
debugger->setBreakOnThrow(m_breakOnThrow);
foreach (const BreakPoint &breakPoint, m_breakPoints.values())
for (const BreakPoint &breakPoint : qAsConst(m_breakPoints))
if (breakPoint.enabled)
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(profilingDisabledWhileWaiting()),
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)),
engine->profiler, SLOT(setTimer(QElapsedTimer)));
connect(engine->profiler,
@ -68,49 +68,65 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
// use of QDataStream can skew results
// (see tst_qqmldebugtrace::trace() benchmark)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
const QQmlProfiler::LocationHash &locations,
QList<QByteArray> &messages)
QQmlProfiler::LocationHash &locations,
QList<QByteArray> &messages,
bool trackLocations)
{
QQmlDebugPacket ds;
Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO,
"You can use at most 31 message types.");
for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0;
++decodedMessageType) {
if ((d.messageType & (1 << decodedMessageType)) == 0)
continue;
if (decodedMessageType == QQmlProfilerDefinitions::RangeData
|| (d.messageType & (1 << decodedMessageType)) == 0) {
continue; // RangeData is sent together with RangeLocation
}
//### using QDataStream is relatively expensive
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
QQmlProfiler::Location l = locations.value(d.locationId);
switch (decodedMessageType) {
case QQmlProfilerDefinitions::RangeStart:
case QQmlProfilerDefinitions::RangeEnd:
break;
case QQmlProfilerDefinitions::RangeData:
ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile);
break;
case QQmlProfilerDefinitions::RangeLocation:
ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString())
<< static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column);
break;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type.");
break;
if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd
|| decodedMessageType == QQmlProfilerDefinitions::RangeStart) {
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
if (trackLocations && d.locationId != 0)
ds << static_cast<qint64>(d.locationId);
} else {
auto i = locations.find(d.locationId);
if (i != locations.end()) {
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
ds << (i->url.isEmpty() ? i->location.sourceFile : i->url.toString())
<< static_cast<qint32>(i->location.line)
<< static_cast<qint32>(i->location.column);
if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) {
// Send both, location and data ...
if (trackLocations)
ds << static_cast<qint64>(d.locationId);
messages.append(ds.squeezedData());
ds.clear();
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());
ds.clear();
}
}
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations)
{
while (next != data.length()) {
const QQmlProfilerData &nextData = data.at(next);
if (nextData.time > until || messages.length() > s_numMessagesPerBatch)
return nextData.time;
qQmlProfilerDataToByteArrays(nextData, locations, messages);
qQmlProfilerDataToByteArrays(nextData, locations, messages, trackLocations);
++next;
}

View File

@ -60,7 +60,8 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
Q_OBJECT
public:
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:
void receiveData(const QVector<QQmlProfilerData> &new_data,

View File

@ -57,7 +57,7 @@ Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
m_waitingForStop(false)
m_waitingForStop(false), m_useMessageTypes(false)
{
m_timer.start();
QQmlAbstractProfilerAdapter *quickAdapter =
@ -309,7 +309,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
m_waitingForStop = true;
foreach (QQmlAbstractProfilerAdapter *profiler, reporting)
profiler->reportData();
profiler->reportData(m_useMessageTypes);
foreach (QQmlAbstractProfilerAdapter *profiler, stopping)
profiler->stopProfiling();
@ -343,7 +343,8 @@ void QQmlProfilerServiceImpl::sendMessages()
m_startTimes.erase(m_startTimes.begin());
qint64 next = first->sendMessages(m_startTimes.isEmpty() ?
std::numeric_limits<qint64>::max() :
m_startTimes.begin().key(), messages);
m_startTimes.begin().key(), messages,
m_useMessageTypes);
if (next != -1)
m_startTimes.insert(next, first);
@ -418,6 +419,8 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
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 (enabled)
@ -435,14 +438,14 @@ void QQmlProfilerServiceImpl::flush()
foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) {
if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler);
profiler->reportData();
profiler->reportData(m_useMessageTypes);
}
}
foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
if (profiler->isRunning()) {
m_startTimes.insert(-1, profiler);
profiler->reportData();
profiler->reportData(m_useMessageTypes);
}
}
}

View File

@ -116,6 +116,7 @@ private:
QElapsedTimer m_timer;
QTimer m_flushTimer;
bool m_waitingForStop;
bool m_useMessageTypes;
QList<QQmlAbstractProfilerAdapter *> m_globalProfilers;
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(profilingDisabledWhileWaiting()), 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)),
engine->profiler, SLOT(setTimer(QElapsedTimer)));
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);
}
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations)
{
QQmlDebugPacket d;
// Make it const, so that we cannot accidentally detach it.
const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData;
const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations;
while (true) {
while (!m_stack.isEmpty() &&
@ -133,17 +133,27 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
return finalizeMessages(until, messages, props.start, d);
appendMemoryEvents(props.start, messages, d);
auto location = functionLocations.constFind(props.id);
Q_ASSERT(location != functionLocations.constEnd());
auto location = m_functionLocations.find(props.id);
d << props.start << RangeStart << Javascript;
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeLocation << Javascript << location->file << location->line
<< location->column;
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeData << Javascript << location->name;
if (trackLocations)
d << static_cast<qint64>(props.id);
if (location != m_functionLocations.end()) {
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeLocation << Javascript << location->file << location->line
<< 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());
d.clear();
m_stack.push(props.end);

View File

@ -67,7 +67,8 @@ class QV4ProfilerAdapter : public QQmlAbstractProfilerAdapter {
public:
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:
void v4ProfilingEnabled(quint64 v4Features);

View File

@ -61,8 +61,8 @@ QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) :
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabledWhileWaiting()),
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
connect(this, SIGNAL(dataRequested()),
QQuickProfiler::s_instance, SLOT(reportDataImpl()), Qt::DirectConnection);
connect(this, SIGNAL(dataRequested(bool)),
QQuickProfiler::s_instance, SLOT(reportDataImpl(bool)), Qt::DirectConnection);
connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)),
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()) {
if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch)
qQuickProfilerDataToByteArrays(m_data[next++], messages);

View File

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

View File

@ -1089,7 +1089,7 @@ void QSGD3D12RenderLoop::polishAndSync(WindowData *w, bool inExpose)
}
// 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
w = windowFor(windows, window);
if (!w || !w->thread || !w->thread->exposedWindow) {

View File

@ -72,23 +72,24 @@ using namespace QmlIR;
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;
location.line = loc.startLine;
location.column = loc.startColumn;
idIndex = id;
idNameIndex = idIndex;
id = -1;
indexOfDefaultPropertyOrAlias = -1;
defaultPropertyIsAlias = false;
flags = QV4::CompiledData::Object::NoFlag;
properties = pool->New<PoolList<Property> >();
aliases = pool->New<PoolList<Alias> >();
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
runtimeFunctionIndices = 0;
declarationsOverride = 0;
}
@ -1237,10 +1238,10 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
if (illegalNames.contains(idQString))
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"));
_object->idIndex = registerString(idQString);
_object->idNameIndex = registerString(idQString);
_object->locationOfIdProperty.line = idLocation.startLine;
_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 objectOffsetTableSize = output.objects.count() * sizeof(quint32);
QHash<Object*, quint32> objectOffsets;
QHash<const Object*, quint32> objectOffsets;
int objectsSize = 0;
foreach (Object *o, output.objects) {
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;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@ -1413,14 +1414,17 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
// write objects
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
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);
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
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->locationOfIdProperty = o->locationOfIdProperty;
@ -1446,9 +1450,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectToWrite->offsetToBindings = nextOffset;
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);
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;
for (const Property *p = o->firstProperty(); p; p = p->next) {
@ -1492,7 +1500,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
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;
}
@ -1509,7 +1522,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
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) {
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);
*bindingToWrite = *b;
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);
}
return bindingPtr;

View File

@ -170,7 +170,12 @@ class FixedPoolArray
public:
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();
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 {
Q_ASSERT(index >= 0 && index < count);
return data[index];
@ -274,9 +289,11 @@ struct Q_QML_PRIVATE_EXPORT Object
Q_DECLARE_TR_FUNCTIONS(Object)
public:
quint32 inheritedTypeNameIndex;
quint32 idIndex;
int indexOfDefaultPropertyOrAlias : 31;
int defaultPropertyIsAlias : 1;
quint32 idNameIndex;
int id;
int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias;
int flags;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
@ -296,7 +313,7 @@ public:
// specified object. Used for declarations inside group properties.
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);
@ -312,7 +329,9 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
FixedPoolArray<int> *runtimeFunctionIndices;
FixedPoolArray<int> runtimeFunctionIndices;
FixedPoolArray<quint32> namedObjectsInComponent;
private:
friend struct IRLoader;
@ -467,7 +486,7 @@ struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
private:
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

View File

@ -65,16 +65,16 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *
bool QQmlTypeCompiler::compile()
{
compiledData->importCache = new QQmlTypeNameCache;
importCache = new QQmlTypeNameCache;
foreach (const QString &ns, typeData->namespaces())
compiledData->importCache->add(ns);
importCache->add(ns);
// Add any Composite Singletons that were used to the import cache
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();
for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
@ -137,8 +137,6 @@ bool QQmlTypeCompiler::compile()
customParsers.insert(it.key(), customParser);
}
compiledData->propertyCaches.reserve(document->objects.count());
{
QQmlPropertyCacheCreator propertyCacheBuilder(this);
if (!propertyCacheBuilder.buildMetaObjects())
@ -174,7 +172,8 @@ bool QQmlTypeCompiler::compile()
// Collect imported scripts
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) {
const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
@ -187,10 +186,10 @@ bool QQmlTypeCompiler::compile()
qualifier = qualifier.mid(lastDotIndex+1);
}
compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref();
compiledData->scripts << scriptData;
dependentScripts << scriptData;
}
// Resolve component boundaries and aliases
@ -202,6 +201,12 @@ bool QQmlTypeCompiler::compile()
return false;
}
{
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
if (!deferredAndCustomParserBindingScanner.scanObject())
return false;
}
// Compile JS binding expressions and signal handlers
if (!document->javaScriptCompilationUnit) {
{
@ -211,7 +216,7 @@ bool QQmlTypeCompiler::compile()
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);
if (!jsCodeGen.generateCodeForComponents())
return false;
@ -236,9 +241,12 @@ bool QQmlTypeCompiler::compile()
document->javaScriptCompilationUnit->data = qmlUnit;
compiledData->compilationUnit = document->javaScriptCompilationUnit;
compiledData->compilationUnit->propertyCaches = m_propertyCaches;
compiledData->compilationUnit->importCache = importCache;
compiledData->compilationUnit->dependentScripts = dependentScripts;
// Add to type registry of composites
if (compiledData->isCompositeType())
if (compiledData->compilationUnit->isCompositeType())
engine->registerInternalCompositeType(compiledData);
else {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
@ -272,18 +280,18 @@ bool QQmlTypeCompiler::compile()
}
++objectCount;
if (typeRef->component) {
bindingCount += typeRef->component->totalBindingsCount;
parserStatusCount += typeRef->component->totalParserStatusCount;
objectCount += typeRef->component->totalObjectCount;
bindingCount += typeRef->component->compilationUnit->totalBindingsCount;
parserStatusCount += typeRef->component->compilationUnit->totalParserStatusCount;
objectCount += typeRef->component->compilationUnit->totalObjectCount;
}
}
}
compiledData->totalBindingsCount = bindingCount;
compiledData->totalParserStatusCount = parserStatusCount;
compiledData->totalObjectCount = objectCount;
compiledData->compilationUnit->totalBindingsCount = bindingCount;
compiledData->compilationUnit->totalParserStatusCount = parserStatusCount;
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();
}
@ -337,28 +345,13 @@ int QQmlTypeCompiler::rootObjectIndex() const
void QQmlTypeCompiler::setPropertyCaches(const QQmlPropertyCacheVector &caches)
{
compiledData->propertyCaches = caches;
m_propertyCaches = caches;
Q_ASSERT(caches.count() >= document->indexOfRootObject);
}
const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const
{
return compiledData->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;
return m_propertyCaches;
}
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
@ -376,11 +369,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
return &document->jsGenerator.stringTable;
}
void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject)
{
compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
}
void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
{
compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData;
@ -1324,11 +1312,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex())
, _componentIndex(-1)
, _objectIndexToIdInScope(0)
, resolvedTypes(typeCompiler->resolvedTypes())
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
, objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent())
{
}
@ -1351,7 +1336,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
if (targetType->metaObject() == &QQmlComponent::staticMetaObject)
continue;
} else if (tr->component) {
if (tr->component->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
if (tr->component->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
continue;
}
@ -1382,6 +1367,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
syntheticComponent->location = binding->valueLocation;
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
@ -1408,7 +1394,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
binding->value.objectIndex = 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.
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
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();
if (obj->inheritedTypeNameIndex == 0 && !cache)
continue;
@ -1439,7 +1424,7 @@ bool QQmlComponentAndAliasResolver::resolve()
continue;
}
componentRoots.append(i);
obj->flags |= QV4::CompiledData::Object::IsComponent;
if (obj->functionCount() > 0)
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)
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) {
const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
const QmlIR::Binding *rootBinding = component->firstBinding();
_componentIndex = i;
_idToObjectIndex.clear();
_objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
_objectsWithAliases.clear();
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
@ -1482,51 +1467,56 @@ bool QQmlComponentAndAliasResolver::resolve()
if (!resolveAliases())
return false;
component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
}
// Collect ids and aliases for root
_componentIndex = -1;
_idToObjectIndex.clear();
_objectIndexToIdInScope = objectIndexToIdForRoot;
_objectsWithAliases.clear();
collectIdsAndAliases(indexOfRootObject);
resolveAliases();
QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
// Implicit component insertion may have added objects and thus we also need
// to extend the symmetric propertyCaches.
compiler->setPropertyCaches(propertyCaches);
compiler->setComponentRoots(componentRoots);
return true;
}
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{
const QmlIR::Object *obj = qmlObjects->at(objectIndex);
QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idIndex != 0) {
if (_idToObjectIndex.contains(obj->idIndex)) {
if (obj->idNameIndex != 0) {
if (_idToObjectIndex.contains(obj->idNameIndex)) {
recordError(obj->locationOfIdProperty, tr("id is not unique"));
return false;
}
_idToObjectIndex.insert(obj->idIndex, objectIndex);
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
obj->id = _idToObjectIndex.count();
_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
}
if (obj->aliasCount() > 0)
_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) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
continue;
// Stop at Component boundary
if (std::binary_search(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex))
continue;
if (!collectIdsAndAliases(binding->value.objectIndex))
return false;
}
@ -1555,8 +1545,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
}
Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved));
alias->flags |= QV4::CompiledData::Alias::Resolved;
Q_ASSERT(_objectIndexToIdInScope->contains(targetObjectIndex));
alias->targetObjectId = _objectIndexToIdInScope->value(targetObjectIndex);
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
alias->targetObjectId = targetObject->id;
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
@ -1668,6 +1659,126 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
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)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
@ -1675,9 +1786,6 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
, resolvedTypes(*typeCompiler->resolvedTypes())
, customParsers(typeCompiler->customParserCache())
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, customParserBindingsPerObject(typeCompiler->customParserBindings())
, _seenObjectWithId(false)
{
}
@ -1686,7 +1794,6 @@ bool QQmlPropertyValidator::validate()
_bindingPropertyDataPerObject.resize(qmlUnit->nObjects);
if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
return false;
compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject);
compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject);
return true;
}
@ -1717,10 +1824,8 @@ struct BindingFinder
bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{
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);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
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);
}
QBitArray customParserBindings(obj->nBindings);
QBitArray deferredBindings;
QmlIR::PropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
@ -1790,13 +1892,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
customParserBindings.setBit(i);
continue;
}
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
customParserBindings.setBit(i);
continue;
}
}
@ -1845,24 +1945,10 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
return false;
}
bool seenSubObjectWithId = false;
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));
qSwap(_seenObjectWithId, seenSubObjectWithId);
if (!subObjectValid)
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.
@ -1947,7 +2033,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
} else {
if (customParser) {
customBindings << binding;
customParserBindings.setBit(i);
continue;
}
if (bindingToDefaultProperty) {
@ -1958,7 +2043,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
}
}
if (obj->idIndex) {
if (obj->idNameIndex) {
bool notInRevision = false;
collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
}
@ -1972,7 +2057,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
customParser->validator = 0;
customParser->engine = 0;
customParser->imports = (QQmlImports*)0;
customParserBindingsPerObject->insert(objectIndex, customParserBindings);
const QList<QQmlError> parserErrors = customParser->errors();
if (!parserErrors.isEmpty()) {
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;
return true;
@ -2328,7 +2409,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
}
}
return true;
} else if (isComponent(binding->value.objectIndex)) {
} else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
return true;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return true;
@ -2365,7 +2446,6 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
: QQmlCompilePass(typeCompiler)
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
, resolvedTypes(*typeCompiler->resolvedTypes())
, customParsers(typeCompiler->customParserCache())
, qmlObjects(*typeCompiler->qmlObjects())
@ -2376,46 +2456,40 @@ QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::
bool QQmlJSCodeGenerator::generateCodeForComponents()
{
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent();
for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd();
component != end; ++component) {
if (!compileComponent(component.key(), component.value()))
const QVector<quint32> &componentRoots = compiler->componentRoots();
for (int i = 0; i < componentRoots.count(); ++i) {
if (!compileComponent(componentRoots.at(i)))
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 *component = qmlObjects.at(contextObject);
Q_ASSERT(component->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
const QmlIR::Object *obj = qmlObjects.at(contextObject);
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);
contextObject = componentBinding->value.objectIndex;
}
QmlIR::JSCodeGen::ObjectIdMapping idMapping;
if (!objectIndexToId.isEmpty()) {
idMapping.reserve(objectIndexToId.count());
idMapping.reserve(obj->namedObjectsInComponent.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();
idIt != end; ++idIt) {
QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
if (tref && tref->isFullyDynamicType)
m.type = 0;
const int objectIndex = idIt.key();
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;
}
idMapping << m;
}
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)
{
if (isComponent(objectIndex))
QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->flags & QV4::CompiledData::Object::IsComponent)
return true;
QmlIR::Object *object = qmlObjects.at(objectIndex);
if (object->functionsAndExpressions->count > 0) {
QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex).data();
v4CodeGen->beginObjectScope(scopeObject);
@ -2451,8 +2525,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
}
QQmlJS::MemoryPool *pool = compiler->memoryPool();
object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >();
object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
}
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)
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);
if (simplifyBinding(irFunction, binding)) {
irFunctionsToRemove.append(irFunctionIndex);
@ -2838,10 +2911,8 @@ void QQmlIRFunctionCleanser::clean()
}
foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
if (!obj->runtimeFunctionIndices)
continue;
for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i)
(*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;
void setPropertyCaches(const QQmlPropertyCacheVector &caches);
const QQmlPropertyCacheVector &propertyCaches() const;
QHash<int, int> *objectIndexToIdForRoot();
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
QHash<int, QBitArray> *customParserBindings();
void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
@ -119,9 +117,14 @@ private:
QQmlEnginePrivate *engine;
QQmlCompiledData *compiledData;
QQmlTypeData *typeData;
QQmlRefPointer<QQmlTypeNameCache> importCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
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
@ -268,20 +271,31 @@ protected:
const int indexOfRootObject;
// indices of the objects that are actually Component {}
QVector<int> componentRoots;
// indices of objects that are the beginning of a new component
// scope. This is sorted and used for binary search.
QVector<quint32> componentBoundaries;
QVector<quint32> componentRoots;
int _componentIndex;
QHash<int, int> _idToObjectIndex;
QHash<int, int> *_objectIndexToIdInScope;
QList<int> _objectsWithAliases;
QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
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
@ -300,8 +314,6 @@ private:
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 isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
QQmlEnginePrivate *enginePrivate;
@ -309,12 +321,8 @@ private:
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
const QHash<int, QQmlCustomParser*> &customParsers;
const QQmlPropertyCacheVector &propertyCaches;
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, QBitArray> *customParserBindingsPerObject;
// collected state variables, essentially write-only
mutable QHash<int, QBitArray> _deferredBindingsPerObject;
mutable bool _seenObjectWithId;
mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject;
};
@ -327,12 +335,9 @@ public:
bool generateCodeForComponents();
private:
bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId);
bool compileComponent(int componentRoot);
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, QQmlCustomParser*> &customParsers;
const QList<QmlIR::Object*> &qmlObjects;

View File

@ -47,6 +47,7 @@
#include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qqmltypeloader_p.h>
#endif
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
@ -67,6 +68,9 @@ CompilationUnit::CompilationUnit()
, runtimeLookups(0)
, runtimeRegularExpressions(0)
, runtimeClasses(0)
, totalBindingsCount(0)
, totalParserStatusCount(0)
, totalObjectCount(0)
{}
CompilationUnit::~CompilationUnit()
@ -165,6 +169,18 @@ void CompilationUnit::unlink()
{
if (engine)
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;
free(runtimeStrings);
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
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)

View File

@ -60,11 +60,22 @@
#include <private/qv4executableallocator_p.h>
#include <private/qqmlrefcount_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
class QQmlPropertyCache;
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 {
struct Document;
@ -234,7 +245,9 @@ struct Q_QML_PRIVATE_EXPORT Binding
InitializerForReadOnlyDeclaration = 0x8,
IsResolvedEnum = 0x10,
IsListItem = 0x20,
IsBindingToAlias = 0x40
IsBindingToAlias = 0x40,
IsDeferredBinding = 0x80,
IsCustomParserBinding = 0x100,
};
quint32 flags : 16;
@ -391,13 +404,22 @@ struct Alias {
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
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
quint32 inheritedTypeNameIndex;
quint32 idIndex;
qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object
quint32 idNameIndex;
qint32 id : 16;
qint32 flags : 15;
quint32 defaultPropertyIsAlias : 1;
qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint32 nFunctions;
quint32 offsetToFunctions;
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 nBindings;
quint32 offsetToBindings;
quint32 nNamedObjectsInComponent;
quint32 offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
// Function[]
@ -415,7 +439,7 @@ struct Object
// Signal[]
// 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)
+ nFunctions * sizeof(quint32)
@ -423,6 +447,7 @@ struct Object
+ nAliases * sizeof(Alias)
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
+ 0x7
) & ~0x7;
}
@ -453,6 +478,11 @@ struct Object
const uint offset = offsetTable[idx];
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
@ -641,11 +671,29 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QVector<QV4::Function *> runtimeFunctions;
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
// property data when initializing bindings, avoiding expensive
// lookups by string (property name).
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);
void unlink();

View File

@ -71,13 +71,13 @@ public:
virtual ~QQmlAbstractProfilerAdapter() {}
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 stopProfiling();
void reportData() { emit dataRequested(); }
void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
@ -94,7 +94,7 @@ signals:
void profilingDisabled();
void profilingDisabledWhileWaiting();
void dataRequested();
void dataRequested(bool trackLocations);
void referenceTimeKnown(const QElapsedTimer &timer);
protected:

View File

@ -59,19 +59,21 @@ void QQmlProfiler::startProfiling(quint64 features)
void QQmlProfiler::stopProfiling()
{
featuresEnabled = false;
reportData();
reportData(true);
m_locations.clear();
}
void QQmlProfiler::reportData()
void QQmlProfiler::reportData(bool trackLocations)
{
LocationHash resolved;
resolved.reserve(m_locations.size());
for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it)
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
// a good idea to release the memory before creating the packets to be sent.
m_locations.clear();
for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
if (!trackLocations || !it->sent) {
resolved.insert(it.key(), it.value());
if (trackLocations)
it->sent = true;
}
}
QVector<QQmlProfilerData> 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
// be available anymore when we send the data.
struct RefLocation : public Location {
RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr)
RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false)
{}
RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) :
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,
const QString &type) :
Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
locationType(Creating), ref(ref)
locationType(Creating), ref(ref), sent(false)
{}
RefLocation(QQmlBoundSignalExpression *ref) :
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref)
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref), sent(false)
{}
RefLocation(QQmlDataBlob *ref) :
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref)
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref),
sent(false)
{}
bool isValid() const
@ -175,6 +176,7 @@ public:
RangeType locationType;
QQmlRefPointer<QQmlRefCount> ref;
bool sent;
};
typedef QHash<quintptr, Location> LocationHash;
@ -217,11 +219,6 @@ public:
location = RefLocation(expression);
}
void startCreating()
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating));
}
void startCreating(const QV4::CompiledData::Object *obj)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
@ -233,10 +230,6 @@ public:
const QUrl &url, const QString &type)
{
quintptr locationId(id(obj));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeLocation | 1 << RangeData),
Creating, locationId));
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(ref, url, obj, type);
@ -261,7 +254,7 @@ public:
public slots:
void startProfiling(quint64 features);
void stopProfiling();
void reportData();
void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
@ -363,9 +356,10 @@ private:
class QQmlObjectCreationProfiler {
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()

View File

@ -64,12 +64,33 @@ IdentifierHashData::IdentifierHashData(int numBits)
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)
{
d = new IdentifierHashData(3);
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)
{

View File

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

View File

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

View File

@ -134,6 +134,11 @@ public:
return *this;
}
Function *function() const
{
return m_function;
}
FunctionLocation resolveLocation() const;
FunctionCallProperties properties() const;
@ -165,6 +170,46 @@ class Q_QML_EXPORT Profiler : public QObject {
Q_OBJECT
Q_DISABLE_COPY(Profiler)
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);
size_t trackAlloc(size_t size, MemoryType type)
@ -186,7 +231,7 @@ public:
public slots:
void stopProfiling();
void startProfiling(quint64 features);
void reportData();
void reportData(bool trackLocations);
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
@ -199,6 +244,7 @@ private:
QElapsedTimer m_timer;
QVector<FunctionCall> m_data;
QVector<MemoryAllocationProperties> m_memory_data;
QHash<quintptr, SentMarker> m_sentLocations;
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::FunctionCall, 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
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)

View File

@ -68,7 +68,7 @@
#include <pthread_np.h>
#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;
@ -108,29 +108,20 @@ using namespace QV4;
struct MemoryManager::Data
{
const size_t pageSize;
struct ChunkHeader {
Heap::Base freeItems;
ChunkHeader *nextNonFull;
char *itemStart;
char *itemEnd;
int itemSize;
unsigned itemSize;
};
bool gcBlocked;
bool aggressiveGC;
bool gcStats;
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;
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 unmanagedHeapSizeGCLimit;
@ -147,24 +138,39 @@ struct MemoryManager::Data
LargeItem *largeItems;
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:
#ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters;
#endif // DETAILED_MM_STATS
Data()
: gcBlocked(false)
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
, gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
: pageSize(WTF::pageSize())
, engine(0)
, totalItems(0)
, totalAlloc(0)
, maxShift(maxShiftValue())
, maxChunkSize(maxChunkSizeValue())
, unmanagedHeapSize(0)
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
, largeItems(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(nChunks, 0, sizeof(nChunks));
@ -174,7 +180,7 @@ struct MemoryManager::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);
i->deallocate();
}
@ -198,7 +204,7 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
// qDebug("chunk @ %p, in use: %s, mark bit: %s",
// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
Q_ASSERT((qintptr) item % 16 == 0);
Q_ASSERT(qintptr(item) % 16 == 0);
if (m->isMarked()) {
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)
shift = m_d->maxShift;
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(
Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage),
OSAllocator::JSGCHeapPages);
m_d->heapChunks.append(allocation);
m_d->heapChunks.push_back(allocation);
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->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);
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->totalItems += int(increase);
#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];
memset(itemsInUse, 0, sizeof(itemsInUse));
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());
chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize);
}
QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
for (int i = 0; i < m_d->heapChunks.size(); ++i) {
std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
Q_ASSERT(chunkIter != m_d->heapChunks.end());
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
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.
if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
@ -561,7 +570,7 @@ void MemoryManager::runGC()
t.restart();
const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem();
int chunksBefore = m_d->heapChunks.size();
size_t chunksBefore = m_d->heapChunks.size();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
@ -589,11 +598,11 @@ void MemoryManager::runGC()
size_t MemoryManager::getUsedMem() const
{
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());
for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
Q_ASSERT((qintptr) item % 16 == 0);
Q_ASSERT(qintptr(item) % 16 == 0);
if (m->inUse())
usedMem += header->itemSize;
}
@ -604,7 +613,7 @@ size_t MemoryManager::getUsedMem() const
size_t MemoryManager::getAllocatedMem() const
{
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();
return total;
}

View File

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

View File

@ -80,10 +80,6 @@ class QQmlComponent;
class QQmlContext;
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
class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
{
@ -93,8 +89,6 @@ public:
QQmlEngine *engine;
QQmlTypeNameCache *importCache;
int metaTypeId;
int listMetaTypeId;
bool isRegisteredWithEngine;
@ -126,23 +120,7 @@ public:
// map from name index
QHash<int, TypeReference*> resolvedTypes;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(compilationUnit->data->indexOfRootObject).data(); }
QQmlPropertyCacheVector propertyCaches;
QList<QQmlScriptData *> scripts;
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(); }
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);
if (idx == -1) {
properties.add(name, data->idValueCount + d->propertyValues.count());
@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
return;
}
QV4::IdentifierHash<int> &properties = data->propertyNames();
QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
int idx = properties.value(name);
if (idx == -1) {
@ -523,7 +523,7 @@ QQmlContextData::QQmlContextData()
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(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),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0)
@ -760,15 +760,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj)
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
{
const QV4::IdentifierHash<int> &properties = propertyNames();
@ -804,21 +795,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
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()) {
propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle()));
for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend();
it != end; ++it) {
const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key());
const QString name = typeCompilationUnit->data->stringAt(obj->idIndex);
propertyNameCache.add(name, it.value());
}
objectIndexToId.clear();
if (typeCompilationUnit)
propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
else
propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine));
}
return propertyNameCache;
}
QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames()
{
propertyNames();
propertyNameCache.detach();
return propertyNameCache;
}
QUrl QQmlContextData::url() const
{
if (typeCompilationUnit)

View File

@ -151,9 +151,15 @@ public:
// Compilation unit for contexts that belong to a compiled type.
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;
QV4::IdentifierHash<int> &propertyNames() const;
const QV4::IdentifierHash<int> &propertyNames() const;
QV4::IdentifierHash<int> &detachedPropertyNames();
// Context object
QObject *contextObject;
@ -201,7 +207,6 @@ public:
ContextGuard *idValues;
int idValueCount;
void setIdProperty(int, QObject *);
void setIdPropertyData(const QHash<int, int> &);
// Linked contexts. this owns linkedContext.
QQmlContextData *linkedContext;

View File

@ -82,7 +82,7 @@ public:
Flags flags() const { return m_flags; }
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; }

View File

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

View File

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

View File

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

View File

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

View File

@ -452,7 +452,12 @@ QQmlPropertyCache *QQmlPropertyCache::parent() const
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
{
if (_parent == newParent)
return;
if (_parent)
_parent->release();
_parent = newParent;
_parent->addref();
}
// 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 componentcomplete;
QQmlRefPointer<QQmlCompiledData> cdata;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
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 =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
p->cdata = cdata;
p->compilationUnit = compilationUnit;
p->bindings = bindings;
}
@ -278,7 +278,7 @@ void QQmlConnections::connectSignals()
QQmlData *ddata = QQmlData::get(this);
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) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
@ -291,7 +291,7 @@ void QQmlConnections::connectSignals()
QQmlBoundSignalExpression *expression = ctxtdata ?
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);
d->boundsignals += signal;
} else {

View File

@ -99,7 +99,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
{
public:
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
}
if (!qmlUnit->stringAt(target->idIndex).isEmpty()) {
if (!qmlUnit->stringAt(target->idNameIndex).isEmpty()) {
error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
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);
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;

View File

@ -188,7 +188,7 @@ public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
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:
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);
QPacket stream(d->connection->currentDataStreamVersion());
stream << record << engineId << d->features << flushInterval;
stream << record << engineId << d->features << flushInterval << true;
sendMessage(stream.data());
}
@ -205,7 +205,7 @@ inline QQmlProfilerDefinitions::ProfileFeature featureFromRangeType(
void QQmlProfilerClient::messageReceived(const QByteArray &data)
{
Q_D(const QQmlProfilerClient);
Q_D(QQmlProfilerClient);
QPacket stream(d->connection->currentDataStreamVersion(), data);
@ -333,12 +333,25 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
!(d->features & one << featureFromRangeType(rangeType)))
return;
qint64 typeId = 0;
if (messageType == QQmlProfilerDefinitions::RangeStart) {
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) {
QString data;
stream >> data;
rangeData(rangeType, time, data);
if (!stream.atEnd()) {
stream >> typeId;
d->types[typeId].name = data;
}
} else if (messageType == QQmlProfilerDefinitions::RangeLocation) {
QQmlEventLocation location;
stream >> location.filename >> location.line;
@ -347,6 +360,10 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
stream >> location.column;
rangeLocation(rangeType, time, location);
if (!stream.atEnd()) {
stream >> typeId;
d->types[typeId].location = location;
}
} else if (messageType == QQmlProfilerDefinitions::RangeEnd) {
rangeEnd(rangeType, time);
} else {

View File

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

View File

@ -415,4 +415,26 @@ Item {
\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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2028,7 +2028,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
}
}
void QQuickWindowPrivate::flushDelayedTouchEvent()
void QQuickWindowPrivate::flushFrameSynchronousEvents()
{
if (delayedTouch) {
deliverDelayedTouchEvent();
@ -2039,6 +2039,17 @@ void QQuickWindowPrivate::flushDelayedTouchEvent()
if (ut && ut->hasStartAnimationPending())
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)

View File

@ -160,7 +160,7 @@ public:
void reallyDeliverTouchEvent(QTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *);
void deliverDelayedTouchEvent();
void flushDelayedTouchEvent();
void flushFrameSynchronousEvents();
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);
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;
if (!data.grabOnly) {
cd->flushDelayedTouchEvent();
cd->flushFrameSynchronousEvents();
// Event delivery/processing triggered the window to be deleted or stop rendering.
if (!m_windows.contains(window))
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);
}
foreach (Node *n, m_nodes.values())
for (Node *n : qAsConst(m_nodes))
m_nodeAllocator.release(n);
// Remaining elements...

View File

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

View File

@ -1142,7 +1142,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
}
// 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
w = windowFor(m_windows, 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.
if (!windowData(window))
return;

View File

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

View File

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

View File

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

View File

@ -202,7 +202,7 @@ public:
QPointer<QObject> object;
QList<const QV4::CompiledData::Binding *> bindings;
QQmlRefPointer<QQmlCompiledData> cdata;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
bool decoded : 1;
bool restore : 1;
@ -258,7 +258,7 @@ void QQuickPropertyChangesPrivate::decode()
return;
foreach (const QV4::CompiledData::Binding *binding, bindings)
decodeBinding(QString(), cdata->compilationUnit->data, binding);
decodeBinding(QString(), compilationUnit->data, binding);
bindings.clear();
@ -288,7 +288,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
handler->property = prop;
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;
return;
}
@ -338,12 +338,12 @@ void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::Unit *
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 =
static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj));
p->bindings = bindings;
p->cdata = cdata;
p->compilationUnit = compilationUnit;
p->decoded = false;
}
@ -456,7 +456,7 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
QQmlBinding *newBinding = 0;
if (e.id != QQmlBinding::Invalid) {
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);
}
// 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);
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()
{
foreach(QSmoothedAnimation* ease, activeAnimations.values()){
for (QSmoothedAnimation *ease : qAsConst(activeAnimations)) {
ease->maximumEasingTime = anim->maximumEasingTime;
ease->reversingMode = anim->reversingMode;
ease->velocity = anim->velocity;
@ -444,7 +444,8 @@ QAbstractAnimationJob* QQuickSmoothedAnimation::transition(QQuickStateActions &a
anims.insert(ease);
}
foreach (QSmoothedAnimation *ease, d->activeAnimations.values()){
const auto copy = d->activeAnimations;
for (QSmoothedAnimation *ease : copy) {
if (!anims.contains(ease)) {
ease->clearTemplate();
d->activeAnimations.remove(ease->target);

View File

@ -585,7 +585,8 @@ QAbstractAnimationJob* QQuickSpringAnimation::transition(QQuickStateActions &act
animation->restart();
anims.insert(animation);
}
foreach (QSpringAnimation *anim, d->activeAnimations.values()){
const auto copy = d->activeAnimations;
for (QSpringAnimation *anim : copy) {
if (!anims.contains(anim)) {
anim->clearTemplate();
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);
Q_ASSERT(customBinding);
customBinding->cdata = cdata;
customBinding->compilationUnit = compilationUnit;
customBinding->bindings = bindings;
}
@ -123,14 +123,14 @@ void CustomBinding::componentComplete()
Q_ASSERT(m_target);
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;
QQmlContextData *context = QQmlContextData::get(qmlContext(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);
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);
Q_ASSERT(o);

View File

@ -733,14 +733,14 @@ class MyCustomParserTypeParser : public QQmlCustomParser
{
public:
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
{
public:
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
@ -1170,7 +1170,7 @@ public:
void setTarget(QObject *newTarget) { m_target = newTarget; }
QPointer<QObject> m_target;
QQmlRefPointer<QQmlCompiledData> cdata;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding*> bindings;
QByteArray m_bindingData;
};
@ -1178,7 +1178,7 @@ public:
class CustomBindingParser : public QQmlCustomParser
{
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
@ -1224,7 +1224,7 @@ private:
class SimpleObjectCustomParser : public QQmlCustomParser
{
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

View File

@ -108,6 +108,7 @@ private slots:
void bindTypeToJSValue();
void customParserTypes();
void rootAsQmlComponent();
void rootItemIsComponent();
void inlineQmlComponents();
void idProperty();
void autoNotifyConnection();
@ -1195,6 +1196,19 @@ void tst_qqmllanguage::rootAsQmlComponent()
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
void tst_qqmllanguage::inlineQmlComponents()
{

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