aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp11
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h65
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp80
-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
15 files changed, 348 insertions, 706 deletions
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..1beaac8095 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,8 +689,6 @@ 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())) {
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 8f2f4a11c1..e6d079fe36 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 8f3b60e395..cb20ea9d57 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;
@@ -362,6 +364,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 */