aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp9
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h1
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp11
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h65
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp85
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp4
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h70
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp455
-rw-r--r--src/qml/compiler/qv4bytecodehandler_p.h10
-rw-r--r--src/qml/compiler/qv4codegen.cpp140
-rw-r--r--src/qml/compiler/qv4compileddata.cpp7
-rw-r--r--src/qml/compiler/qv4compileddata_p.h21
-rw-r--r--src/qml/compiler/qv4compiler.cpp15
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp24
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h4
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp75
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h73
-rw-r--r--src/qml/configure.json9
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml2
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs (renamed from src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.js)4
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs (renamed from src/qml/doc/snippets/qml/integrating-javascript/includejs/script.js)2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc3
-rw-r--r--src/qml/doc/src/javascript/imports.qdoc65
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc52
-rw-r--r--src/qml/doc/src/statemachine.qdoc4
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp66
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h6
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp26
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h15
-rw-r--r--src/qml/jit/qv4baselinejit.cpp92
-rw-r--r--src/qml/jit/qv4baselinejit_p.h65
-rw-r--r--src/qml/jsruntime/jsruntime.pri20
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4engine.cpp41
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp10
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp67
-rw-r--r--src/qml/jsruntime/qv4function_p.h52
-rw-r--r--src/qml/jsruntime/qv4functiontable_noop.cpp65
-rw-r--r--src/qml/jsruntime/qv4functiontable_p.h75
-rw-r--r--src/qml/jsruntime/qv4functiontable_unix.cpp99
-rw-r--r--src/qml/jsruntime/qv4functiontable_win64.cpp153
-rw-r--r--src/qml/jsruntime/qv4global_p.h14
-rw-r--r--src/qml/jsruntime/qv4math_p.h27
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp50
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h2
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp153
-rw-r--r--src/qml/parser/parser.pri3
-rw-r--r--src/qml/parser/qqmljs.g8
-rw-r--r--src/qml/parser/qqmljsast.cpp4
-rw-r--r--src/qml/parser/qqmljsast_p.h4
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h26
-rw-r--r--src/qml/parser/qqmljsastvisitor.cpp4
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h4
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp4
-rw-r--r--src/qml/parser/qqmljsengine_p.h8
-rw-r--r--src/qml/parser/qqmljsglobal_p.h4
-rw-r--r--src/qml/parser/qqmljskeywords_p.h4
-rw-r--r--src/qml/parser/qqmljslexer_p.h4
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h81
-rw-r--r--src/qml/parser/qqmljssourcelocation_p.h87
-rw-r--r--src/qml/qml.pro1
-rw-r--r--src/qml/qml/qml.pri4
-rw-r--r--src/qml/qml/qqml.h3
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.h4
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h1
-rw-r--r--src/qml/qml/qqmlbinding.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp4
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmlexpression.cpp1
-rw-r--r--src/qml/qml/qqmlextensioninterface.h4
-rw-r--r--src/qml/qml/qqmlfile.cpp17
-rw-r--r--src/qml/qml/qqmlglobal_p.h10
-rw-r--r--src/qml/qml/qqmlmetatype.cpp20
-rw-r--r--src/qml/qml/qqmlmetatype_p.h2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp89
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp108
-rw-r--r--src/qml/qml/qqmltypeloader.cpp14
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp5
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h1
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp23
-rw-r--r--src/qml/qmldirparser/qmldirparser.pri11
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp (renamed from src/qml/qml/qqmldirparser.cpp)2
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h (renamed from src/qml/qml/qqmldirparser_p.h)4
-rw-r--r--src/qml/qmldirparser/qqmlerror.cpp (renamed from src/qml/qml/qqmlerror.cpp)16
-rw-r--r--src/qml/qmldirparser/qqmlerror.h (renamed from src/qml/qml/qqmlerror.h)4
-rw-r--r--src/qml/qmldirparser/qqmlsourcecoordinate_p.h72
-rw-r--r--src/qml/qtqmlglobal.h1
-rw-r--r--src/qml/types/qqmllistmodel.cpp2
-rw-r--r--src/qml/types/qquickworkerscript.cpp2
93 files changed, 1894 insertions, 1122 deletions
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index b01b2f3b36..a27c9195dd 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -72,7 +72,7 @@ public:
QAbstractAnimationJob *firstChild() const { return m_firstChild; }
QAbstractAnimationJob *lastChild() const { return m_lastChild; }
- void clear();
+ virtual void clear();
//called by QAbstractAnimationJob
virtual void uncontrolledAnimationFinished(QAbstractAnimationJob *animation);
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index 22e20d9268..d98546122f 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -204,6 +204,15 @@ int QSequentialAnimationGroupJob::duration() const
return ret;
}
+void QSequentialAnimationGroupJob::clear()
+{
+ m_previousLoop = 0;
+ QAnimationGroupJob::clear();
+
+ // clear() should call removeAnimation(), which will clear m_currentAnimation, eventually.
+ Q_ASSERT(m_currentAnimation == nullptr);
+}
+
void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
{
if (!m_currentAnimation)
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 13f9806be1..34e8fe1e08 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -68,6 +68,7 @@ public:
int duration() const override;
QAbstractAnimationJob *currentAnimation() const { return m_currentAnimation; }
+ void clear() override;
protected:
void updateCurrentTime(int) override;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 868f600a10..6e077ec44c 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1082,6 +1082,9 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value));
}
+ } else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
+ binding->type = QV4::CompiledData::Binding::Type_Null;
+ binding->value.nullMarker = 0;
}
}
@@ -1627,7 +1630,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
uint nextOffset = objectOffset + objectOffsetTableSize;
for (Object *o : qAsConst(output.objects)) {
objectOffsets.insert(o, nextOffset);
- nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
+ nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size());
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@@ -1702,7 +1705,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
objectToWrite->offsetToBindings = nextOffset;
nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
- objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.count;
+ objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.size();
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
@@ -1774,7 +1777,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
}
quint32_le *namedObjectInComponentPtr = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
- for (int i = 0; i < o->namedObjectsInComponent.count; ++i) {
+ for (int i = 0; i < o->namedObjectsInComponent.size(); ++i) {
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
}
}
@@ -2105,8 +2108,6 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
f->location = compiledFunction->location;
f->nameIndex = compiledFunction->nameIndex;
- const QString name = unit->stringAtInternal(compiledFunction->nameIndex);
-
f->formals.allocate(pool, int(compiledFunction->nFormals));
const quint32_le *formalNameIdx = compiledFunction->formalsTable();
for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 56724bcda5..22bc2d2953 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -198,69 +198,6 @@ struct PoolList
Iterator end() { return Iterator(nullptr); }
};
-template <typename T>
-class FixedPoolArray
-{
- T *data;
-public:
- int count = 0;
-
- FixedPoolArray()
- : data(nullptr)
-
- {}
-
- void allocate(QQmlJS::MemoryPool *pool, int size)
- {
- count = size;
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
- }
-
- void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
- {
- count = vector.count();
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
-
- if (QTypeInfo<T>::isComplex) {
- for (int i = 0; i < count; ++i)
- new (data + i) T(vector.at(i));
- } else {
- memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
- }
- }
-
- 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];
- }
-
- T &operator[](int index) {
- Q_ASSERT(index >= 0 && index < count);
- return data[index];
- }
-
-
- int indexOf(const T &value) const {
- for (int i = 0; i < count; ++i)
- if (data[i] == value)
- return i;
- return -1;
- }
-
- const T *begin() const { return data; }
- const T *end() const { return data + count; }
-};
-
struct Object;
struct EnumValue : public QV4::CompiledData::EnumValue
@@ -410,7 +347,7 @@ public:
FixedPoolArray<int> runtimeFunctionIndices;
FixedPoolArray<quint32> namedObjectsInComponent;
- int namedObjectsInComponentCount() const { return namedObjectsInComponent.count; }
+ int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index 5e821518a4..d20efe616b 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -352,30 +352,45 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
return noError;
}
+ auto warnOrError = [&](const QString &error) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ QQmlError warning;
+ warning.setUrl(compilationUnit->url());
+ warning.setLine(binding->valueLocation.line);
+ warning.setColumn(binding->valueLocation.column);
+ warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
+ "is deprecated. This will become a compile error in "
+ "future versions of Qt."));
+ enginePrivate->warning(warning);
+ return noError;
+ }
+ return QQmlCompileError(binding->valueLocation, error);
+ };
+
switch (property->propType()) {
case QMetaType::QVariant:
break;
case QVariant::String: {
if (!binding->evaluatesToString()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string expected"));
+ return warnOrError(tr("Invalid property assignment: string expected"));
}
}
break;
case QVariant::StringList: {
if (!binding->evaluatesToString()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or string list expected"));
+ return warnOrError(tr("Invalid property assignment: string or string list expected"));
}
}
break;
case QVariant::ByteArray: {
if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: byte array expected"));
+ return warnOrError(tr("Invalid property assignment: byte array expected"));
}
}
break;
case QVariant::Url: {
if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url expected"));
+ return warnOrError(tr("Invalid property assignment: url expected"));
}
}
break;
@@ -385,7 +400,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
if (double(uint(d)) == d)
return noError;
}
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected"));
+ return warnOrError(tr("Invalid property assignment: unsigned int expected"));
}
break;
case QVariant::Int: {
@@ -394,18 +409,18 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
if (double(int(d)) == d)
return noError;
}
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int expected"));
+ return warnOrError(tr("Invalid property assignment: int expected"));
}
break;
case QMetaType::Float: {
if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
case QVariant::Double: {
if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected"));
+ return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
@@ -413,7 +428,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: color expected"));
+ return warnOrError(tr("Invalid property assignment: color expected"));
}
}
break;
@@ -422,7 +437,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: date expected"));
+ return warnOrError(tr("Invalid property assignment: date expected"));
}
}
break;
@@ -430,7 +445,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: time expected"));
+ return warnOrError(tr("Invalid property assignment: time expected"));
}
}
break;
@@ -438,7 +453,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: datetime expected"));
+ return warnOrError(tr("Invalid property assignment: datetime expected"));
}
}
break;
@@ -447,7 +462,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
@@ -455,7 +470,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
@@ -463,7 +478,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
@@ -471,7 +486,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected"));
+ return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
@@ -479,7 +494,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
+ return warnOrError(tr("Invalid property assignment: rect expected"));
}
}
break;
@@ -487,13 +502,13 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
bool ok = false;
QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected"));
+ return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
case QVariant::Bool: {
if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: boolean expected"));
+ return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
break;
@@ -503,7 +518,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float yp;
} vec;
if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected"));
+ return warnOrError(tr("Invalid property assignment: 2D vector expected"));
}
}
break;
@@ -514,7 +529,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float zy;
} vec;
if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected"));
+ return warnOrError(tr("Invalid property assignment: 3D vector expected"));
}
}
break;
@@ -526,7 +541,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float wp;
} vec;
if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected"));
+ return warnOrError(tr("Invalid property assignment: 4D vector expected"));
}
}
break;
@@ -538,17 +553,17 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float zp;
} vec;
if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected"));
+ return warnOrError(tr("Invalid property assignment: quaternion expected"));
}
}
break;
case QVariant::RegExp:
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
+ return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == qMetaTypeId<QList<qreal> >()) {
if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected"));
+ return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QList<int> >()) {
@@ -559,33 +574,36 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
ok = false;
}
if (!ok)
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected"));
+ return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (property->propType() == qMetaTypeId<QList<bool> >()) {
if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected"));
+ return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
if (binding->type != QV4::CompiledData::Binding::Type_String) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected"));
+ return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QList<QString> >()) {
if (!binding->evaluatesToString()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected"));
+ return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
}
break;
} else if (property->propType() == qMetaTypeId<QJSValue>()) {
break;
} else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
break;
+ } else if (property->isQObject()
+ && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ break;
}
// otherwise, try a custom type assignment
QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
if (!converter) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
+ return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
}
}
break;
@@ -671,12 +689,13 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
}
}
return noError;
- } else if (compilationUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
- return noError;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
} else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- return QQmlCompileError(binding->location, tr("Unexpected object assignment for property \"%1\"").arg(propertyName));
+ auto typeName = QMetaType::typeName(property->propType());
+ return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
+ .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
+ .arg(propertyName));
} else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else {
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index d0bca69b56..ea252a6013 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -180,6 +180,10 @@ void BytecodeGenerator::finalize(Compiler::Context *context)
context->code = code;
context->lineNumberMapping = lineNumbers;
+
+ for (const auto &li : _labelInfos) {
+ context->labelInfo.push_back(instructions.at(labels.at(li.labelIndex)).position);
+ }
}
int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, int offsetOfOffset) {
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 4f3dc27acc..1d0a57c536 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
#include <private/qv4instr_moth_p.h>
+#include <private/qv4compileddata_p.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +66,8 @@ namespace Moth {
class BytecodeGenerator {
public:
+ typedef CompiledData::Function::TraceInfoCount TraceInfoCount;
+
BytecodeGenerator(int line, bool debug)
: startLine(line), debugMode(debug) {}
@@ -161,6 +164,15 @@ public:
addInstructionHelper(Moth::Instr::Type(InstrT), genericInstr);
}
+ // Same as addInstruction, but also add a trace slot. Move only, because the instruction cannot
+ // be reused afterwards.
+ template<int InstrT>
+ void addTracingInstruction(InstrData<InstrT> data)
+ {
+ data.traceSlot = nextTraceInfo();
+ addInstruction(data);
+ }
+
Q_REQUIRED_RESULT Jump jump()
{
QT_WARNING_PUSH
@@ -172,14 +184,12 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpTrue()
{
- Instruction::JumpTrue data;
- return addJumpInstruction(data);
+ return addTracingJumpInstruction(Instruction::JumpTrue());
}
Q_REQUIRED_RESULT Jump jumpFalse()
{
- Instruction::JumpFalse data;
- return addJumpInstruction(data);
+ return addTracingJumpInstruction(Instruction::JumpFalse());
}
Q_REQUIRED_RESULT Jump jumpNotUndefined()
@@ -198,16 +208,16 @@ QT_WARNING_POP
{
Instruction::CmpStrictEqual cmp;
cmp.lhs = lhs;
- addInstruction(cmp);
- addJumpInstruction(Instruction::JumpTrue()).link(target);
+ addInstruction(std::move(cmp));
+ addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
}
void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
{
Instruction::CmpStrictNotEqual cmp;
cmp.lhs = lhs;
- addInstruction(cmp);
- addJumpInstruction(Instruction::JumpTrue()).link(target);
+ addInstruction(std::move(cmp));
+ addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
}
void setUnwindHandler(ExceptionHandler *handler)
@@ -248,6 +258,13 @@ QT_WARNING_POP
void finalize(Compiler::Context *context);
template<int InstrT>
+ Jump addTracingJumpInstruction(InstrData<InstrT> &&data)
+ {
+ data.traceSlot = nextTraceInfo();
+ return addJumpInstruction(data);
+ }
+
+ template<int InstrT>
Jump addJumpInstruction(const InstrData<InstrT> &data)
{
Instr genericInstr;
@@ -258,9 +275,9 @@ QT_WARNING_POP
void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
{
if (jumpOnFalse)
- addJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
+ addTracingJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
else
- addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
+ addTracingJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
void clearLastInstruction()
@@ -268,6 +285,32 @@ QT_WARNING_POP
lastInstrType = -1;
}
+ TraceInfoCount nextTraceInfo()
+ {
+ // If tracing is disabled, use slot 0 to unconditionally store all trace info
+ if (nTraceInfos == CompiledData::Function::NoTracing())
+ return TraceInfoCount(0);
+ return nTraceInfos++;
+ }
+
+ void setTracing(bool onoff, int argumentCount)
+ {
+ if (onoff)
+ nTraceInfos = argumentCount;
+ else
+ nTraceInfos = CompiledData::Function::NoTracing();
+ }
+
+ TraceInfoCount traceInfoCount() const
+ {
+ return nTraceInfos;
+ }
+
+ void addLoopStart(const Label &start)
+ {
+ _labelInfos.push_back({ start.index });
+ }
+
private:
friend struct Jump;
friend struct Label;
@@ -302,6 +345,13 @@ private:
int lastInstrType = -1;
Moth::Instr lastInstr;
+
+ TraceInfoCount nTraceInfos = TraceInfoCount(0);
+
+ struct LabelInfo {
+ int labelIndex;
+ };
+ std::vector<LabelInfo> _labelInfos;
};
}
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index e1fc0c6ee3..92b112c2fa 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -79,458 +79,3 @@ void ByteCodeHandler::decode(const char *code, uint len)
#undef DECODE_AND_DISPATCH
#undef DISPATCH_INSTRUCTION
-
-#define MOTH_UNUSED_ARGS0()
-#define MOTH_UNUSED_ARGS1(arg) \
- Q_UNUSED(arg);
-#define MOTH_UNUSED_ARGS2(arg1, arg2) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2);
-#define MOTH_UNUSED_ARGS3(arg1, arg2, arg3) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2); \
- Q_UNUSED(arg3);
-#define MOTH_UNUSED_ARGS4(arg1, arg2, arg3, arg4) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2); \
- Q_UNUSED(arg3); \
- Q_UNUSED(arg4);
-
-#define MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, ...) \
- MOTH_EXPAND_FOR_MSVC(MOTH_UNUSED_ARGS##nargs(__VA_ARGS__))
-
-#define MOTH_MARK_ARGS_UNUSED_INSTRUCTION(name, nargs, ...) \
- MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, __VA_ARGS__)
-
-#define COLLECTOR_BEGIN_INSTR(instr) \
- { \
- INSTR_##instr(MOTH_DECODE_WITH_BASE) \
- INSTR_##instr(MOTH_MARK_ARGS_UNUSED) \
- Q_UNUSED(base_ptr);
-
-#define COLLECTOR_END_INSTR(instr) \
- continue; \
- }
-
-std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint len)
-{
- MOTH_JUMP_TABLE;
-
- std::vector<int> labels;
-
- const auto addLabel = [&labels,len](int offset) {
- Q_ASSERT(offset >= 0 && offset < static_cast<int>(len));
- labels.push_back(offset);
- };
-
- const char *start = code;
- const char *end = code + len;
- while (code < end) {
- MOTH_DISPATCH()
- Q_UNREACHABLE();
-
- COLLECTOR_BEGIN_INSTR(LoadReg)
- COLLECTOR_END_INSTR(LoadReg)
-
- COLLECTOR_BEGIN_INSTR(StoreReg)
- COLLECTOR_END_INSTR(StoreReg)
-
- COLLECTOR_BEGIN_INSTR(MoveReg)
- COLLECTOR_END_INSTR(MoveReg)
-
- COLLECTOR_BEGIN_INSTR(LoadConst)
- COLLECTOR_END_INSTR(LoadConst)
-
- COLLECTOR_BEGIN_INSTR(LoadNull)
- COLLECTOR_END_INSTR(LoadNull)
-
- COLLECTOR_BEGIN_INSTR(LoadZero)
- COLLECTOR_END_INSTR(LoadZero)
-
- COLLECTOR_BEGIN_INSTR(LoadTrue)
- COLLECTOR_END_INSTR(LoadTrue)
-
- COLLECTOR_BEGIN_INSTR(LoadFalse)
- COLLECTOR_END_INSTR(LoadFalse)
-
- COLLECTOR_BEGIN_INSTR(LoadUndefined)
- COLLECTOR_END_INSTR(LoadUndefined)
-
- COLLECTOR_BEGIN_INSTR(LoadInt)
- COLLECTOR_END_INSTR(LoadInt)
-
- COLLECTOR_BEGIN_INSTR(MoveConst)
- COLLECTOR_END_INSTR(MoveConst)
-
- COLLECTOR_BEGIN_INSTR(LoadImport)
- COLLECTOR_END_INSTR(LoadImport)
-
- COLLECTOR_BEGIN_INSTR(LoadLocal)
- COLLECTOR_END_INSTR(LoadLocal)
-
- COLLECTOR_BEGIN_INSTR(StoreLocal)
- COLLECTOR_END_INSTR(StoreLocal)
-
- COLLECTOR_BEGIN_INSTR(LoadScopedLocal)
- COLLECTOR_END_INSTR(LoadScopedLocal)
-
- COLLECTOR_BEGIN_INSTR(StoreScopedLocal)
- COLLECTOR_END_INSTR(StoreScopedLocal)
-
- COLLECTOR_BEGIN_INSTR(LoadRuntimeString)
- COLLECTOR_END_INSTR(LoadRuntimeString)
-
- COLLECTOR_BEGIN_INSTR(MoveRegExp)
- COLLECTOR_END_INSTR(MoveRegExp)
-
- COLLECTOR_BEGIN_INSTR(LoadClosure)
- COLLECTOR_END_INSTR(LoadClosure)
-
- COLLECTOR_BEGIN_INSTR(LoadName)
- COLLECTOR_END_INSTR(LoadName)
-
- COLLECTOR_BEGIN_INSTR(LoadGlobalLookup)
- COLLECTOR_END_INSTR(LoadGlobalLookup)
-
- COLLECTOR_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- COLLECTOR_END_INSTR(LoadQmlContextPropertyLookup)
-
- COLLECTOR_BEGIN_INSTR(StoreNameSloppy)
- COLLECTOR_END_INSTR(StoreNameSloppy)
-
- COLLECTOR_BEGIN_INSTR(StoreNameStrict)
- COLLECTOR_END_INSTR(StoreNameStrict)
-
- COLLECTOR_BEGIN_INSTR(LoadElement)
- COLLECTOR_END_INSTR(LoadElement)
-
- COLLECTOR_BEGIN_INSTR(StoreElement)
- COLLECTOR_END_INSTR(StoreElement)
-
- COLLECTOR_BEGIN_INSTR(LoadProperty)
- COLLECTOR_END_INSTR(LoadProperty)
-
- COLLECTOR_BEGIN_INSTR(GetLookup)
- COLLECTOR_END_INSTR(GetLookup)
-
- COLLECTOR_BEGIN_INSTR(StoreProperty)
- COLLECTOR_END_INSTR(StoreProperty)
-
- COLLECTOR_BEGIN_INSTR(SetLookup)
- COLLECTOR_END_INSTR(SetLookup)
-
- COLLECTOR_BEGIN_INSTR(LoadSuperProperty)
- COLLECTOR_END_INSTR(LoadSuperProperty)
-
- COLLECTOR_BEGIN_INSTR(StoreSuperProperty)
- COLLECTOR_END_INSTR(StoreSuperProperty)
-
- COLLECTOR_BEGIN_INSTR(Yield)
- COLLECTOR_END_INSTR(Yield)
-
- COLLECTOR_BEGIN_INSTR(YieldStar)
- COLLECTOR_END_INSTR(YieldStar)
-
- COLLECTOR_BEGIN_INSTR(Resume)
- COLLECTOR_END_INSTR(Resume)
-
- COLLECTOR_BEGIN_INSTR(CallValue)
- COLLECTOR_END_INSTR(CallValue)
-
- COLLECTOR_BEGIN_INSTR(CallWithReceiver)
- COLLECTOR_END_INSTR(CallWithReceiver)
-
- COLLECTOR_BEGIN_INSTR(CallProperty)
- COLLECTOR_END_INSTR(CallProperty)
-
- COLLECTOR_BEGIN_INSTR(CallPropertyLookup)
- COLLECTOR_END_INSTR(CallPropertyLookup)
-
- COLLECTOR_BEGIN_INSTR(CallElement)
- COLLECTOR_END_INSTR(CallElement)
-
- COLLECTOR_BEGIN_INSTR(CallName)
- COLLECTOR_END_INSTR(CallName)
-
- COLLECTOR_BEGIN_INSTR(CallPossiblyDirectEval)
- COLLECTOR_END_INSTR(CallPossiblyDirectEval)
-
- COLLECTOR_BEGIN_INSTR(CallGlobalLookup)
- COLLECTOR_END_INSTR(CallGlobalLookup)
-
- COLLECTOR_BEGIN_INSTR(CallQmlContextPropertyLookup)
- COLLECTOR_END_INSTR(CallQmlContextPropertyLookup)
-
- COLLECTOR_BEGIN_INSTR(CallWithSpread)
- COLLECTOR_END_INSTR(CallWithSpread)
-
- COLLECTOR_BEGIN_INSTR(Construct)
- COLLECTOR_END_INSTR(Construct)
-
- COLLECTOR_BEGIN_INSTR(ConstructWithSpread)
- COLLECTOR_END_INSTR(ConstructWithSpread)
-
- COLLECTOR_BEGIN_INSTR(SetUnwindHandler)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(SetUnwindHandler)
-
- COLLECTOR_BEGIN_INSTR(UnwindDispatch)
- COLLECTOR_END_INSTR(UnwindDispatch)
-
- COLLECTOR_BEGIN_INSTR(UnwindToLabel)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(UnwindToLabel)
-
- COLLECTOR_BEGIN_INSTR(DeadTemporalZoneCheck)
- COLLECTOR_END_INSTR(DeadTemporalZoneCheck)
-
- COLLECTOR_BEGIN_INSTR(ThrowException)
- COLLECTOR_END_INSTR(ThrowException)
-
- COLLECTOR_BEGIN_INSTR(GetException)
- COLLECTOR_END_INSTR(HasException)
-
- COLLECTOR_BEGIN_INSTR(SetException)
- COLLECTOR_END_INSTR(SetExceptionFlag)
-
- COLLECTOR_BEGIN_INSTR(CreateCallContext)
- COLLECTOR_END_INSTR(CreateCallContext)
-
- COLLECTOR_BEGIN_INSTR(PushCatchContext)
- COLLECTOR_END_INSTR(PushCatchContext)
-
- COLLECTOR_BEGIN_INSTR(PushWithContext)
- COLLECTOR_END_INSTR(PushWithContext)
-
- COLLECTOR_BEGIN_INSTR(PushBlockContext)
- COLLECTOR_END_INSTR(PushBlockContext)
-
- COLLECTOR_BEGIN_INSTR(CloneBlockContext)
- COLLECTOR_END_INSTR(CloneBlockContext)
-
- COLLECTOR_BEGIN_INSTR(PushScriptContext)
- COLLECTOR_END_INSTR(PushScriptContext)
-
- COLLECTOR_BEGIN_INSTR(PopScriptContext)
- COLLECTOR_END_INSTR(PopScriptContext)
-
- COLLECTOR_BEGIN_INSTR(PopContext)
- COLLECTOR_END_INSTR(PopContext)
-
- COLLECTOR_BEGIN_INSTR(GetIterator)
- COLLECTOR_END_INSTR(GetIterator)
-
- COLLECTOR_BEGIN_INSTR(IteratorNext)
- COLLECTOR_END_INSTR(IteratorNext)
-
- COLLECTOR_BEGIN_INSTR(IteratorNextForYieldStar)
- COLLECTOR_END_INSTR(IteratorNextForYieldStar)
-
- COLLECTOR_BEGIN_INSTR(IteratorClose)
- COLLECTOR_END_INSTR(IteratorClose)
-
- COLLECTOR_BEGIN_INSTR(DestructureRestElement)
- COLLECTOR_END_INSTR(DestructureRestElement)
-
- COLLECTOR_BEGIN_INSTR(DeleteProperty)
- COLLECTOR_END_INSTR(DeleteProperty)
-
- COLLECTOR_BEGIN_INSTR(DeleteName)
- COLLECTOR_END_INSTR(DeleteName)
-
- COLLECTOR_BEGIN_INSTR(TypeofName)
- COLLECTOR_END_INSTR(TypeofName)
-
- COLLECTOR_BEGIN_INSTR(TypeofValue)
- COLLECTOR_END_INSTR(TypeofValue)
-
- COLLECTOR_BEGIN_INSTR(DeclareVar)
- COLLECTOR_END_INSTR(DeclareVar)
-
- COLLECTOR_BEGIN_INSTR(DefineArray)
- COLLECTOR_END_INSTR(DefineArray)
-
- COLLECTOR_BEGIN_INSTR(DefineObjectLiteral)
- COLLECTOR_END_INSTR(DefineObjectLiteral)
-
- COLLECTOR_BEGIN_INSTR(CreateClass)
- COLLECTOR_END_INSTR(CreateClass)
-
- COLLECTOR_BEGIN_INSTR(CreateMappedArgumentsObject)
- COLLECTOR_END_INSTR(CreateMappedArgumentsObject)
-
- COLLECTOR_BEGIN_INSTR(CreateUnmappedArgumentsObject)
- COLLECTOR_END_INSTR(CreateUnmappedArgumentsObject)
-
- COLLECTOR_BEGIN_INSTR(CreateRestParameter)
- COLLECTOR_END_INSTR(CreateRestParameter)
-
- COLLECTOR_BEGIN_INSTR(ConvertThisToObject)
- COLLECTOR_END_INSTR(ConvertThisToObject)
-
- COLLECTOR_BEGIN_INSTR(LoadSuperConstructor)
- COLLECTOR_END_INSTR(LoadSuperConstructor)
-
- COLLECTOR_BEGIN_INSTR(ToObject)
- COLLECTOR_END_INSTR(ToObject)
-
- COLLECTOR_BEGIN_INSTR(Jump)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(Jump)
-
- COLLECTOR_BEGIN_INSTR(JumpTrue)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(JumpTrue)
-
- COLLECTOR_BEGIN_INSTR(JumpFalse)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(JumpFalse)
-
- COLLECTOR_BEGIN_INSTR(JumpNoException)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(JumpNoException)
-
- COLLECTOR_BEGIN_INSTR(JumpNotUndefined)
- addLabel(code - start + offset);
- COLLECTOR_END_INSTR(JumpNotUndefined)
-
- COLLECTOR_BEGIN_INSTR(CmpEqNull)
- COLLECTOR_END_INSTR(CmpEqNull)
-
- COLLECTOR_BEGIN_INSTR(CmpNeNull)
- COLLECTOR_END_INSTR(CmpNeNull)
-
- COLLECTOR_BEGIN_INSTR(CmpEqInt)
- COLLECTOR_END_INSTR(CmpEq)
-
- COLLECTOR_BEGIN_INSTR(CmpNeInt)
- COLLECTOR_END_INSTR(CmpNeInt)
-
- COLLECTOR_BEGIN_INSTR(CmpEq)
- COLLECTOR_END_INSTR(CmpEq)
-
- COLLECTOR_BEGIN_INSTR(CmpNe)
- COLLECTOR_END_INSTR(CmpNe)
-
- COLLECTOR_BEGIN_INSTR(CmpGt)
- COLLECTOR_END_INSTR(CmpGt)
-
- COLLECTOR_BEGIN_INSTR(CmpGe)
- COLLECTOR_END_INSTR(CmpGe)
-
- COLLECTOR_BEGIN_INSTR(CmpLt)
- COLLECTOR_END_INSTR(CmpLt)
-
- COLLECTOR_BEGIN_INSTR(CmpLe)
- COLLECTOR_END_INSTR(CmpLe)
-
- COLLECTOR_BEGIN_INSTR(CmpStrictEqual)
- COLLECTOR_END_INSTR(CmpStrictEqual)
-
- COLLECTOR_BEGIN_INSTR(CmpStrictNotEqual)
- COLLECTOR_END_INSTR(CmpStrictNotEqual)
-
- COLLECTOR_BEGIN_INSTR(CmpIn)
- COLLECTOR_END_INSTR(CmpIn)
-
- COLLECTOR_BEGIN_INSTR(CmpInstanceOf)
- COLLECTOR_END_INSTR(CmpInstanceOf)
-
- COLLECTOR_BEGIN_INSTR(UNot)
- COLLECTOR_END_INSTR(UNot)
-
- COLLECTOR_BEGIN_INSTR(UPlus)
- COLLECTOR_END_INSTR(UPlus)
-
- COLLECTOR_BEGIN_INSTR(UMinus)
- COLLECTOR_END_INSTR(UMinus)
-
- COLLECTOR_BEGIN_INSTR(UCompl)
- COLLECTOR_END_INSTR(UCompl)
-
- COLLECTOR_BEGIN_INSTR(Increment)
- COLLECTOR_END_INSTR(PreIncrement)
-
- COLLECTOR_BEGIN_INSTR(Decrement)
- COLLECTOR_END_INSTR(PreDecrement)
-
- COLLECTOR_BEGIN_INSTR(Add)
- COLLECTOR_END_INSTR(Add)
-
- COLLECTOR_BEGIN_INSTR(BitAnd)
- COLLECTOR_END_INSTR(BitAnd)
-
- COLLECTOR_BEGIN_INSTR(BitOr)
- COLLECTOR_END_INSTR(BitOr)
-
- COLLECTOR_BEGIN_INSTR(BitXor)
- COLLECTOR_END_INSTR(BitXor)
-
- COLLECTOR_BEGIN_INSTR(UShr)
- COLLECTOR_END_INSTR(UShr)
-
- COLLECTOR_BEGIN_INSTR(Shr)
- COLLECTOR_END_INSTR(Shr)
-
- COLLECTOR_BEGIN_INSTR(Shl)
- COLLECTOR_END_INSTR(Shl)
-
- COLLECTOR_BEGIN_INSTR(BitAndConst)
- COLLECTOR_END_INSTR(BitAndConst)
-
- COLLECTOR_BEGIN_INSTR(BitOrConst)
- COLLECTOR_END_INSTR(BitOr)
-
- COLLECTOR_BEGIN_INSTR(BitXorConst)
- COLLECTOR_END_INSTR(BitXor)
-
- COLLECTOR_BEGIN_INSTR(UShrConst)
- COLLECTOR_END_INSTR(UShrConst)
-
- COLLECTOR_BEGIN_INSTR(ShrConst)
- COLLECTOR_END_INSTR(ShrConst)
-
- COLLECTOR_BEGIN_INSTR(ShlConst)
- COLLECTOR_END_INSTR(ShlConst)
-
- COLLECTOR_BEGIN_INSTR(Exp)
- COLLECTOR_END_INSTR(Exp)
-
- COLLECTOR_BEGIN_INSTR(Mul)
- COLLECTOR_END_INSTR(Mul)
-
- COLLECTOR_BEGIN_INSTR(Div)
- COLLECTOR_END_INSTR(Div)
-
- COLLECTOR_BEGIN_INSTR(Mod)
- COLLECTOR_END_INSTR(Mod)
-
- COLLECTOR_BEGIN_INSTR(Sub)
- COLLECTOR_END_INSTR(Sub)
-
- COLLECTOR_BEGIN_INSTR(Ret)
- COLLECTOR_END_INSTR(Ret)
-
-#ifndef QT_NO_QML_DEBUGGER
- COLLECTOR_BEGIN_INSTR(Debug)
- COLLECTOR_END_INSTR(Debug)
-#endif // QT_NO_QML_DEBUGGER
-
- COLLECTOR_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
- COLLECTOR_END_INSTR(InitializeBlockDeadTemporalZone)
-
- COLLECTOR_BEGIN_INSTR(ThrowOnNullOrUndefined)
- COLLECTOR_END_INSTR(ThrowOnNullOrUndefined)
-
- COLLECTOR_BEGIN_INSTR(GetTemplateObject)
- COLLECTOR_END_INSTR(GetTemplateObject)
-
- COLLECTOR_BEGIN_INSTR(TailCall)
- COLLECTOR_END_INSTR(TailCall)
- }
-
- return labels;
-}
-
-#undef COLLECTOR_BEGIN_INSTR
-#undef COLLECTOR_END_INSTR
diff --git a/src/qml/compiler/qv4bytecodehandler_p.h b/src/qml/compiler/qv4bytecodehandler_p.h
index ca6abf3dc3..797d25b8d0 100644
--- a/src/qml/compiler/qv4bytecodehandler_p.h
+++ b/src/qml/compiler/qv4bytecodehandler_p.h
@@ -75,6 +75,12 @@ namespace Moth {
int arg2, \
int arg3, \
int arg4
+#define BYTECODE_HANDLER_DEFINE_ARGS5(arg1, arg2, arg3, arg4, arg5) \
+ int arg1, \
+ int arg2, \
+ int arg3, \
+ int arg4, \
+ int arg5
#define BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER_INSTRUCTION(name, nargs, ...) \
virtual void generate_##name( \
@@ -93,8 +99,8 @@ public:
int currentInstructionOffset() const { return _currentOffset; }
int nextInstructionOffset() const { return _nextOffset; }
-
- static std::vector<int> collectLabelsInBytecode(const char *code, uint len);
+ int absoluteOffset(int relativeOffset) const
+ { return nextInstructionOffset() + relativeOffset; }
protected:
FOR_EACH_MOTH_INSTR(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 3fdba08f20..e0d259bd0c 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -288,8 +288,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
switch (op) {
case UMinus: {
expr.loadInAccumulator();
- Instruction::UMinus uminus;
- bytecodeGenerator->addInstruction(uminus);
+ Instruction::UMinus uminus = {};
+ bytecodeGenerator->addTracingInstruction(uminus);
return Reference::fromAccumulator(this);
}
case UPlus: {
@@ -317,8 +317,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Instruction::UPlus uplus;
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
- Instruction::Increment inc;
- bytecodeGenerator->addInstruction(inc);
+ Instruction::Increment inc = {};
+ bytecodeGenerator->addTracingInstruction(inc);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -329,8 +329,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case PreIncrement: {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::Increment inc;
- bytecodeGenerator->addInstruction(inc);
+ Instruction::Increment inc = {};
+ bytecodeGenerator->addTracingInstruction(inc);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -343,8 +343,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Instruction::UPlus uplus;
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
- Instruction::Decrement dec;
- bytecodeGenerator->addInstruction(dec);
+ Instruction::Decrement dec = {};
+ bytecodeGenerator->addTracingInstruction(dec);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -355,8 +355,8 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case PreDecrement: {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::Decrement dec;
- bytecodeGenerator->addInstruction(dec);
+ Instruction::Decrement dec = {};
+ bytecodeGenerator->addTracingInstruction(dec);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -1138,8 +1138,8 @@ bool Codegen::visit(ArrayPattern *ast)
slot.storeConsumeAccumulator();
index.loadInAccumulator();
- Instruction::Increment inc;
- bytecodeGenerator->addInstruction(inc);
+ Instruction::Increment inc = {};
+ bytecodeGenerator->addTracingInstruction(inc);
index.storeConsumeAccumulator();
};
@@ -1195,7 +1195,7 @@ bool Codegen::visit(ArrayPattern *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
lhsValue.loadInAccumulator();
pushAccumulator();
@@ -1482,24 +1482,24 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
{
switch (oper) {
case QSOperator::Add: {
- //### Todo: when we add type hints, we can generate an Increment when both the lhs is a number and the rhs == 1
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Add add;
add.lhs = left.stackSlot();
- bytecodeGenerator->addInstruction(add);
+ bytecodeGenerator->addTracingInstruction(add);
break;
}
case QSOperator::Sub: {
if (right.isConstant() && right.constant == Encode(int(1))) {
left.loadInAccumulator();
- bytecodeGenerator->addInstruction(Instruction::Decrement());
+ Instruction::Decrement dec = {};
+ bytecodeGenerator->addTracingInstruction(dec);
} else {
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Sub sub;
sub.lhs = left.stackSlot();
- bytecodeGenerator->addInstruction(sub);
+ bytecodeGenerator->addTracingInstruction(sub);
}
break;
}
@@ -1516,7 +1516,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mul mul;
mul.lhs = left.stackSlot();
- bytecodeGenerator->addInstruction(mul);
+ bytecodeGenerator->addTracingInstruction(mul);
break;
}
case QSOperator::Div: {
@@ -1532,7 +1532,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mod mod;
mod.lhs = left.stackSlot();
- bytecodeGenerator->addInstruction(mod);
+ bytecodeGenerator->addTracingInstruction(mod);
break;
}
case QSOperator::BitAnd:
@@ -1901,7 +1901,7 @@ bool Codegen::visit(CallExpression *ast)
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else {
Instruction::TailCall call;
call.func = base.stackSlot();
@@ -1930,14 +1930,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else {
Instruction::CallProperty call;
call.base = base.propertyBase.stackSlot();
call.name = base.propertyNameIndex;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
}
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
@@ -1945,33 +1945,33 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.index = base.elementSubscript.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else if (base.type == Reference::Name) {
if (base.name == QStringLiteral("eval")) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
}
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
}
} else if (base.type == Reference::SuperProperty) {
Reference receiver = base.baseObject();
@@ -1988,14 +1988,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.thisObject = receiver.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
} else {
Q_ASSERT(base.isStackSlot());
Instruction::CallValue call;
call.name = base.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ bytecodeGenerator->addTracingInstruction(call);
}
setExprResult(Reference::fromAccumulator(this));
@@ -2490,9 +2490,6 @@ bool Codegen::visit(ObjectPattern *ast)
TailCallBlocker blockTailCalls(this);
- QVector<QPair<Reference, ObjectPropertyValue>> computedProperties;
- QMap<QString, ObjectPropertyValue> valueMap;
-
RegisterScope scope(this);
QStringList members;
@@ -2734,14 +2731,14 @@ bool Codegen::visit(TemplateLiteral *ast)
Instruction::Add instr;
instr.lhs = temp2;
- bytecodeGenerator->addInstruction(instr);
+ bytecodeGenerator->addTracingInstruction(instr);
} else {
expr.loadInAccumulator();
}
Instruction::Add instr;
instr.lhs = temp;
- bytecodeGenerator->addInstruction(instr);
+ bytecodeGenerator->addTracingInstruction(instr);
}
auto r = Reference::fromAccumulator(this);
@@ -2999,6 +2996,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool savedFunctionEndsWithReturn = functionEndsWithReturn;
functionEndsWithReturn = endsWithReturn(_module, body);
+ bytecodeGenerator->setTracing(_functionContext->canUseTracingJit(), _context->arguments.size());
// reserve the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
@@ -3085,6 +3083,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
_context->registerCountInFunction = bytecodeGenerator->registerCount();
+ _context->nTraceInfos = bytecodeGenerator->traceInfoCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
@@ -3185,25 +3184,28 @@ bool Codegen::visit(DoWhileStatement *ast)
RegisterScope scope(this);
- BytecodeGenerator::Label body = bytecodeGenerator->label();
+ BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
ControlFlowLoop flow(this, &end, &cond);
-
- statement(ast->statement);
- setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
+ bytecodeGenerator->jump().link(body);
cond.link();
+ bytecodeGenerator->addLoopStart(cond);
- TailCallBlocker blockTailCalls(this);
- if (!AST::cast<FalseLiteral *>(ast->expression)) {
- if (AST::cast<TrueLiteral *>(ast->expression))
- bytecodeGenerator->jump().link(body);
- else
- condition(ast->expression, &body, &end, false);
+ if (!AST::cast<TrueLiteral *>(ast->expression)) {
+ TailCallBlocker blockTailCalls(this);
+ condition(ast->expression, &body, &end, true);
}
+ body.link();
+ statement(ast->statement);
+ setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
+
+ if (!AST::cast<FalseLiteral *>(ast->expression))
+ bytecodeGenerator->jump().link(cond);
+
end.link();
return false;
@@ -3274,9 +3276,14 @@ bool Codegen::visit(ForEachStatement *ast)
}
};
ControlFlowLoop flow(this, &end, &in, cleanup);
- bytecodeGenerator->jump().link(in);
-
- BytecodeGenerator::Label body = bytecodeGenerator->label();
+ bytecodeGenerator->addLoopStart(in);
+ in.link();
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ next.value = lhsValue.stackSlot();
+ next.done = iteratorDone.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
// each iteration gets it's own context, as per spec
{
@@ -3307,20 +3314,16 @@ bool Codegen::visit(ForEachStatement *ast)
Q_UNREACHABLE();
}
+ blockTailCalls.unblock();
statement(ast->statement);
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
-
}
+ bytecodeGenerator->jump().link(in);
+
error:
- in.link();
- iterator.loadInAccumulator();
- Instruction::IteratorNext next;
- next.value = lhsValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpFalse()).link(body);
end.link();
+
// all execution paths need to end up here (normal loop exit, break, and exceptions) in
// order to reset the unwind handler, and to close the iterator in calse of an for-of loop.
}
@@ -3349,7 +3352,7 @@ bool Codegen::visit(ForStatement *ast)
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
ControlFlowLoop flow(this, &end, &step);
-
+ bytecodeGenerator->addLoopStart(cond);
condition(ast->condition, &body, &end, true);
body.link();
@@ -3639,16 +3642,17 @@ bool Codegen::visit(WhileStatement *ast)
return false;
RegisterScope scope(this);
- TailCallBlocker blockTailCalls(this);
BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
BytecodeGenerator::Label cond = bytecodeGenerator->label();
ControlFlowLoop flow(this, &end, &cond);
+ bytecodeGenerator->addLoopStart(cond);
- if (!AST::cast<TrueLiteral *>(ast->expression))
+ if (!AST::cast<TrueLiteral *>(ast->expression)) {
+ TailCallBlocker blockTailCalls(this);
condition(ast->expression, &start, &end, true);
- blockTailCalls.unblock();
+ }
start.link();
statement(ast->statement);
@@ -4216,7 +4220,7 @@ void Codegen::Reference::storeAccumulator() const
Instruction::StoreElement store;
store.base = elementBase;
store.index = elementSubscript.stackSlot();
- codegen->bytecodeGenerator->addInstruction(store);
+ codegen->bytecodeGenerator->addTracingInstruction(store);
} return;
case Invalid:
case Accumulator:
@@ -4306,12 +4310,12 @@ QT_WARNING_POP
if (!scope) {
Instruction::LoadLocal load;
load.index = index;
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
} else {
Instruction::LoadScopedLocal load;
load.index = index;
load.scope = scope;
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
}
tdzCheck(requiresTDZCheck);
return;
@@ -4335,16 +4339,16 @@ QT_WARNING_POP
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
}
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
}
return;
case Member:
@@ -4353,11 +4357,11 @@ QT_WARNING_POP
if (!disable_lookups && codegen->useFastLookups) {
Instruction::GetLookup load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
} else {
Instruction::LoadProperty load;
load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
}
return;
case Import: {
@@ -4372,7 +4376,7 @@ QT_WARNING_POP
tdzCheck(subscriptRequiresTDZCheck);
Instruction::LoadElement load;
load.base = elementBase;
- codegen->bytecodeGenerator->addInstruction(load);
+ codegen->bytecodeGenerator->addTracingInstruction(load);
} return;
case Invalid:
break;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 9fb91e9140..c0ce125741 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -200,7 +200,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeFunctions.resize(data->functionTableSize);
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
- runtimeFunctions[i] = new QV4::Function(engine, this, compiledFunction);
+ runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction);
}
Scope scope(engine);
@@ -317,7 +317,8 @@ void CompilationUnit::unlink()
runtimeRegularExpressions = nullptr;
free(runtimeClasses);
runtimeClasses = nullptr;
- qDeleteAll(runtimeFunctions);
+ for (QV4::Function *f : qAsConst(runtimeFunctions))
+ f->destroy();
runtimeFunctions.clear();
}
@@ -777,6 +778,8 @@ QString Binding::valueAsString(const CompilationUnit *unit) const
case Type_Script:
case Type_String:
return unit->stringAt(stringIndex);
+ case Type_Null:
+ return QStringLiteral("null");
case Type_Boolean:
return value.b ? QStringLiteral("true") : QStringLiteral("false");
case Type_Number:
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 3fd9fdf74b..23e33247a8 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -73,7 +73,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x20
+#define QV4_DATA_STRUCTURE_VERSION 0x21
class QIODevice;
class QQmlPropertyCache;
@@ -288,10 +288,16 @@ struct Function
quint16_le nRegisters;
Location location;
+ quint32_le nLabelInfos;
+ size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
+
+ typedef quint16_le TraceInfoCount;
+ TraceInfoCount nTraceInfos;
+ static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
+
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
- quint16 padding2;
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
@@ -305,10 +311,13 @@ struct Function
const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
// ---
+ const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
+
const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
- static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int codeSize) {
- int trailingData = (nFormals + nLocals + nInnerfunctions)*sizeof (quint32) + nLines*sizeof(CodeOffsetToLine);
+ static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
+ int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ + nLines*sizeof(CodeOffsetToLine);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
return int(size);
@@ -318,7 +327,7 @@ struct Function
return (a + 7) & ~size_t(7);
}
};
-static_assert(sizeof(Function) == 48, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Method {
enum Type {
@@ -424,6 +433,7 @@ struct Q_QML_PRIVATE_EXPORT Binding
Type_Boolean,
Type_Number,
Type_String,
+ Type_Null,
Type_Translation,
Type_TranslationById,
Type_Script,
@@ -455,6 +465,7 @@ struct Q_QML_PRIVATE_EXPORT Binding
quint32_le compiledScriptIndex; // used when Type_Script
quint32_le objectIndex;
quint32_le translationDataIndex; // used when Type_Translation
+ quint32 nullMarker;
} value;
quint32_le stringIndex; // Set for Type_String and Type_Script (the latter because of script strings)
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 4d85f25d4b..01c033cb2a 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -424,9 +424,15 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
Q_ASSERT(function->lineNumberOffset() == currentOffset);
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
-
+ function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
+ if (!irFunction->labelInfo.empty()) {
+ function->nLabelInfos = quint32(irFunction->labelInfo.size());
+ Q_ASSERT(function->labelInfosOffset() == currentOffset);
+ currentOffset += function->nLabelInfos * sizeof(quint32);
+ }
+
function->location.line = irFunction->line;
function->location.column = irFunction->column;
@@ -446,6 +452,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
// write line numbers
memcpy(f + function->lineNumberOffset(), irFunction->lineNumberMapping.constData(), irFunction->lineNumberMapping.size()*sizeof(CompiledData::CodeOffsetToLine));
+ quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
+ for (unsigned u : irFunction->labelInfo) {
+ *labels++ = u;
+ }
+
// write byte code
memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size());
}
@@ -643,7 +654,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
blockAndFunctionOffsets[i] = nextOffset;
quint32 size = QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(),
- f->code.size());
+ int(f->labelInfo.size()), f->code.size());
functionSize += size - f->code.size();
nextOffset += size;
}
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index d1a5fee92b..b9ab4e5173 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -410,4 +410,28 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
+bool Context::canUseTracingJit() const
+{
+#if QT_CONFIG(qml_tracing)
+ static bool forceTracing = !qEnvironmentVariableIsEmpty("QV4_FORCE_TRACING");
+ if (forceTracing) //### we can probably remove this when tracing is turned on by default
+ return true; // to be used by unittests
+
+ static bool disableTracing = !qEnvironmentVariableIsEmpty("QV4_DISABLE_TRACING");
+ if (disableTracing)
+ return false;
+
+ static QStringList onlyTrace =
+ qEnvironmentVariable("QV4_ONLY_TRACE").split(QLatin1Char(','), QString::SkipEmptyParts);
+ if (!onlyTrace.isEmpty())
+ return onlyTrace.contains(name);
+
+ //### the next condition should be refined and have the IR distinguish between escaping and
+ // non-escaping locals
+ return !hasTry && !requiresExecutionContext && !hasNestedFunctions;
+#else
+ return false;
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 020b403bc4..57ef4be36e 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -162,6 +162,7 @@ struct Context {
int line = 0;
int column = 0;
int registerCountInFunction = 0;
+ uint nTraceInfos = 0;
int functionIndex = -1;
int blockIndex = -1;
@@ -200,6 +201,7 @@ struct Context {
ControlFlow *controlFlow = nullptr;
QByteArray code;
QVector<CompiledData::CodeOffsetToLine> lineNumberMapping;
+ std::vector<unsigned> labelInfo;
int nRegisters = 0;
int registerOffset = -1;
@@ -361,6 +363,8 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
+
+ bool canUseTracingJit() const;
};
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index c6c8caffba..345f03ae8a 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -156,7 +156,7 @@ QString dumpRegister(int reg, int nFormals)
return QStringLiteral("(this)");
else if (reg == CallData::Argc)
return QStringLiteral("(argc)");
- reg -= CallData::OffsetCount;
+ reg -= CallData::HeaderSize();
if (reg < nFormals)
return QStringLiteral("a%1").arg(reg);
reg -= nFormals;
@@ -171,6 +171,7 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
+#define TRACE_SLOT QStringLiteral(" {%1}").arg(traceSlot)
void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
{
@@ -240,9 +241,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index;
+ d << "l" << index << TRACE_SLOT;
else
- d << "a" << (index - nLocals);
+ d << "a" << (index - nLocals) << TRACE_SLOT;
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -254,9 +255,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope;
+ d << "l" << index << "@" << scope << TRACE_SLOT;
else
- d << "a" << (index - nLocals) << "@" << scope;
+ d << "a" << (index - nLocals) << "@" << scope << TRACE_SLOT;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -279,15 +280,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name;
+ d << name << TRACE_SLOT;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index;
+ d << index << TRACE_SLOT;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index;
+ d << index << TRACE_SLOT;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
@@ -299,19 +300,20 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]";
+ d << dumpRegister(base, nFormals) << "[acc]" << TRACE_SLOT;
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
+ << TRACE_SLOT;
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]";
+ d << "acc[" << name << "]" << TRACE_SLOT;
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")";
+ d << "acc(" << index << ")" << TRACE_SLOT;
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -341,51 +343,57 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
+ d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
- d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
+ d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
+ << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
- d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals);
+ d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
+ << TRACE_SLOT;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
- d << dumpRegister(base, nFormals) << "." << lookupIndex << dumpArguments(argc, argv, nFormals);
+ d << dumpRegister(base, nFormals) << "." << lookupIndex
+ << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]" << dumpArguments(argc, argv, nFormals);
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
+ << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals);
+ d << name << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals);
+ d << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals);
+ d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals);
+ d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
- d << "new" << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
+ d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
+ << dumpArguments(argc, argv, nFormals)
+ << TRACE_SLOT;
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
- d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ d << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(Construct)
MOTH_BEGIN_INSTR(ConstructWithSpread)
- d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ d << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(ConstructWithSpread)
MOTH_BEGIN_INSTR(SetUnwindHandler)
@@ -520,11 +528,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET();
+ d << ABSOLUTE_OFFSET() << TRACE_SLOT;
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET();
+ d << ABSOLUTE_OFFSET() << TRACE_SLOT;
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
@@ -588,19 +596,22 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
+ d << TRACE_SLOT;
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(Increment)
- MOTH_END_INSTR(PreIncrement)
+ d << TRACE_SLOT;
+ MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- MOTH_END_INSTR(PreDecrement)
+ d << TRACE_SLOT;
+ MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
@@ -656,7 +667,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
@@ -664,11 +675,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 25fca3c0b0..26901c297c 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -77,20 +77,20 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg)
#define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg)
#define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index)
-#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index)
+#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 2, index, traceSlot)
#define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index)
-#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index)
+#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 3, scope, index, traceSlot)
#define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index)
#define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId)
#define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg)
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
-#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name)
-#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index)
-#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index)
+#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
+#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
-#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
-#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
+#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -100,18 +100,18 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base)
-#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index)
-#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv)
-#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
-#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
-#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
-#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
-#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
-#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
-#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv)
-#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
+#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
+#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
+#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
+#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 5, name, thisObject, argc, argv, traceSlot)
+#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 5, name, base, argc, argv, traceSlot)
+#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 5, lookupIndex, base, argc, argv, traceSlot)
+#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 5, base, index, argc, argv, traceSlot)
+#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
+#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
+#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
@@ -148,8 +148,8 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
-#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
-#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
+#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 2, traceSlot, offset)
+#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 2, traceSlot, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
@@ -168,11 +168,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
-#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
+#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 1, traceSlot)
#define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0)
-#define INSTR_Increment(op) INSTRUCTION(op, Increment, 0)
-#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0)
-#define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs)
+#define INSTR_Increment(op) INSTRUCTION(op, Increment, 1, traceSlot)
+#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 1, traceSlot)
+#define INSTR_Add(op) INSTRUCTION(op, Add, 2, lhs, traceSlot)
#define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs)
#define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs)
#define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs)
@@ -186,10 +186,10 @@ QT_BEGIN_NAMESPACE
#define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs)
#define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs)
#define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs)
-#define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs)
+#define INSTR_Mul(op) INSTRUCTION(op, Mul, 2, lhs, traceSlot)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
-#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
-#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
+#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
+#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -334,12 +334,18 @@ QT_BEGIN_NAMESPACE
#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::Debug_Wide) + 1)
-#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
+#if defined(Q_CC_GNU)
+#if defined(Q_CC_INTEL)
// icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the
// current use results in an internal compiler error. We could enable this if/when it gets fixed
// in a later version.
+# elif defined(Q_OS_WASM) && !defined(__asmjs)
+// Upstream llvm does not support computed goto for the wasm target, unlike the 'fastcomp' llvm fork
+// shipped with the emscripten SDK. Disable computed goto usage for non-fastcomp llvm on Wasm.
+#else
# define MOTH_COMPUTED_GOTO
#endif
+#endif
#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1)
@@ -365,6 +371,12 @@ QT_BEGIN_NAMESPACE
int arg2; \
int arg3; \
int arg4;
+#define MOTH_DEFINE_ARGS5(arg1, arg2, arg3, arg4, arg5) \
+ int arg1; \
+ int arg2; \
+ int arg3; \
+ int arg4; \
+ int arg5;
#define MOTH_COLLECT_ENUMS(instr) \
INSTR_##instr(MOTH_GET_ENUM)
@@ -435,6 +447,9 @@ QT_BEGIN_NAMESPACE
#define MOTH_DECODE_ARGS4(name, type, nargs, arg1, arg2, arg3, arg4) \
MOTH_DECODE_ARGS3(name, type, nargs, arg1, arg2, arg3); \
MOTH_DECODE_ARG(arg4, type, nargs, 3);
+#define MOTH_DECODE_ARGS5(name, type, nargs, arg1, arg2, arg3, arg4, arg5) \
+ MOTH_DECODE_ARGS4(name, type, nargs, arg1, arg2, arg3, arg4); \
+ MOTH_DECODE_ARG(arg5, type, nargs, 4);
#ifdef MOTH_COMPUTED_GOTO
/* collect jump labels */
diff --git a/src/qml/configure.json b/src/qml/configure.json
index 17d1f800ac..c35f5be06b 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -8,6 +8,7 @@
"commandline": {
"options": {
"qml-network": "boolean",
+ "qml-tracing": "boolean",
"qml-debug": "boolean"
}
},
@@ -39,6 +40,13 @@
"condition": "features.network",
"output": [ "publicFeature" ]
},
+ "qml-tracing": {
+ "label": "QML tracing JIT support",
+ "purpose": "Provides a JIT that uses trace information generated by the interpreter.",
+ "section": "QML",
+ "output": [ "privateFeature" ],
+ "autoDetect": false
+ },
"qml-debug": {
"label": "QML debugging and profiling support",
"purpose": "Provides infrastructure and plugins for debugging and profiling.",
@@ -132,6 +140,7 @@
"entries": [
"qml-network",
"qml-debug",
+ "qml-tracing",
"qml-sequence-object",
"qml-list-model",
"qml-xml-http-request",
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml b/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
index 5339fcddce..e2104f8740 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
@@ -49,7 +49,7 @@
****************************************************************************/
//![0]
import QtQuick 2.0
-import "script.js" as MyScript
+import "script.mjs" as MyScript
Item {
width: 100; height: 100
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.js b/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs
index f2e31265e3..d0a09b68ad 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.js
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs
@@ -48,8 +48,8 @@
**
****************************************************************************/
//![0]
-// factorial.js
-function factorial(a) {
+// factorial.mjs
+export function factorial(a) {
a = parseInt(a);
if (a <= 0)
return 1;
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.js b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
index c44b39abda..ef7688693d 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.js
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
@@ -49,7 +49,7 @@
****************************************************************************/
//![0]
// script.js
-Qt.include("factorial.js")
+import { factorial } from "factorial.mjs"
function showCalculations(value) {
console.log(
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 8ebbd28737..171b2b6a11 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -284,6 +284,9 @@ In particular, QML currently supports:
\li \c {std::vector<bool>}
\endlist
+and all registered QList, QVector, QQueue, QStack, QSet, QLinkedList, std::list,
+std::vector that contain a type marked with \l Q_DECLARE_METATYPE.
+
These sequence types are implemented directly in terms of the underlying C++
sequence. There are two ways in which such sequences can be exposed to QML:
as a Q_PROPERTY of the given sequence type; or as the return type of a
diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc
index 7da2cd22fe..974f2e154f 100644
--- a/src/qml/doc/src/javascript/imports.qdoc
+++ b/src/qml/doc/src/javascript/imports.qdoc
@@ -99,9 +99,44 @@ A JavaScript resource may import another in the following fashion:
\endcode
For example:
\code
-.import "factorial.js" as MathFunctions
+import * as MathFunctions from "factorial.mjs";
\endcode
+The latter is standard ECMAScript syntax for importing ECMAScript modules, and
+only works from within ECMAScript modules as denoted by the \c mjs file
+extension. The former is an extension to JavaScript provided by the \c QML
+engine and will work also with non-modules.
+
+When a JavaScript file is imported this way, it is imported with a qualifier.
+The functions in that file are then accessible from the importing script via the
+qualifier (that is, as \tt{Qualifier.functionName(params)}).
+
+Sometimes it is desirable to have the functions made available in the importing
+context without needing to qualify them. In this case ECMAScript modules and the
+JavaScript \c import statement should be used without the \c as qualifier.
+
+For example, the QML code below left calls \c showCalculations() in \c script.mjs,
+which in turn can call \c factorial() in \c factorial.mjs, as it has included
+\c factorial.mjs using \c import.
+
+\table
+\row
+\li {1,2} \snippet qml/integrating-javascript/includejs/app.qml 0
+\li \snippet qml/integrating-javascript/includejs/script.mjs 0
+\row
+\li \snippet qml/integrating-javascript/includejs/factorial.mjs 0
+\endtable
+
+The \l{QtQml::Qt::include()} {Qt.include()} function includes one JavaScript
+file from another without using ECMAScript modules and without qualifying the
+import. It makes all functions and variables from the other file available in
+the current file's namespace, but ignores all pragmas and imports defined in
+that file. This is not a good idea as a function call should never modify the
+caller's context.
+
+\l{QtQml::Qt::include()} {Qt.include()} is deprecated and should be avoided. It
+will be removed in a future version of Qt.
+
\section2 Importing a QML Module from a JavaScript Resource
A JavaScript resource may import a QML module in the following fashion:
@@ -119,32 +154,4 @@ via a singleton type; see qmlRegisterSingletonType() for more information.
\note The .import syntax doesn't work for scripts used in the \l {WorkerScript}
-\section1 Including a JavaScript Resource from Another JavaScript Resource
-
-When a JavaScript file is imported, it must be imported with a qualifier. The
-functions in that file are then accessible from the importing script via the
-qualifier (that is, as \tt{Qualifier.functionName(params)}). Sometimes it is
-desirable to have the functions made available in the importing context without
-needing to qualify them, and in this circumstance the \l{QtQml::Qt::include()}
-{Qt.include()} function may be used to include one JavaScript file from another.
-This copies all functions from the other file into the current file's
-namespace, but ignores all pragmas and imports defined in that file.
-
-For example, the QML code below left calls \c showCalculations() in \c script.js,
-which in turn can call \c factorial() in \c factorial.js, as it has included
-\c factorial.js using \l {QtQml::Qt::include()}{Qt.include()}.
-
-\table
-\row
-\li {1,2} \snippet qml/integrating-javascript/includejs/app.qml 0
-\li \snippet qml/integrating-javascript/includejs/script.js 0
-\row
-\li \snippet qml/integrating-javascript/includejs/factorial.js 0
-\endtable
-
-Notice that calling \l {QtQml::Qt::include()}{Qt.include()} copies all functions
-from \c factorial.js into the \c MyScript namespace, which means the QML
-component can also access \c factorial() directly as \c MyScript.factorial().
-
-
*/
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 2bb1fcac61..15e8e4c52c 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -540,6 +540,58 @@ Internally, however, the rectangle can correctly set its \c color
property and refer to the actual defined property rather than the alias.
+\section4 Property Aliases and Types
+
+Property aliases cannot have explicit type specifications. The type of a
+property alias is the \e declared type of the property or object it refers to.
+Therefore, if you create an alias to an object referenced via id with extra
+properties declared inline, the extra properties won't be accessible through
+the alias:
+
+\code
+// MyItem.qml
+Item {
+ property alias inner: innerItem
+
+ Item {
+ id: innerItem
+ property int extraProperty
+ }
+}
+\code
+
+You cannot initialize \a inner.extraProperty from outside of this component, as
+inner is only an \a Item:
+
+\code
+// main.qml
+MyItem {
+ inner.extraProperty: 5 // fails
+}
+\code
+
+However, if you extract the inner object into a separate component with a
+dedicated .qml file, you can instantiate that component instead and have all
+its properties available through the alias:
+
+\code
+// MainItem.qml
+Item {
+ // Now you can access inner.extraProperty, as inner is now an ExtraItem
+ property alias inner: innerItem
+
+ ExtraItem {
+ id: innerItem
+ }
+}
+
+// ExtraItem.qml
+Item {
+ property int extraProperty
+}
+\code
+
+
\section3 Default Properties
An object definition can have a single \e default property. A default property
diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc
index 6986f1baa0..231b85af76 100644
--- a/src/qml/doc/src/statemachine.qdoc
+++ b/src/qml/doc/src/statemachine.qdoc
@@ -27,7 +27,7 @@
/*!
\qmlmodule QtQml.StateMachine 1.\QtMinorVersion
- \title Declarative State Machine QML Types
+ \title Qt QML State Machine QML Types
\brief Provides QML types to create and execute state graphs.
The following is a list of QML types provided by the module:
@@ -322,7 +322,7 @@
\section1 Related Information
\list
- \li \l{Declarative State Machine QML Types}
+ \li \l{Qt QML State Machine QML Types}
\li \l{The State Machine Framework}
\endlist
*/
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 831496a628..dd810d9d70 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -39,10 +39,12 @@
#include <QBuffer>
#include <QFile>
+#include <QLoggingCategory>
#include "qv4engine_p.h"
#include "qv4assemblercommon_p.h"
#include <private/qv4function_p.h>
+#include <private/qv4functiontable_p.h>
#include <private/qv4runtime_p.h>
#include <assembler/MacroAssemblerCodeRef.h>
@@ -57,6 +59,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+Q_LOGGING_CATEGORY(lcAsm, "qt.v4.asm")
+
namespace {
class QIODevicePrintStream: public FilePrintStream
{
@@ -109,18 +113,9 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
}
}
- qDebug("%s", processedOutput.constData());
-}
-
-static QByteArray functionName(Function *function)
-{
- QByteArray name = function->name()->toQString().toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(reinterpret_cast<quintptr>(function), 16);
- name.prepend("QV4::Function(0x");
- name.append(')');
- }
- return name;
+ auto lines = processedOutput.split('\n');
+ for (const auto &line : lines)
+ qCDebug(lcAsm, "%s", line.constData());
}
JIT::PlatformAssemblerCommon::~PlatformAssemblerCommon()
@@ -141,13 +136,15 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
JSC::MacroAssemblerCodeRef codeRef;
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
+ static const bool showCode = lcAsm().isDebugEnabled();
if (showCode) {
QBuffer buf;
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
- QByteArray name = functionName(function);
+ // We use debugAddress here because it's actually for debugging and hidden behind an
+ // environment variable.
+ const QByteArray name = Function::prettyName(function, linkBuffer.debugAddress()).toUtf8();
codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, "function %s", name.constData());
WTF::setDataFile(stderr);
@@ -159,31 +156,9 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
- // This implements writing of JIT'd addresses so that perf can find the
- // symbol names.
- //
- // Perf expects the mapping to be in a certain place and have certain
- // content, for more information, see:
- // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
- static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
- if (Q_UNLIKELY(doProfile)) {
- static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
- .arg(QCoreApplication::applicationPid()));
- static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
- if (!isOpen) {
- qWarning("QV4::JIT::Assembler: Cannot write perf map file.");
- doProfile = false;
- } else {
- perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>(
- codeRef.code().executableAddress()), 16));
- perfMapFile.putChar(' ');
- perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef.size()), 16));
- perfMapFile.putChar(' ');
- perfMapFile.write(functionName(function));
- perfMapFile.putChar('\n');
- perfMapFile.flush();
- }
- }
+ generateFunctionTable(function, &codeRef);
+
+ linkBuffer.makeExecutable();
}
void PlatformAssemblerCommon::prepareCallWithArgCount(int argc)
@@ -316,6 +291,19 @@ void PlatformAssemblerCommon::passInt32AsArg(int value, int arg)
store32(TrustedImm32(value), argStackAddress(arg));
}
+void JIT::PlatformAssemblerCommon::passPointerAsArg(void *ptr, int arg)
+{
+#ifndef QT_NO_DEBUG
+ Q_ASSERT(arg < remainingArgcForCall);
+ --remainingArgcForCall;
+#endif
+
+ if (arg < ArgInRegCount)
+ move(TrustedImmPtr(ptr), registerForArg(arg));
+ else
+ storePtr(TrustedImmPtr(ptr), argStackAddress(arg));
+}
+
void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *funcPtr)
{
#ifndef QT_NO_DEBUG
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index 729d0fc53d..d3d7eedae2 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -587,7 +587,7 @@ public:
Address loadCompilationUnitPtr(RegisterID target)
{
Address addr = loadFunctionPtr(target);
- addr.offset = offsetof(QV4::Function, compilationUnit);
+ addr.offset = offsetof(QV4::FunctionData, compilationUnit);
loadPtr(addr, target);
return Address(target);
}
@@ -670,7 +670,8 @@ public:
void addLabelForOffset(int offset)
{
- labelForOffset.insert(offset, label());
+ if (!labelForOffset.contains(offset))
+ labelForOffset.insert(offset, label());
}
void addJumpToOffset(const Jump &jump, int offset)
@@ -699,6 +700,7 @@ public:
void passAddressAsArg(Address addr, int arg);
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
+ void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr);
void callRuntimeUnchecked(const char *functionName, const void *funcPtr);
void tailCallRuntime(const char *functionName, const void *funcPtr);
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index b13f646360..25c74e74e8 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -1382,28 +1382,31 @@ void BaselineAssembler::cmpStrictNotEqual(int lhs)
pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
}
-void BaselineAssembler::jump(int offset)
+int BaselineAssembler::jump(int offset)
{
pasm()->addJumpToOffset(pasm()->jump(), offset);
+ return offset;
}
-void BaselineAssembler::jumpTrue(int offset)
+int BaselineAssembler::jumpTrue(int offset)
{
pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) {
auto jump = pasm()->branch32(PlatformAssembler::NotEqual, TrustedImm32(0), resultReg);
pasm()->addJumpToOffset(jump, offset);
});
+ return offset;
}
-void BaselineAssembler::jumpFalse(int offset)
+int BaselineAssembler::jumpFalse(int offset)
{
pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) {
auto jump = pasm()->branch32(PlatformAssembler::Equal, TrustedImm32(0), resultReg);
pasm()->addJumpToOffset(jump, offset);
});
+ return offset;
}
-void BaselineAssembler::jumpNoException(int offset)
+int BaselineAssembler::jumpNoException(int offset)
{
auto jump = pasm()->branch32(
PlatformAssembler::Equal,
@@ -1411,11 +1414,13 @@ void BaselineAssembler::jumpNoException(int offset)
offsetof(EngineBase, hasException)),
TrustedImm32(0));
pasm()->addJumpToOffset(jump, offset);
+ return offset;
}
-void BaselineAssembler::jumpNotUndefined(int offset)
+int BaselineAssembler::jumpNotUndefined(int offset)
{
pasm()->jumpNotUndefined(offset);
+ return offset;
}
void BaselineAssembler::prepareCallWithArgCount(int argc)
@@ -1458,6 +1463,11 @@ void BaselineAssembler::passInt32AsArg(int value, int arg)
pasm()->passInt32AsArg(value, arg);
}
+void BaselineAssembler::passPointerAsArg(void *ptr, int arg)
+{
+ pasm()->passPointerAsArg(ptr, arg);
+}
+
void BaselineAssembler::callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest)
{
pasm()->callRuntime(functionName, funcPtr, dest);
@@ -1534,10 +1544,11 @@ void BaselineAssembler::setException()
noException.link(pasm());
}
-void BaselineAssembler::setUnwindHandler(int offset)
+int BaselineAssembler::setUnwindHandler(int offset)
{
auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress());
pasm()->addEHTarget(l, offset);
+ return offset;
}
@@ -1563,12 +1574,13 @@ void JIT::BaselineAssembler::unwindDispatch()
noUnwind.link(pasm());
}
-void JIT::BaselineAssembler::unwindToLabel(int level, int offset)
+int JIT::BaselineAssembler::unwindToLabel(int level, int offset)
{
auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)));
pasm()->addEHTarget(l, offset);
pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
gotoCatchException();
+ return offset;
}
void BaselineAssembler::pushCatchContext(int index, int name)
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index 0aa508ae71..c39d002bf9 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -135,11 +135,11 @@ public:
void cmpStrictNotEqual(int lhs);
// jumps
- void jump(int offset);
- void jumpTrue(int offset);
- void jumpFalse(int offset);
- void jumpNoException(int offset);
- void jumpNotUndefined(int offset);
+ Q_REQUIRED_RESULT int jump(int offset);
+ Q_REQUIRED_RESULT int jumpTrue(int offset);
+ Q_REQUIRED_RESULT int jumpFalse(int offset);
+ Q_REQUIRED_RESULT int jumpNoException(int offset);
+ Q_REQUIRED_RESULT int jumpNotUndefined(int offset);
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
@@ -150,6 +150,7 @@ public:
void passJSSlotAsArg(int reg, int arg);
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
+ void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
void jsTailCall(int func, int thisObject, int argc, int argv);
@@ -159,10 +160,10 @@ public:
void gotoCatchException();
void getException();
void setException();
- void setUnwindHandler(int offset);
+ Q_REQUIRED_RESULT int setUnwindHandler(int offset);
void clearUnwindHandler();
void unwindDispatch();
- void unwindToLabel(int level, int offset);
+ Q_REQUIRED_RESULT int unwindToLabel(int level, int offset);
void pushCatchContext(int index, int name);
void popContext();
void deadTemporalZoneCheck(int offsetForSavedIP, int variableName);
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 1e4288e3c9..e518fc5a0e 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -63,7 +63,9 @@ void BaselineJIT::generate()
// qDebug()<<"jitting" << function->name()->toQString();
const char *code = function->codeData;
uint len = function->compiledFunction->codeSize;
- labels = collectLabelsInBytecode(code, len);
+
+ for (unsigned i = 0, ei = function->compiledFunction->nLabelInfos; i != ei; ++i)
+ labels.insert(int(function->compiledFunction->labelInfoTable()[i]));
as->generatePrologue();
decode(code, len);
@@ -149,7 +151,7 @@ void BaselineJIT::generate_LoadImport(int index)
as->loadImport(index);
}
-void BaselineJIT::generate_LoadLocal(int index)
+void BaselineJIT::generate_LoadLocal(int index, int /*traceSlot*/)
{
as->loadLocal(index);
}
@@ -160,7 +162,7 @@ void BaselineJIT::generate_StoreLocal(int index)
as->storeLocal(index);
}
-void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
+void BaselineJIT::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
{
as->loadLocal(index, scope);
}
@@ -193,7 +195,7 @@ void BaselineJIT::generate_LoadClosure(int value)
BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_closure, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadName(int name)
+void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(2);
@@ -203,7 +205,7 @@ void BaselineJIT::generate_LoadName(int name)
as->checkException();
}
-void BaselineJIT::generate_LoadGlobalLookup(int index)
+void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
@@ -213,7 +215,7 @@ void BaselineJIT::generate_LoadGlobalLookup(int index)
as->checkException();
}
-void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
@@ -247,7 +249,7 @@ void BaselineJIT::generate_StoreNameStrict(int name)
as->checkException();
}
-void BaselineJIT::generate_LoadElement(int base)
+void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
{
STORE_IP();
STORE_ACC();
@@ -259,7 +261,7 @@ void BaselineJIT::generate_LoadElement(int base)
as->checkException();
}
-void BaselineJIT::generate_StoreElement(int base, int index)
+void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
{
STORE_IP();
STORE_ACC();
@@ -272,7 +274,7 @@ void BaselineJIT::generate_StoreElement(int base, int index)
as->checkException();
}
-void BaselineJIT::generate_LoadProperty(int name)
+void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
{
STORE_IP();
STORE_ACC();
@@ -284,7 +286,7 @@ void BaselineJIT::generate_LoadProperty(int name)
as->checkException();
}
-void BaselineJIT::generate_GetLookup(int index)
+void BaselineJIT::generate_GetLookup(int index, int /*traceSlot*/)
{
STORE_IP();
STORE_ACC();
@@ -365,7 +367,7 @@ void BaselineJIT::generate_Resume(int)
Q_UNREACHABLE();
}
-void BaselineJIT::generate_CallValue(int name, int argc, int argv)
+void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -377,7 +379,7 @@ void BaselineJIT::generate_CallValue(int name, int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
+void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -390,7 +392,7 @@ void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc,
as->checkException();
}
-void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
+void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -403,7 +405,7 @@ void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
+void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -416,7 +418,7 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
as->checkException();
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
+void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -429,7 +431,7 @@ void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallName(int name, int argc, int argv)
+void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -441,7 +443,7 @@ void BaselineJIT::generate_CallName(int name, int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
+void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(3);
@@ -452,7 +454,7 @@ void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
+void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -464,7 +466,8 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
as->checkException();
}
-void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
+ int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -476,7 +479,7 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int
as->checkException();
}
-void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -526,7 +529,7 @@ void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
void BaselineJIT::generate_SetUnwindHandler(int offset)
{
if (offset)
- as->setUnwindHandler(absoluteOffsetForJump(offset));
+ labels.insert(as->setUnwindHandler(absoluteOffset(offset)));
else
as->clearUnwindHandler();
}
@@ -538,7 +541,7 @@ void BaselineJIT::generate_UnwindDispatch()
void BaselineJIT::generate_UnwindToLabel(int level, int offset)
{
- as->unwindToLabel(level, absoluteOffsetForJump(offset));
+ labels.insert(as->unwindToLabel(level, absoluteOffset(offset)));
}
void BaselineJIT::generate_DeadTemporalZoneCheck(int name)
@@ -805,11 +808,30 @@ void BaselineJIT::generate_ToObject()
}
-void BaselineJIT::generate_Jump(int offset) { as->jump(absoluteOffsetForJump(offset)); }
-void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(absoluteOffsetForJump(offset)); }
-void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(absoluteOffsetForJump(offset)); }
-void BaselineJIT::generate_JumpNoException(int offset) { as->jumpNoException(absoluteOffsetForJump(offset)); }
-void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(absoluteOffsetForJump(offset)); }
+void BaselineJIT::generate_Jump(int offset)
+{
+ labels.insert(as->jump(absoluteOffset(offset)));
+}
+
+void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset)
+{
+ labels.insert(as->jumpTrue(absoluteOffset(offset)));
+}
+
+void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset)
+{
+ labels.insert(as->jumpFalse(absoluteOffset(offset)));
+}
+
+void BaselineJIT::generate_JumpNoException(int offset)
+{
+ labels.insert(as->jumpNoException(absoluteOffset(offset)));
+}
+
+void BaselineJIT::generate_JumpNotUndefined(int offset)
+{
+ labels.insert(as->jumpNotUndefined(absoluteOffset(offset)));
+}
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
@@ -848,11 +870,11 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
void BaselineJIT::generate_UNot() { as->unot(); }
void BaselineJIT::generate_UPlus() { as->toNumber(); }
-void BaselineJIT::generate_UMinus() { as->uminus(); }
+void BaselineJIT::generate_UMinus(int /*traceSlot*/) { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
-void BaselineJIT::generate_Increment() { as->inc(); }
-void BaselineJIT::generate_Decrement() { as->dec(); }
-void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
+void BaselineJIT::generate_Increment(int /*traceSlot*/) { as->inc(); }
+void BaselineJIT::generate_Decrement(int /*traceSlot*/) { as->dec(); }
+void BaselineJIT::generate_Add(int lhs, int /*traceSlot*/) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
@@ -877,10 +899,10 @@ void BaselineJIT::generate_Exp(int lhs) {
BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::exp, CallResultDestination::InAccumulator);
as->checkException();
}
-void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
+void BaselineJIT::generate_Mul(int lhs, int /*traceSlot*/) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
-void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
-void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
+void BaselineJIT::generate_Mod(int lhs, int /*traceSlot*/) { as->mod(lhs); }
+void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
@@ -923,7 +945,7 @@ void BaselineJIT::generate_GetTemplateObject(int index)
void BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
- if (hasLabel())
+ if (labels.contains(currentInstructionOffset()))
as->addLabel(currentInstructionOffset());
}
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 6646eb713e..10c89bc74b 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -88,22 +88,22 @@ public:
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index) override;
+ void generate_LoadLocal(int index, int traceSlot) override;
void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index) override;
+ void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
- void generate_LoadName(int name) override;
- void generate_LoadGlobalLookup(int index) override;
- void generate_LoadQmlContextPropertyLookup(int index) override;
+ void generate_LoadName(int name, int traceSlot) override;
+ void generate_LoadGlobalLookup(int index, int traceSlot) override;
+ void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base) override;
- void generate_StoreElement(int base, int index) override;
- void generate_LoadProperty(int name) override;
- void generate_GetLookup(int index) override;
+ void generate_LoadElement(int base, int traceSlot) override;
+ void generate_StoreElement(int base, int index, int traceSlot) override;
+ void generate_LoadProperty(int name, int traceSlot) override;
+ void generate_GetLookup(int index, int traceSlot) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -112,16 +112,16 @@ public:
void generate_YieldStar() override;
void generate_Resume(int) override;
- void generate_CallValue(int name, int argc, int argv) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
- void generate_CallProperty(int name, int base, int argc, int argv) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
- void generate_CallElement(int base, int index, int argc, int argv) override;
- void generate_CallName(int name, int argc, int argv) override;
- void generate_CallPossiblyDirectEval(int argc, int argv) override;
- void generate_CallGlobalLookup(int index, int argc, int argv) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
+ void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
+ void generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int traceSlot) override;
+ void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
+ void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int traceSlot) override;
+ void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
+ void generate_CallName(int name, int argc, int argv, int traceSlot) override;
+ void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
+ void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
@@ -160,8 +160,8 @@ public:
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
- void generate_JumpTrue(int offset) override;
- void generate_JumpFalse(int offset) override;
+ void generate_JumpTrue(int traceSlot, int offset) override;
+ void generate_JumpFalse(int traceSlot, int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
void generate_CmpEqNull() override;
@@ -180,11 +180,11 @@ public:
void generate_CmpInstanceOf(int lhs) override;
void generate_UNot() override;
void generate_UPlus() override;
- void generate_UMinus() override;
+ void generate_UMinus(int traceSlot) override;
void generate_UCompl() override;
- void generate_Increment() override;
- void generate_Decrement() override;
- void generate_Add(int lhs) override;
+ void generate_Increment(int traceSlot) override;
+ void generate_Decrement(int traceSlot) override;
+ void generate_Add(int lhs, int traceSlot) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
@@ -198,10 +198,10 @@ public:
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
- void generate_Mul(int lhs) override;
+ void generate_Mul(int lhs, int traceSlot) override;
void generate_Div(int lhs) override;
- void generate_Mod(int lhs) override;
- void generate_Sub(int lhs) override;
+ void generate_Mod(int lhs, int traceSlot) override;
+ void generate_Sub(int lhs, int traceSlot) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
@@ -209,17 +209,10 @@ public:
void startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
-protected:
- bool hasLabel() const
- { return std::find(labels.cbegin(), labels.cend(), currentInstructionOffset()) != labels.cend(); }
-
- int absoluteOffsetForJump(int relativeOffset) const
- { return nextInstructionOffset() + relativeOffset; }
-
private:
QV4::Function *function;
QScopedPointer<BaselineAssembler> as;
- std::vector<int> labels;
+ QSet<int> labels;
};
#endif // V4_ENABLE_JIT
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 5ec55b960b..a24ee0a188 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -147,7 +147,8 @@ HEADERS += \
$$PWD/qv4value_p.h \
$$PWD/qv4string_p.h \
$$PWD/qv4util_p.h \
- $$PWD/qv4value_p.h
+ $$PWD/qv4value_p.h \
+ $$PWD/qv4functiontable_p.h
SOURCES += \
$$PWD/qv4engine.cpp \
@@ -156,6 +157,23 @@ SOURCES += \
$$PWD/qv4value.cpp \
$$PWD/qv4executableallocator.cpp
+qmldevtools_build {
+ SOURCES += \
+ $$PWD/qv4functiontable_noop.cpp
+} else:win32 {
+ !winrt:equals(QT_ARCH, x86_64) {
+ SOURCES += \
+ $$PWD/qv4functiontable_win64.cpp
+ } else {
+ SOURCES += \
+ $$PWD/qv4functiontable_noop.cpp
+ }
+} else {
+ SOURCES += \
+ $$PWD/qv4functiontable_unix.cpp
+}
+
+
valgrind {
DEFINES += V4_USE_VALGRIND
}
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index a13fb37a52..21c6a5d06b 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -670,17 +670,17 @@ static inline QString ToTimeString(double t)
static inline QString ToLocaleString(double t)
{
- return ToDateTime(t, Qt::LocalTime).toString(Qt::LocaleDate);
+ return ToDateTime(t, Qt::LocalTime).toString(Qt::DefaultLocaleShortDate);
}
static inline QString ToLocaleDateString(double t)
{
- return ToDateTime(t, Qt::LocalTime).date().toString(Qt::LocaleDate);
+ return ToDateTime(t, Qt::LocalTime).date().toString(Qt::DefaultLocaleShortDate);
}
static inline QString ToLocaleTimeString(double t)
{
- return ToDateTime(t, Qt::LocalTime).time().toString(Qt::LocaleDate);
+ return ToDateTime(t, Qt::LocalTime).time().toString(Qt::DefaultLocaleShortDate);
}
static double getLocalTZA()
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index bd1124beb6..4c5e124cb0 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -50,6 +50,7 @@
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
+#include <QLoggingCategory>
#ifndef V4_BOOTSTRAP
@@ -134,6 +135,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcTracingAll, "qt.v4.tracing.all")
+
using namespace QV4;
#ifndef V4_BOOTSTRAP
@@ -652,6 +655,13 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ExecutionEngine::~ExecutionEngine()
{
+ if (Q_UNLIKELY(lcTracingAll().isDebugEnabled())) {
+ for (auto cu : compilationUnits) {
+ for (auto f : qAsConst(cu->runtimeFunctions))
+ qCDebug(lcTracingAll).noquote().nospace() << f->traceInfoToString();
+ }
+ }
+
modules.clear();
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = nullptr;
@@ -1620,6 +1630,22 @@ static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVaria
return a.asReturnedValue();
}
+// Converts a QSequentialIterable to JS.
+// The result is a new Array object with length equal to the length
+// of the QSequentialIterable, and the elements being the QSequentialIterable's
+// elements converted to JS, recursively.
+static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst)
+{
+ QV4::Scope scope(v4);
+ QV4::ScopedArrayObject a(scope, v4->newArrayObject());
+ a->arrayReserve(lst.size());
+ QV4::ScopedValue v(scope);
+ for (int i = 0; i < lst.size(); i++)
+ a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
+ a->setArrayLengthUnchecked(lst.size());
+ return a.asReturnedValue();
+}
+
// Converts a QVariantMap to JS.
// The result is a new Object object with property names being
// the keys of the QVariantMap, and values being the values of
@@ -1724,9 +1750,18 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return QV4::Encode::null();
}
QMetaType mt(type);
- if (mt.flags() & QMetaType::IsGadget) {
- Q_ASSERT(mt.metaObject());
- return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), mt.metaObject(), type);
+ if (auto metaObject = mt.metaObject()) {
+ auto flags = mt.flags();
+ if (flags & QMetaType::IsGadget) {
+ return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), metaObject, type);
+ } else if (flags & QMetaType::PointerToQObject) {
+ return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
+ }
+ }
+ if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
+ auto v = QVariant(type, data);
+ QSequentialIterable lst = v.value<QSequentialIterable>();
+ return sequentialIterableToJS(this, lst);
}
// Fall back to wrapping in a QVariant.
return QV4::Encode(newVariantObject(QVariant(type, data)));
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index 6f04a712e6..c836d121e3 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -38,17 +38,23 @@
****************************************************************************/
#include "qv4executableallocator_p.h"
+#include "qv4functiontable_p.h"
#include <wtf/StdLibExtras.h>
#include <wtf/PageAllocation.h>
using namespace QV4;
-void *ExecutableAllocator::Allocation::start() const
+void *ExecutableAllocator::Allocation::exceptionHandler() const
{
return reinterpret_cast<void*>(addr);
}
+void *ExecutableAllocator::Allocation::start() const
+{
+ return reinterpret_cast<void*>(addr + exceptionHandlerSize());
+}
+
void ExecutableAllocator::Allocation::deallocate(ExecutableAllocator *allocator)
{
if (isValid())
@@ -162,7 +168,7 @@ ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size)
Allocation *allocation = nullptr;
// Code is best aligned to 16-byte boundaries.
- size = WTF::roundUpToMultipleOf(16, size);
+ size = WTF::roundUpToMultipleOf(16, size + exceptionHandlerSize());
QMultiMap<size_t, Allocation*>::Iterator it = freeAllocations.lowerBound(size);
if (it != freeAllocations.end()) {
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 375c9a365f..013c6d7120 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -86,6 +86,7 @@ public:
, free(true)
{}
+ void *exceptionHandler() const;
void *start() const;
void invalidate() { addr = 0; }
bool isValid() const { return addr != 0; }
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 51a9b92967..1bd4329fe8 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -46,6 +46,7 @@
#include "qv4lookup_p.h"
#include <private/qv4mm_p.h>
#include <private/qv4identifiertable_p.h>
+#include <private/qv4functiontable_p.h>
#include <assembler/MacroAssemblerCodeRef.h>
#include <private/qv4vme_moth_p.h>
#include <private/qqmlglobal_p.h>
@@ -72,12 +73,29 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg
return result;
}
+Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
+{
+ quint16 traceSlotCount = 0;
+#if QT_CONFIG(qml_tracing)
+ traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing()
+ ? 1
+ : function->nTraceInfos;
+#endif
+ quint8 *storage = new quint8[sizeof(Function) + traceSlotCount];
+ return new(storage) Function(engine, unit, function);
+}
+
+void Function::destroy()
+{
+ delete[] reinterpret_cast<quint8 *>(this);
+}
+
Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
- : compiledFunction(function)
- , compilationUnit(unit)
+ : FunctionData(unit)
+ , compiledFunction(function)
, codeData(function->code())
- , jittedCode(nullptr)
- , codeRef(nullptr)
+ , jittedCode(nullptr)
+ , codeRef(nullptr)
{
Scope scope(engine);
Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
@@ -93,11 +111,21 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
+
+#if QT_CONFIG(qml_tracing)
+ if (tracingEnabled()) {
+ for (uint i = 0; i < function->nTraceInfos; ++i)
+ *traceInfo(i) = 0;
+ }
+#endif
}
Function::~Function()
{
- delete codeRef;
+ if (codeRef) {
+ destroyFunctionTable(this, codeRef);
+ delete codeRef;
+ }
}
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
@@ -144,9 +172,38 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
nFormals = parameters.size();
}
+QString Function::prettyName(const Function *function, const void *code)
+{
+ QString prettyName = function ? function->name()->toQString() : QString();
+ if (prettyName.isEmpty()) {
+ prettyName = QString::number(reinterpret_cast<quintptr>(code), 16);
+ prettyName.prepend(QLatin1String("QV4::Function(0x"));
+ prettyName.append(QLatin1Char(')'));
+ }
+ return prettyName;
+}
+
QQmlSourceLocation Function::sourceLocation() const
{
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
+QString Function::traceInfoToString()
+{
+ QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':');
+ if (!tracingEnabled())
+ return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount);
+ if (compiledFunction->nTraceInfos == 0)
+ return info + QLatin1String(" none.\n");
+
+ info += QLatin1Char('\n');
+ for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) {
+ auto bits = QString::number(*traceInfo(i), 2);
+ if (bits.size() < 8)
+ bits.prepend(QString(8 - bits.size(), '0'));
+ info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits);
+ }
+ return info;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 62c5d24fc4..f8125a58f8 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -64,10 +64,24 @@ struct QQmlSourceLocation;
namespace QV4 {
-struct Q_QML_EXPORT Function {
- const CompiledData::Function *compiledFunction;
+struct Q_QML_EXPORT FunctionData {
CompiledData::CompilationUnit *compilationUnit;
+ FunctionData(CompiledData::CompilationUnit *compilationUnit)
+ : compilationUnit(compilationUnit)
+ {}
+};
+// Make sure this class can be accessed through offsetof (done by the assemblers):
+Q_STATIC_ASSERT(std::is_standard_layout< FunctionData >::value);
+
+struct Q_QML_EXPORT Function : public FunctionData {
+private:
+ Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
+ ~Function();
+
+public:
+ const CompiledData::Function *compiledFunction;
+
ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context);
const char *codeData;
@@ -82,15 +96,18 @@ struct Q_QML_EXPORT Function {
int interpreterCallCount = 0;
bool isEval = false;
- Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
- ~Function();
+ static Function *create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
+ void destroy();
// used when dynamically assigning signal handlers (QQmlConnection)
void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
- inline Heap::String *name() {
+ inline Heap::String *name() const {
return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
}
+
+ static QString prettyName(const Function *function, const void *address);
+
inline QString sourceFile() const { return compilationUnit->fileName(); }
inline QUrl finalUrl() const { return compilationUnit->finalUrl(); }
@@ -106,6 +123,31 @@ struct Q_QML_EXPORT Function {
return nullptr;
return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
}
+
+ Q_NEVER_INLINE QString traceInfoToString();
+
+ quint8 *traceInfo(uint i)
+ {
+#if QT_CONFIG(qml_tracing)
+ Q_ASSERT((tracingEnabled() && i < traceInfoCount()) || (i == 0));
+ return reinterpret_cast<quint8 *>(this) + sizeof(Function) + i;
+#else
+ Q_UNUSED(i);
+ return nullptr;
+#endif
+ }
+
+ quint32 traceInfoCount() const
+ { return compiledFunction->nTraceInfos; }
+
+ bool tracingEnabled() const
+ {
+#if QT_CONFIG(qml_tracing)
+ return traceInfoCount() != CompiledData::Function::NoTracing();
+#else
+ return false;
+#endif
+ }
};
}
diff --git a/src/qml/jsruntime/qv4functiontable_noop.cpp b/src/qml/jsruntime/qv4functiontable_noop.cpp
new file mode 100644
index 0000000000..31c198eb00
--- /dev/null
+++ b/src/qml/jsruntime/qv4functiontable_noop.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4functiontable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+void generateFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ Q_UNUSED(function);
+ Q_UNUSED(codeRef);
+}
+
+void destroyFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ Q_UNUSED(function);
+ Q_UNUSED(codeRef);
+}
+
+size_t exceptionHandlerSize()
+{
+ return 0;
+}
+
+} // QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functiontable_p.h b/src/qml/jsruntime/qv4functiontable_p.h
new file mode 100644
index 0000000000..69e3d2bdd5
--- /dev/null
+++ b/src/qml/jsruntime/qv4functiontable_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4FUNCTIONTABLE_P_H
+#define QV4FUNCTIONTABLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qv4global_p.h"
+
+namespace JSC {
+class MacroAssemblerCodeRef;
+}
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+
+void generateFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef);
+void destroyFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef);
+
+size_t exceptionHandlerSize();
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4FUNCTIONTABLE_P_H
diff --git a/src/qml/jsruntime/qv4functiontable_unix.cpp b/src/qml/jsruntime/qv4functiontable_unix.cpp
new file mode 100644
index 0000000000..25b5c27161
--- /dev/null
+++ b/src/qml/jsruntime/qv4functiontable_unix.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4functiontable_p.h"
+#include "qv4function_p.h"
+
+#include <assembler/MacroAssemblerCodeRef.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+void generateFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ // This implements writing of JIT'd addresses so that perf can find the
+ // symbol names.
+ //
+ // Perf expects the mapping to be in a certain place and have certain
+ // content, for more information, see:
+ // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
+ static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
+ if (Q_UNLIKELY(doProfile)) {
+ static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
+ .arg(QCoreApplication::applicationPid()));
+ static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
+ if (!isOpen) {
+ qWarning("QV4::JIT::Assembler: Cannot write perf map file.");
+ doProfile = false;
+ } else {
+ const void *address = codeRef->code().executableAddress();
+ perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>(address), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef->size()), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(Function::prettyName(function, address).toUtf8());
+ perfMapFile.putChar('\n');
+ perfMapFile.flush();
+ }
+ }
+}
+
+void destroyFunctionTable(Function *function, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ Q_UNUSED(function);
+ Q_UNUSED(codeRef);
+
+ // It's not advisable to remove things from the perf map file, as it's primarily used to analyze
+ // a trace after the application has terminated. We want to know about all functions that were
+ // ever jitted then. If the memory ranges overlap, we will have a problem when analyzing the
+ // trace. The JIT should try to avoid this.
+}
+
+size_t exceptionHandlerSize()
+{
+ return 0;
+}
+
+} // QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functiontable_win64.cpp b/src/qml/jsruntime/qv4functiontable_win64.cpp
new file mode 100644
index 0000000000..fc13dc2602
--- /dev/null
+++ b/src/qml/jsruntime/qv4functiontable_win64.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4functiontable_p.h"
+
+#include <assembler/MacroAssemblerCodeRef.h>
+
+#include <QtCore/qdebug.h>
+
+#include <windows.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum UnwindOpcode: UINT8
+{
+ UWOP_PUSH_NONVOL = 0, /* info == register number */
+ UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
+ UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
+ UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+ UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
+ UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+ UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
+ UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
+};
+
+enum Register : UINT8
+{
+ RAX = 0,
+ RCX,
+ RDX,
+ RBX,
+ RSP,
+ RBP,
+ RSI,
+ RDI,
+ NONE = 15
+};
+
+struct UnwindCode
+{
+ UnwindCode(UINT8 offset, UnwindOpcode operation, Register info)
+ : offset(offset), operation(operation), info(info)
+ {}
+
+ UINT8 offset;
+ UINT8 operation: 4;
+ UINT8 info: 4;
+};
+
+struct UnwindInfo
+{
+ UINT8 Version : 3;
+ UINT8 Flags : 5;
+ UINT8 SizeOfProlog;
+ UINT8 CountOfUnwindCodes;
+ UINT8 FrameRegister : 4;
+ UINT8 FrameRegisterOffset : 4;
+ UnwindCode UnwindCodes[2];
+};
+
+struct ExceptionHandlerRecord
+{
+ RUNTIME_FUNCTION handler;
+ UnwindInfo info;
+};
+
+void generateFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
+ codeRef->executableMemory()->exceptionHandler());
+
+ record->info.Version = 1;
+ record->info.Flags = 0;
+ record->info.SizeOfProlog = 4;
+ record->info.CountOfUnwindCodes = 2;
+ record->info.FrameRegister = RBP;
+ record->info.FrameRegisterOffset = 0;
+
+ // Push frame pointer
+ record->info.UnwindCodes[1] = UnwindCode(1, UWOP_PUSH_NONVOL, RBP);
+ // Set frame pointer from stack pointer
+ record->info.UnwindCodes[0] = UnwindCode(4, UWOP_SET_FPREG, NONE);
+
+ const quintptr codeStart = quintptr(codeRef->code().executableAddress());
+ const quintptr codeSize = codeRef->size();
+
+ record->handler.BeginAddress = DWORD(codeStart - quintptr(record));
+ record->handler.EndAddress = DWORD(codeStart + codeSize - quintptr(record));
+ record->handler.UnwindData = offsetof(ExceptionHandlerRecord, info);
+
+ if (!RtlAddFunctionTable(&record->handler, 1, DWORD64(record))) {
+ const unsigned int errorCode = GetLastError();
+ qWarning() << "Failed to install win64 unwind hook. Error code:" << errorCode;
+ }
+}
+
+void destroyFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
+{
+ ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
+ codeRef->executableMemory()->exceptionHandler());
+ if (!RtlDeleteFunctionTable(&record->handler)) {
+ const unsigned int errorCode = GetLastError();
+ qWarning() << "Failed to remove win64 unwind hook. Error code:" << errorCode;
+ }
+}
+
+size_t exceptionHandlerSize()
+{
+ return sizeof(ExceptionHandlerRecord);
+}
+
+} // QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 58bffdf2d1..d47393b3bb 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -280,6 +280,20 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
+enum class ObservedTraceValues : quint8 {
+ Integer = 1 << 0,
+ Boolean = 1 << 1,
+ Double = 1 << 2,
+ Other = 1 << 3,
+ TypeMask = Integer | Boolean | Double | Other,
+
+ TruePathTaken = 1 << 0,
+ FalsePathTaken = 1 << 1,
+
+ ArrayWasAccessed = 1 << 7,
+ ArrayAccessNeededFallback = 1 << 6,
+};
+
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index 90246c4229..a60a49a811 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -66,27 +66,42 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
+static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b, quint8 *traceInfo = nullptr)
{
int result;
- if (Q_UNLIKELY(add_overflow(a, b, &result)))
+ if (Q_UNLIKELY(add_overflow(a, b, &result))) {
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue();
+ }
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
+static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b, quint8 *traceInfo = nullptr)
{
int result;
- if (Q_UNLIKELY(sub_overflow(a, b, &result)))
+ if (Q_UNLIKELY(sub_overflow(a, b, &result))) {
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue();
+ }
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
+static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b, quint8 *traceInfo = nullptr)
{
int result;
- if (Q_UNLIKELY(mul_overflow(a, b, &result)))
+ if (Q_UNLIKELY(mul_overflow(a, b, &result))) {
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue();
+ }
+ if (traceInfo)
+ *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6a242ba5f6..f7c339dc26 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -704,6 +704,30 @@ ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &
return getElementFallback(engine, object, index);
}
+ReturnedValue Runtime::method_loadElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)
+{
+ *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
+ if (index.isPositiveInt()) {
+ uint idx = static_cast<uint>(index.int_32());
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->internalClass->vtable->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->values.size)
+ if (!s->data(idx).isEmpty())
+ return s->data(idx).asReturnedValue();
+ }
+ }
+ }
+ *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
+ return getElementIntFallback(engine, object, idx);
+ }
+
+ *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
+ return getElementFallback(engine, object, index);
+}
+
static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
@@ -759,6 +783,30 @@ void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object,
engine->throwTypeError();
}
+void Runtime::method_storeElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)
+{
+ *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
+ if (index.isPositiveInt()) {
+ uint idx = static_cast<uint>(index.int_32());
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->internalClass->vtable->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
+ if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict())
+ engine->throwTypeError();
+}
+
ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &in, int iterator)
{
Scope scope(engine);
@@ -1405,7 +1453,7 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base,
if (!f) {
QString error = QStringLiteral("Property '%1' of object %2 is not a function")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
+ .arg(name->toQString(),
base->toQStringNoThrow());
return engine->throwTypeError(error);
}
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 4b3905c56f..ceec13a3bb 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -113,9 +113,11 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(void, storeNameSloppy, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
F(void, storeProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \
F(void, storeElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \
+ F(void, storeElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)) \
F(ReturnedValue, loadProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \
F(ReturnedValue, loadName, (ExecutionEngine *engine, int nameIndex)) \
F(ReturnedValue, loadElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \
+ F(ReturnedValue, loadElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)) \
F(ReturnedValue, loadSuperProperty, (ExecutionEngine *engine, const Value &property)) \
F(void, storeSuperProperty, (ExecutionEngine *engine, const Value &property, const Value &value)) \
F(ReturnedValue, loadSuperConstructor, (ExecutionEngine *engine, const Value &t)) \
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index ef0877dbd0..e4d8bcaafc 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -138,11 +138,14 @@ ReturnedValue VariantPrototype::method_toString(const FunctionObject *b, const V
const VariantObject *o = thisObject->as<QV4::VariantObject>();
if (!o)
RETURN_UNDEFINED();
- QString result = o->d()->data().toString();
- if (result.isEmpty() && !o->d()->data().canConvert(QVariant::String)) {
- result = QLatin1String("QVariant(")
- + QLatin1String(o->d()->data().typeName())
- + QLatin1Char(')');
+ const QVariant variant = o->d()->data();
+ QString result = variant.toString();
+ if (result.isEmpty() && !variant.canConvert(QVariant::String)) {
+ QDebug dbg(&result);
+ dbg << variant;
+ // QDebug appends a space, we're not interested in continuing the stream so we chop it off.
+ // Can't use nospace() because it would affect the debug-stream operator of the variant.
+ result.chop(1);
}
return Encode(v4->newString(result));
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index ea2217499f..dd712a15d6 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -346,6 +346,70 @@ static struct InstrCount {
if (engine->hasException) \
goto handleUnwind
+static inline void traceJumpTakesTruePath(bool truePathTaken, Function *f, int slot)
+{
+#if QT_CONFIG(qml_tracing)
+ quint8 *traceInfo = f->traceInfo(slot);
+ Q_ASSERT(traceInfo);
+ *traceInfo |= truePathTaken ? quint8(ObservedTraceValues::TruePathTaken)
+ : quint8(ObservedTraceValues::FalsePathTaken);
+#else
+ Q_UNUSED(truePathTaken);
+ Q_UNUSED(f);
+ Q_UNUSED(slot);
+#endif
+}
+
+static inline void traceValue(ReturnedValue acc, Function *f, int slot)
+{
+#if QT_CONFIG(qml_tracing)
+ quint8 *traceInfo = f->traceInfo(slot);
+ Q_ASSERT(traceInfo);
+ switch (Primitive::fromReturnedValue(acc).type()) {
+ case QV4::Value::Integer_Type:
+ *traceInfo |= quint8(ObservedTraceValues::Integer);
+ break;
+ case QV4::Value::Boolean_Type:
+ *traceInfo |= quint8(ObservedTraceValues::Boolean);
+ break;
+ case QV4::Value::Double_Type:
+ *traceInfo |= quint8(ObservedTraceValues::Double);
+ break;
+ default:
+ *traceInfo |= quint8(ObservedTraceValues::Other);
+ break;
+ }
+#else
+ Q_UNUSED(acc);
+ Q_UNUSED(f);
+ Q_UNUSED(slot);
+#endif
+}
+
+static inline void traceDoubleValue(Function *f, int slot)
+{
+#if QT_CONFIG(qml_tracing)
+ quint8 *traceInfo = f->traceInfo(slot);
+ Q_ASSERT(traceInfo);
+ *traceInfo |= quint8(ObservedTraceValues::Double);
+#else
+ Q_UNUSED(f);
+ Q_UNUSED(slot);
+#endif
+}
+
+static inline void traceOtherValue(Function *f, int slot)
+{
+#if QT_CONFIG(qml_tracing)
+ quint8 *traceInfo = f->traceInfo(slot);
+ Q_ASSERT(traceInfo);
+ *traceInfo |= quint8(ObservedTraceValues::Other);
+#else
+ Q_UNUSED(f);
+ Q_UNUSED(slot);
+#endif
+}
+
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
{
Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
@@ -453,6 +517,11 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
+ if (function->tracingEnabled()) {
+ for (int i = 0; i < int(function->nFormals); ++i)
+ traceValue(frame->jsFrame->argument(i), function, i);
+ }
+
MOTH_JUMP_TABLE;
for (;;) {
@@ -511,6 +580,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -523,6 +593,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadScopedLocal)
auto cc = getScope(stack, scope);
acc = cc->locals[index].asReturnedValue();
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -547,6 +618,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
acc = Runtime::method_loadName(engine, name);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
@@ -554,6 +626,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->globalGetter(l, engine);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
@@ -561,6 +634,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->qmlContextPropertyGetter(l, engine, nullptr);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameStrict)
@@ -580,14 +654,25 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadElement)
STORE_IP();
STORE_ACC();
+#if QT_CONFIG(qml_tracing)
+ acc = Runtime::method_loadElement_traced(engine, STACK_VALUE(base), accumulator, function->traceInfo(traceSlot));
+ traceValue(acc, function, traceSlot);
+#else
+ Q_UNUSED(traceSlot);
acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator);
+#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
STORE_IP();
STORE_ACC();
+#if QT_CONFIG(qml_tracing)
+ Runtime::method_storeElement_traced(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator, function->traceInfo(traceSlot));
+#else
+ Q_UNUSED(traceSlot);
Runtime::method_storeElement(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
+#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
@@ -596,6 +681,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::method_loadProperty(engine, accumulator, name);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
@@ -614,6 +700,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = l->getter(l, engine, accumulator);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -687,6 +774,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
Value undef = Value::undefinedValue();
acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
@@ -698,12 +786,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
acc = Runtime::method_callProperty(engine, stack + base, name, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -731,42 +821,49 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
acc = Runtime::method_callElement(engine, stack + base, STACK_VALUE(index), stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
acc = Runtime::method_callName(engine, name, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
STORE_IP();
acc = Runtime::method_callPossiblyDirectEval(engine, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
STORE_IP();
acc = Runtime::method_callGlobalLookup(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
STORE_IP();
acc = Runtime::method_callQmlContextPropertyLookup(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
STORE_IP();
acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(TailCall)
@@ -1004,23 +1101,25 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- if (Q_LIKELY(ACC.integerCompatible())) {
- if (ACC.int_32())
- code += offset;
- } else {
- if (ACC.toBoolean())
- code += offset;
- }
+ bool takeJump;
+ if (Q_LIKELY(ACC.integerCompatible()))
+ takeJump = ACC.int_32();
+ else
+ takeJump = ACC.toBoolean();
+ traceJumpTakesTruePath(takeJump, function, traceSlot);
+ if (takeJump)
+ code += offset;
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- if (Q_LIKELY(ACC.integerCompatible())) {
- if (!ACC.int_32())
- code += offset;
- } else {
- if (!ACC.toBoolean())
- code += offset;
- }
+ bool takeJump;
+ if (Q_LIKELY(ACC.integerCompatible()))
+ takeJump = !ACC.int_32();
+ else
+ takeJump = !ACC.toBoolean();
+ traceJumpTakesTruePath(!takeJump, function, traceSlot);
+ if (takeJump)
+ code += offset;
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNoException)
@@ -1189,14 +1288,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
int a = ACC.int_32();
if (a == 0 || a == std::numeric_limits<int>::min()) {
acc = Encode(-static_cast<double>(a));
+ traceDoubleValue(function, traceSlot);
} else {
- acc = sub_int32(0, ACC.int_32());
+ acc = sub_int32(0, ACC.int_32(), function->traceInfo(traceSlot));
}
} else if (ACC.isDouble()) {
acc ^= (1ull << 63); // simply flip sign bit
+ traceDoubleValue(function, traceSlot);
} else {
acc = Encode(-ACC.toNumberImpl());
CHECK_EXCEPTION;
+ traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(UMinus)
@@ -1207,49 +1309,57 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Increment)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = add_int32(ACC.int_32(), 1);
+ acc = add_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() + 1.);
+ traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() + 1.);
CHECK_EXCEPTION;
+ traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = sub_int32(ACC.int_32(), 1);
+ acc = sub_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() - 1.);
+ traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() - 1.);
CHECK_EXCEPTION;
+ traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = add_int32(left.int_32(), ACC.int_32());
+ acc = add_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() + ACC.asDouble());
+ traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::method_add(engine, left, accumulator);
CHECK_EXCEPTION;
+ traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(Sub)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = sub_int32(left.int_32(), ACC.int_32());
+ acc = sub_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() - ACC.asDouble());
+ traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::method_sub(left, accumulator);
CHECK_EXCEPTION;
+ traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Sub)
@@ -1266,13 +1376,15 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Mul)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = mul_int32(left.int_32(), ACC.int_32());
+ acc = mul_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() * ACC.asDouble());
+ traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::method_mul(left, accumulator);
CHECK_EXCEPTION;
+ traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Mul)
@@ -1286,6 +1398,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::method_mod(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(BitAnd)
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri
index adab4ef9a2..2c0175c94b 100644
--- a/src/qml/parser/parser.pri
+++ b/src/qml/parser/parser.pri
@@ -8,7 +8,8 @@ HEADERS += \
$$PWD/qqmljsglobal_p.h \
$$PWD/qqmljskeywords_p.h \
$$PWD/qqmljsengine_p.h \
- $$PWD/qqmljsglobal_p.h
+ $$PWD/qqmljsglobal_p.h \
+ $$PWD/qqmljssourcelocation_p.h
SOURCES += \
$$PWD/qqmljsast.cpp \
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 8ae51a795f..0c947b541b 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -249,7 +249,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -486,7 +486,7 @@ protected:
using namespace QQmlJS;
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
void Parser::reallocateStack()
{
@@ -4476,12 +4476,12 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
return false;
}
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
./
/:
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 54a1200493..e5817ab763 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -41,7 +41,7 @@
#include "qqmljsastvisitor_p.h"
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
@@ -1474,6 +1474,6 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast()
} } // namespace QQmlJS::AST
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index e84c62af2f..b81553776d 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -57,7 +57,7 @@
#include <QtCore/qstring.h>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
#define QQMLJS_DECLARE_AST_NODE(name) \
enum { K = Kind_##name };
@@ -3395,6 +3395,6 @@ public:
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 996264db59..e9caa918d5 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -41,6 +41,7 @@
#define QQMLJSAST_FWD_P_H
#include "qqmljsglobal_p.h"
+#include "qqmljssourcelocation_p.h"
#include <QtCore/qglobal.h>
@@ -55,31 +56,10 @@
// We mean it.
//
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
-class SourceLocation
-{
-public:
- explicit SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
- : offset(offset), length(length),
- startLine(line), startColumn(column)
- { }
-
- bool isValid() const { return length != 0; }
-
- quint32 begin() const { return offset; }
- quint32 end() const { return offset + length; }
-
-// attributes
- // ### encode
- quint32 offset;
- quint32 length;
- quint32 startLine;
- quint32 startColumn;
-};
-
class Visitor;
class Node;
class ExpressionNode;
@@ -201,6 +181,6 @@ class UiEnumMemberList;
} } // namespace AST
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif
diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp
index 666623eecc..5ecac36423 100644
--- a/src/qml/parser/qqmljsastvisitor.cpp
+++ b/src/qml/parser/qqmljsastvisitor.cpp
@@ -39,7 +39,7 @@
#include "qqmljsastvisitor_p.h"
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
@@ -53,4 +53,4 @@ Visitor::~Visitor()
} } // namespace QQmlJS::AST
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 9c69f88e0c..9115449a46 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -54,7 +54,7 @@
#include "qqmljsastfwd_p.h"
#include "qqmljsglobal_p.h"
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
@@ -412,6 +412,6 @@ protected:
} } // namespace AST
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif // QQMLJSASTVISITOR_P_H
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
index 97ce6ebea3..bb27f3992e 100644
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ b/src/qml/parser/qqmljsengine_p.cpp
@@ -44,7 +44,7 @@
#include <QtCore/qhash.h>
#include <QtCore/qdebug.h>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -155,4 +155,4 @@ QStringRef Engine::newStringRef(const QChar *chars, int size)
} // end of namespace QQmlJS
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index 1de907d296..b7f7da9478 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -52,13 +52,13 @@
//
#include "qqmljsglobal_p.h"
-#include "qqmljsastfwd_p.h"
#include "qqmljsmemorypool_p.h"
+#include "qqmljssourcelocation_p.h"
#include <QtCore/qstring.h>
#include <QtCore/qset.h>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -95,7 +95,7 @@ public:
class QML_PARSER_EXPORT DiagnosticMessage
{
public:
- enum Kind { Warning, Error };
+ enum Kind { Hint, Warning, Error };
DiagnosticMessage() {}
@@ -150,6 +150,6 @@ double integerFromString(const char *buf, int size, int radix);
} // end of namespace QQmlJS
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif // QQMLJSENGINE_P_H
diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index 0e195994b4..bf8155c6ec 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -53,8 +53,6 @@
#include <QtCore/qglobal.h>
#ifdef QT_CREATOR
-# define QT_QML_BEGIN_NAMESPACE
-# define QT_QML_END_NAMESPACE
# ifdef QDECLARATIVEJS_BUILD_DIR
# define QML_PARSER_EXPORT Q_DECL_EXPORT
@@ -65,8 +63,6 @@
# endif // QQMLJS_BUILD_DIR
#else // !QT_CREATOR
-# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
-# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
# ifndef QT_STATIC
# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
// QmlDevTools is a static library
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index b0a4951ece..96b3709162 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -53,7 +53,7 @@
#include "qqmljslexer_p.h"
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -918,6 +918,6 @@ int Lexer::classify(const QChar *s, int n, int parseModeFlags) {
} // namespace QQmlJS
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif // QQMLJSKEYWORDS_P_H
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index 03f33f6e06..51152bfd6e 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -57,7 +57,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qstack.h>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -257,6 +257,6 @@ private:
} // end of namespace QQmlJS
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif // LEXER_H
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h
index afd0f809da..e7b1f46414 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/parser/qqmljsmemorypool_p.h
@@ -59,7 +59,7 @@
#include <cstring>
-QT_QML_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE
namespace QQmlJS {
@@ -104,6 +104,8 @@ public:
}
template <typename Tp> Tp *New() { return new (this->allocate(sizeof(Tp))) Tp(); }
+ template <typename Tp, typename... Ta> Tp *New(Ta... args)
+ { return new (this->allocate(sizeof(Tp))) Tp(args...); }
QStringRef newString(const QString &string) {
strings.append(new QString(string));
@@ -172,8 +174,83 @@ public:
void operator delete(void *, MemoryPool *) {}
};
+template <typename T>
+class FixedPoolArray
+{
+ T *data;
+ int count = 0;
+
+public:
+ FixedPoolArray()
+ : data(nullptr)
+ {}
+
+ FixedPoolArray(MemoryPool *pool, int size)
+ { allocate(pool, size); }
+
+ void allocate(MemoryPool *pool, int size)
+ {
+ count = size;
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ }
+
+ void allocate(MemoryPool *pool, const QVector<T> &vector)
+ {
+ count = vector.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+
+ if (QTypeInfo<T>::isComplex) {
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(vector.at(i));
+ } else {
+ memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
+ }
+ }
+
+ template <typename Container>
+ void allocate(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++);
+ }
+
+ int size() const
+ { return count; }
+
+ const T &at(int index) const {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &at(int index) {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &operator[](int index) {
+ return at(index);
+ }
+
+
+ int indexOf(const T &value) const {
+ for (int i = 0; i < count; ++i)
+ if (data[i] == value)
+ return i;
+ return -1;
+ }
+
+ const T *begin() const { return data; }
+ const T *end() const { return data + count; }
+
+ T *begin() { return data; }
+ T *end() { return data + count; }
+};
+
} // namespace QQmlJS
-QT_QML_END_NAMESPACE
+QT_END_NAMESPACE
#endif
diff --git a/src/qml/parser/qqmljssourcelocation_p.h b/src/qml/parser/qqmljssourcelocation_p.h
new file mode 100644
index 0000000000..d76e701d49
--- /dev/null
+++ b/src/qml/parser/qqmljssourcelocation_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSSOURCELOCATION_P_H
+#define QQMLJSSOURCELOCATION_P_H
+
+#include "qqmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+class SourceLocation
+{
+public:
+ explicit SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return length != 0; }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+};
+
+} } // namespace AST
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index db59140f06..94717a8f43 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -73,6 +73,7 @@ include(jsruntime/jsruntime.pri)
include(jit/jit.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
+include(qmldirparser/qmldirparser.pri)
qtConfig(qml-animation) {
include(animations/animations.pri)
}
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 6d69294c17..ca13ce9211 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -18,7 +18,6 @@ SOURCES += \
$$PWD/qqmlparserstatus.cpp \
$$PWD/qqmltypeloader.cpp \
$$PWD/qqmlinfo.cpp \
- $$PWD/qqmlerror.cpp \
$$PWD/qqmlvaluetype.cpp \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
@@ -44,7 +43,6 @@ SOURCES += \
$$PWD/qqmltypewrapper.cpp \
$$PWD/qqmlfileselector.cpp \
$$PWD/qqmlobjectcreator.cpp \
- $$PWD/qqmldirparser.cpp \
$$PWD/qqmldelayedcallqueue.cpp \
$$PWD/qqmlloggingcategory.cpp
@@ -81,7 +79,6 @@ HEADERS += \
$$PWD/qqmllist.h \
$$PWD/qqmllist_p.h \
$$PWD/qqmldata_p.h \
- $$PWD/qqmlerror.h \
$$PWD/qqmlvaluetype_p.h \
$$PWD/qqmlcleanup_p.h \
$$PWD/qqmlpropertycache_p.h \
@@ -112,7 +109,6 @@ HEADERS += \
$$PWD/qqmlfileselector_p.h \
$$PWD/qqmlfileselector.h \
$$PWD/qqmlobjectcreator_p.h \
- $$PWD/qqmldirparser_p.h \
$$PWD/qqmldelayedcallqueue_p.h \
$$PWD/qqmlloggingcategory_p.h
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 9eacc5bc22..42cf723284 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -588,7 +588,6 @@ namespace QtQml {
bool create = true);
#ifndef Q_QDOC
}
-#endif
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
@@ -598,6 +597,8 @@ using namespace QtQml;
QT_WARNING_POP
+#endif // Q_QDOC
+
//The C++ version of protected namespaces in qmldir
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor);
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor.h
index 665b37fb3a..af231f51b2 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.h
+++ b/src/qml/qml/qqmlabstracturlinterceptor.h
@@ -55,8 +55,8 @@ public:
UrlString = 0x1000
};
- QQmlAbstractUrlInterceptor() {}
- virtual ~QQmlAbstractUrlInterceptor() {}
+ QQmlAbstractUrlInterceptor() = default;
+ virtual ~QQmlAbstractUrlInterceptor() = default;
virtual QUrl intercept(const QUrl &path, DataType type) = 0;
};
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 4795170bed..6cf6828832 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -74,7 +74,6 @@ public:
void loadTranslations(const QUrl &rootFile);
void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
- QObject *appObj;
#if QT_CONFIG(translation)
QList<QTranslator *> translators;
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 7f0442d034..b164517011 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -314,7 +314,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType->typeId == pd->propType()) {
+ if (vtw->d()->valueType->metaType.id() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 7cd4bf8579..4c6a1b69d8 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -661,6 +661,10 @@ The following functions are also on the Qt object.
/*!
\qmlmethod object Qt::include(string url, jsobject callback)
+\deprecated
+
+This method should not be used. Use ECMAScript modules instead and the native
+JavaScript \c import and \c export statements instead.
Includes another JavaScript file. This method can only be used from within JavaScript files,
and not regular QML files.
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 8a9581fb35..d05c945ae4 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -64,7 +64,6 @@
#include "qqmlproperty_p.h"
#include "qqmlpropertycache_p.h"
#include "qqmlmetatype_p.h"
-#include "qqmldirparser_p.h"
#include <private/qintrusivelist_p.h>
#include <private/qrecyclepool_p.h>
#include <private/qfieldlist_p.h>
@@ -80,6 +79,7 @@
#include <private/qv8engine_p.h>
#include <private/qjsengine_p.h>
+#include <private/qqmldirparser_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 0c1ffbf3a0..ac2629979f 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -46,6 +46,7 @@
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
#include <private/qv8engine_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h
index c2d20ef0a3..d2eb79c5c9 100644
--- a/src/qml/qml/qqmlextensioninterface.h
+++ b/src/qml/qml/qqmlextensioninterface.h
@@ -51,14 +51,14 @@ class QQmlEngine;
class Q_QML_EXPORT QQmlTypesExtensionInterface
{
public:
- virtual ~QQmlTypesExtensionInterface() {}
+ virtual ~QQmlTypesExtensionInterface() = default;
virtual void registerTypes(const char *uri) = 0;
};
class Q_QML_EXPORT QQmlExtensionInterface : public QQmlTypesExtensionInterface
{
public:
- ~QQmlExtensionInterface() override {}
+ ~QQmlExtensionInterface() override = default;
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 99031e1e74..465a342129 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -64,6 +64,7 @@ static char file_string[] = "file";
#if defined(Q_OS_ANDROID)
static char assets_string[] = "assets";
+static char content_string[] = "content";
#endif
class QQmlFilePrivate;
@@ -452,6 +453,8 @@ bool QQmlFile::isSynchronous(const QUrl &url)
#if defined(Q_OS_ANDROID)
} else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
return true;
+ } else if (scheme.length() == 7 && 0 == scheme.compare(QLatin1String(content_string), Qt::CaseInsensitive)) {
+ return true;
#endif
} else {
@@ -492,7 +495,10 @@ bool QQmlFile::isSynchronous(const QString &url)
return url.length() >= 8 /* assets:/ */ &&
url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
-
+ } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
+ return url.length() >= 9 /* content:/ */ &&
+ url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
+ url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
}
#endif
@@ -556,7 +562,10 @@ bool QQmlFile::isLocalFile(const QString &url)
return url.length() >= 8 /* assets:/ */ &&
url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
-
+ } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
+ return url.length() >= 9 /* content:/ */ &&
+ url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
+ url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
}
#endif
@@ -580,6 +589,8 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
if (url.authority().isEmpty())
return url.toString();
return QString();
+ } else if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
+ return url.toString();
}
#endif
@@ -618,6 +629,8 @@ QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
#if defined(Q_OS_ANDROID)
else if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive)) {
return url;
+ } else if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive)) {
+ return url;
}
#endif
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 302fdd56c4..818537560c 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -174,16 +174,6 @@ T qmlobject_cast(QObject *object)
return 0;
}
-inline quint16 qmlSourceCoordinate(int n)
-{
- return (n > 0 && n <= static_cast<int>(USHRT_MAX)) ? static_cast<quint16>(n) : 0;
-}
-
-inline int qmlSourceCoordinate(quint16 n)
-{
- return (n == 0) ? -1 : static_cast<int>(n);
-}
-
#define IS_SIGNAL_CONNECTED(Sender, SenderType, Name, Arguments) \
do { \
QObject *sender = (Sender); \
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 1873a99a71..b21c3ec40d 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1081,13 +1081,6 @@ QString QQmlType::noCreationReason() const
return d->extraData.cd->noCreationReason;
}
-int QQmlType::createSize() const
-{
- if (!d || d->regType != CppType)
- return 0;
- return d->extraData.cd->allocationSize;
-}
-
bool QQmlType::isCreatable() const
{
return d && d->regType == CppType && d->extraData.cd->newFunc;
@@ -2151,11 +2144,14 @@ int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMet
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- QQmlType type(data->metaObjectToType.value(mo));
- if (type.attachedPropertiesFunction(engine))
- return type.attachedPropertiesId(engine);
- else
- return -1;
+ for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
+ it != end && it.key() == mo; ++it) {
+ const QQmlType type(it.value());
+ if (type.attachedPropertiesFunction(engine))
+ return type.attachedPropertiesId(engine);
+ }
+
+ return -1;
}
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 3c1589d19b..abc79e50e2 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -198,8 +198,6 @@ public:
typedef void (*CreateFunc)(void *);
CreateFunc createFunction() const;
- int createSize() const;
-
QQmlCustomParser *customParser() const;
bool isCreatable() const;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index b62b07e39c..26d3b5b6c1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -379,6 +379,28 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
}
+ auto assertOrNull = [&](bool ok)
+ {
+ Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_UNUSED(ok);
+ };
+
+ auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
+ {
+ Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_UNUSED(type);
+ };
+
+ if (property->isQObject()) {
+ if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ QObject *value = nullptr;
+ const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ return;
+ }
+ }
+
switch (propertyType) {
case QMetaType::QVariant: {
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
@@ -406,6 +428,13 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QVariant value(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (property->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
+ } else {
+ QVariant nullValue = QVariant::fromValue(nullptr);
+ property->writeProperty(_qobject, &nullValue, propertyWriteFlags);
+ }
} else {
QString stringValue = binding->valueAsString(compilationUnit.data());
if (property->isVarProperty()) {
@@ -419,25 +448,25 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QVariant::String: {
- Q_ASSERT(binding->evaluatesToString());
+ assertOrNull(binding->evaluatesToString());
QString value = binding->valueAsString(compilationUnit.data());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::StringList: {
- Q_ASSERT(binding->evaluatesToString());
+ assertOrNull(binding->evaluatesToString());
QStringList value(binding->valueAsString(compilationUnit.data()));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::ByteArray: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ assertType(QV4::CompiledData::Binding::Type_String);
QByteArray value(binding->valueAsString(compilationUnit.data()).toUtf8());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Url: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ assertType(QV4::CompiledData::Binding::Type_String);
QString string = binding->valueAsString(compilationUnit.data());
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
@@ -449,7 +478,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QVariant::UInt: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
double d = binding->valueAsNumber(compilationUnit->constants);
uint value = uint(d);
property->writeProperty(_qobject, &value, propertyWriteFlags);
@@ -457,7 +486,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QVariant::Int: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
double d = binding->valueAsNumber(compilationUnit->constants);
int value = int(d);
property->writeProperty(_qobject, &value, propertyWriteFlags);
@@ -465,13 +494,13 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QMetaType::Float: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
float value = float(binding->valueAsNumber(compilationUnit->constants));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Double: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
double value = binding->valueAsNumber(compilationUnit->constants);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
@@ -479,7 +508,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::Color: {
bool ok = false;
uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
struct { void *data[4]; } buffer;
if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
property->writeProperty(_qobject, &buffer, propertyWriteFlags);
@@ -490,14 +519,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::Date: {
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Time: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
@@ -510,7 +539,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
}
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
@@ -518,47 +547,47 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QVariant::Point: {
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok).toPoint();
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::PointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Size: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok).toSize();
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::SizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Rect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok).toRect();
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::RectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
- Q_ASSERT(ok);
+ assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Bool: {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+ assertType(QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
@@ -569,7 +598,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float yp;
} vec;
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
- Q_ASSERT(ok);
+ assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
@@ -581,7 +610,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float zy;
} vec;
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
- Q_ASSERT(ok);
+ assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
@@ -594,7 +623,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float wp;
} vec;
bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
- Q_ASSERT(ok);
+ assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
@@ -607,37 +636,37 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float zp;
} vec;
bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
- Q_ASSERT(ok);
+ assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
}
break;
case QVariant::RegExp:
- Q_ASSERT(!"not possible");
+ assertOrNull(!"not possible");
break;
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
QList<qreal> value;
value.append(binding->valueAsNumber(compilationUnit->constants));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QList<int> >()) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number);
+ assertType(QV4::CompiledData::Binding::Type_Number);
double n = binding->valueAsNumber(compilationUnit->constants);
QList<int> value;
value.append(int(n));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean);
+ assertType(QV4::CompiledData::Binding::Type_Boolean);
QList<bool> value;
value.append(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
+ assertType(QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(compilationUnit.data());
QUrl u = urlString.isEmpty() ? QUrl()
: compilationUnit->finalUrl().resolved(QUrl(urlString));
@@ -646,7 +675,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QList<QString> >()) {
- Q_ASSERT(binding->evaluatesToString());
+ assertOrNull(binding->evaluatesToString());
QList<QString> value;
value.append(binding->valueAsString(compilationUnit.data()));
property->writeProperty(_qobject, &value, propertyWriteFlags);
@@ -661,6 +690,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
value = QJSValue(int(n));
} else
value = QJSValue(n);
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ value = QJSValue::NullValue;
} else {
value = QJSValue(binding->valueAsString(compilationUnit.data()));
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 20d5c76029..73bfd7bbaa 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -898,6 +898,17 @@ struct StaticQtMetaObject : public QObject
{ return &staticQtMetaObject; }
};
+static bool isNamedEnumeratorInScope(const QMetaObject *resolvedMetaObject, const QByteArray &scope,
+ const QByteArray &name)
+{
+ for (int i = resolvedMetaObject->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = resolvedMetaObject->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return true;
+ }
+ return false;
+}
+
static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scopedName)
{
QByteArray scope;
@@ -909,52 +920,21 @@ static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scop
} else {
name = scopedName;
}
- const QMetaObject *meta;
- if (scope == "Qt")
- meta = StaticQtMetaObject::get();
- else
- meta = metaObj;
- for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = meta->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return true;
- }
- return false;
-}
-
-static bool passTypeAsInt(int type)
-{
- // We should not encounter the unknown type here.
- // In order to check that we need extra information.
- Q_ASSERT(type != QMetaType::UnknownType);
- const QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (scope == "Qt")
+ return isNamedEnumeratorInScope(StaticQtMetaObject::get(), scope, name);
- // Cast enumerations to int.
- if (flags & QMetaType::IsEnumeration)
+ if (isNamedEnumeratorInScope(metaObj, scope, name))
return true;
- // Qt builtins can be handled as they are.
- if (type < int(QMetaType::User))
- return false;
-
- // Pointers to QObjects and QGadgets, and QGadgets themselves can be handled as they are.
- if (flags & (QMetaType::PointerToQObject | QMetaType::PointerToGadget | QMetaType::IsGadget))
- return false;
-
- // If it wasn't declared as metatype, better don't touch it.
- if (!(flags & QMetaType::WasDeclaredAsMetaType))
- return false;
-
- // If it needs construction or destruction (that is, it is a structured type),
- // pass as original type.
- if (flags & (QMetaType::NeedsConstruction | QMetaType::NeedsDestruction))
- return false;
+ if (metaObj->d.relatedMetaObjects && !scope.isEmpty()) {
+ for (auto related = metaObj->d.relatedMetaObjects; *related; ++related) {
+ if (isNamedEnumeratorInScope(*related, scope, name))
+ return true;
+ }
+ }
- // A single value that's not a pointer to a QObject or QGadget, not a builtin type, was declared
- // as meta type, but we don't know it as an enumeration (although it probably is one).
- // Pass as int if it fits into an int.
- return QMetaType::sizeOf(type) <= int(sizeof(int));
+ return false;
}
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
@@ -1658,14 +1638,18 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u
propTypeName = m.typeName();
}
- if (type == QMetaType::UnknownType) {
+ if (QMetaType::sizeOf(type) <= int(sizeof(int))) {
+ if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration)
+ return QMetaType::Int;
+
if (isNamedEnumerator(metaObject(), propTypeName))
- type = QVariant::Int;
- else if (unknownTypeError)
- *unknownTypeError = propTypeName;
- } else if (passTypeAsInt(type)) {
- type = QVariant::Int;
- }
+ return QMetaType::Int;
+
+ if (type == QMetaType::UnknownType) {
+ if (unknownTypeError)
+ *unknownTypeError = propTypeName;
+ }
+ } // else we know that it's a known type, as sizeOf(UnknownType) == 0
return type;
}
@@ -1704,18 +1688,23 @@ int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QMetaType::UnknownType) {
+
+ if (QMetaType::sizeOf(type) > int(sizeof(int))) {
+ // Cannot be passed as int
+ // We know that it's a known type, as sizeOf(UnknownType) == 0
+ } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
+ type = QMetaType::Int;
+ } else {
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
if (isNamedEnumerator(metaObject, argTypeNames.at(ii))) {
- type = QVariant::Int;
- } else {
+ type = QMetaType::Int;
+ } else if (type == QMetaType::UnknownType){
if (unknownTypeError)
*unknownTypeError = argTypeNames.at(ii);
return nullptr;
}
- } else if (passTypeAsInt(type)) {
- type = QVariant::Int;
+
}
args->arguments[ii + 1] = type;
}
@@ -1741,18 +1730,21 @@ int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QMetaType::UnknownType) {
+ if (QMetaType::sizeOf(type) > int(sizeof(int))) {
+ // Cannot be passed as int
+ // We know that it's a known type, as sizeOf(UnknownType) == 0
+ } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
+ type = QMetaType::Int;
+ } else {
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
if (isNamedEnumerator(_m.asT2(), argTypeNames.at(ii))) {
- type = QVariant::Int;
- } else {
+ type = QMetaType::Int;
+ } else if (type == QMetaType::UnknownType) {
if (unknownTypeError)
*unknownTypeError = argTypeNames.at(ii);
return nullptr;
}
- } else if (passTypeAsInt(type)) {
- type = QVariant::Int;
}
argStorage->operator[](ii + 1) = type;
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index df6a8f1500..457558fb56 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1821,6 +1821,11 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
// assets resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
+ } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
+ path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
+ // content url
+ QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
+ return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
}
#endif
@@ -1878,6 +1883,11 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
// assets resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
return fileInfo.isFile();
+ } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
+ path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
+ // content url
+ QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
+ return fileInfo.isFile();
}
#endif
@@ -1891,8 +1901,6 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
if (!fileSet)
return false;
- QString absoluteFilePath;
-
bool *value = fileSet->object(file);
if (value) {
return *value;
@@ -1915,7 +1923,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
bool isResource = path.at(0) == QLatin1Char(':');
#if defined(Q_OS_ANDROID)
- isResource = isResource || path.startsWith(QLatin1String("assets:/"));
+ isResource = isResource || path.startsWith(QLatin1String("assets:/")) || path.startsWith(QLatin1String("content:/"));
#endif
if (isResource) {
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index cb6a467c6c..6fd0f0d37c 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -198,7 +198,6 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor,
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
: gadgetPtr(QMetaType::create(typeId))
- , typeId(typeId)
, metaType(typeId)
{
QObjectPrivate *op = QObjectPrivate::get(this);
@@ -237,12 +236,12 @@ void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags fl
QVariant QQmlValueType::value()
{
Q_ASSERT(gadgetPtr);
- return QVariant(typeId, gadgetPtr);
+ return QVariant(metaType.id(), gadgetPtr);
}
void QQmlValueType::setValue(const QVariant &value)
{
- Q_ASSERT(typeId == value.userType());
+ Q_ASSERT(metaType.id() == value.userType());
metaType.destruct(gadgetPtr);
metaType.construct(gadgetPtr, value.constData());
}
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 4ea71e8955..89f1b71d61 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -84,7 +84,6 @@ private:
void *gadgetPtr;
public:
- int typeId;
QMetaType metaType;
};
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index b22d1530e2..7df5757b95 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -107,7 +107,7 @@ void Heap::QQmlValueTypeWrapper::destroy()
void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
{
- Q_ASSERT(valueType->typeId == value.userType());
+ Q_ASSERT(valueType->metaType.id() == value.userType());
if (gadgetPtr)
valueType->metaType.destruct(gadgetPtr);
if (!gadgetPtr)
@@ -118,7 +118,7 @@ void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
Q_ASSERT(gadgetPtr);
- return QVariant(valueType->typeId, gadgetPtr);
+ return QVariant(valueType->metaType.id(), gadgetPtr);
}
@@ -223,7 +223,7 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
if (!ref->readReferenceValue())
return false;
- const int typeId = d()->valueType->typeId;
+ const int typeId = d()->valueType->metaType.id();
QMetaType::destruct(typeId, data);
QMetaType::construct(typeId, data, d()->gadgetPtr);
return true;
@@ -307,7 +307,7 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType->typeId;
+ return d()->valueType->metaType.id();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
@@ -354,10 +354,10 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
// Prepare a buffer to pass to QMetaType::convert()
QString convertResult;
convertResult.~QString();
- if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) {
+ if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->metaType.id(), &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
- result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId))
+ result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->metaType.id()))
+ QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache()->metaObject();
const int propCount = mo->propertyCount();
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index f713efb289..64dc581a56 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1527,6 +1527,27 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
+static QString serializeArray(Object *array, ExecutionEngine *v4) {
+ Scope scope(v4);
+ ScopedValue val(scope);
+ QString result;
+
+ result += QLatin1Char('[');
+ const uint length = array->getLength();
+ for (uint i = 0; i < length; ++i) {
+ if (i != 0)
+ result += QLatin1Char(',');
+ val = array->get(i);
+ if (val->isManaged() && val->managed()->isArrayLike())
+ result += serializeArray(val->objectValue(), v4);
+ else
+ result += val->toQStringNoThrow();
+ }
+ result += QLatin1Char(']');
+
+ return result;
+};
+
static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, const Value *argv, int argc,
ConsoleLogTypes logType, bool printStack = false)
{
@@ -1554,7 +1575,7 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
result.append(QLatin1Char(' '));
if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
- result += QLatin1Char('[') + argv[i].toQStringNoThrow() + QLatin1Char(']');
+ result.append(serializeArray(argv[i].objectValue(), v4));
else
result.append(argv[i].toQStringNoThrow());
}
diff --git a/src/qml/qmldirparser/qmldirparser.pri b/src/qml/qmldirparser/qmldirparser.pri
new file mode 100644
index 0000000000..660e7b395a
--- /dev/null
+++ b/src/qml/qmldirparser/qmldirparser.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$OUT_PWD
+
+HEADERS += \
+ $$PWD/qqmldirparser_p.h \
+ $$PWD/qqmlerror.h \
+ $$PWD/qqmlsourcecoordinate_p.h
+
+SOURCES += \
+ $$PWD/qqmldirparser.cpp \
+ $$PWD/qqmlerror.cpp
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index d87bf433b8..e944b52e47 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -367,12 +367,10 @@ QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
return _scripts;
}
-#ifdef QT_CREATOR
QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
{
return _typeInfos;
}
-#endif
bool QQmlDirParser::designerSupported() const
{
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index d7e29813d1..cff9cb11a4 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -122,7 +122,6 @@ public:
QList<Plugin> plugins() const;
bool designerSupported() const;
-#ifdef QT_CREATOR
struct TypeInfo
{
TypeInfo() {}
@@ -133,7 +132,6 @@ public:
};
QList<TypeInfo> typeInfos() const;
-#endif
QString className() const;
@@ -149,9 +147,7 @@ private:
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported;
-#ifdef QT_CREATOR
QList<TypeInfo> _typeInfos;
-#endif
QString _className;
};
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qmldirparser/qqmlerror.cpp
index 61e9a3f37e..5e181f7e27 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qmldirparser/qqmlerror.cpp
@@ -38,15 +38,17 @@
****************************************************************************/
#include "qqmlerror.h"
-#include "qqmlglobal_p.h"
+#include "qqmlsourcecoordinate_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
-#include <QtCore/qpointer.h>
-#include <private/qv4errorobject_p.h>
+#ifndef QT_NO_QOBJECT
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -85,11 +87,13 @@ public:
quint16 line;
quint16 column;
QtMsgType messageType;
+#ifndef QT_NO_QOBJECT
QPointer<QObject> object;
+#endif
};
QQmlErrorPrivate::QQmlErrorPrivate()
-: line(0), column(0), messageType(QtMsgType::QtWarningMsg), object()
+: line(0), column(0), messageType(QtMsgType::QtWarningMsg)
{
}
@@ -125,7 +129,9 @@ QQmlError &QQmlError::operator=(const QQmlError &other)
d->description = other.d->description;
d->line = other.d->line;
d->column = other.d->column;
+#ifndef QT_NO_QOBJECT
d->object = other.d->object;
+#endif
d->messageType = other.d->messageType;
}
return *this;
@@ -227,6 +233,7 @@ void QQmlError::setColumn(int column)
d->column = qmlSourceCoordinate(column);
}
+#ifndef QT_NO_QOBJECT
/*!
Returns the nearest object where this error occurred.
Exceptions in bound property expressions set this to the object
@@ -249,6 +256,7 @@ void QQmlError::setObject(QObject *object)
d = new QQmlErrorPrivate;
d->object = object;
}
+#endif // QT_NO_QOBJECT
/*!
\since 5.9
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qmldirparser/qqmlerror.h
index ef529e3828..f4221358e9 100644
--- a/src/qml/qml/qqmlerror.h
+++ b/src/qml/qmldirparser/qqmlerror.h
@@ -68,8 +68,12 @@ public:
void setLine(int);
int column() const;
void setColumn(int);
+
+#ifndef QT_NO_QOBJECT
QObject *object() const;
void setObject(QObject *);
+#endif
+
QtMsgType messageType() const;
void setMessageType(QtMsgType messageType);
diff --git a/src/qml/qmldirparser/qqmlsourcecoordinate_p.h b/src/qml/qmldirparser/qqmlsourcecoordinate_p.h
new file mode 100644
index 0000000000..76ac741ae8
--- /dev/null
+++ b/src/qml/qmldirparser/qqmlsourcecoordinate_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSOURCECOORDINATE_P_H
+#define QQMLSOURCECOORDINATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#include <climits>
+
+QT_BEGIN_NAMESPACE
+
+inline quint16 qmlSourceCoordinate(int n)
+{
+ return (n > 0 && n <= static_cast<int>(USHRT_MAX)) ? static_cast<quint16>(n) : 0;
+}
+
+inline int qmlSourceCoordinate(quint16 n)
+{
+ return (n == 0) ? -1 : static_cast<int>(n);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLSOURCECOORDINATE_P_H
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index e02dfa5ed4..090b830b3c 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -53,6 +53,7 @@
#else
# define QT_FEATURE_qml_debug -1
# define QT_FEATURE_qml_sequence_object 1
+# define QT_FEATURE_qml_tracing -1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 69b7876cf6..565e60b3c1 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2764,6 +2764,8 @@ bool QQmlListModelParser::applyProperty(const QQmlRefPointer<QV4::CompiledData::
value = binding->valueAsNumber(compilationUnit->constants);
} else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
value = binding->valueAsBoolean();
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ value = QVariant::fromValue(nullptr);
} else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = binding->valueAsScriptString(compilationUnit.data());
if (definesEmptyList(scriptStr)) {
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index fe51f8ec47..edb112276c 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -481,7 +481,7 @@ void QQuickWorkerScriptEngine::run()
\qmltype WorkerScript
\instantiates QQuickWorkerScript
\ingroup qtquick-threading
- \inqmlmodule QtQuick
+ \inqmlmodule QtQml
\brief Enables the use of threads in a Qt Quick application.
Use WorkerScript to run operations in a new thread.