diff options
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 11 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 65 | ||||
-rw-r--r-- | src/qml/compiler/qqmlpropertyvalidator.cpp | 80 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodegenerator.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodegenerator_p.h | 70 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodehandler.cpp | 455 | ||||
-rw-r--r-- | src/qml/compiler/qv4bytecodehandler_p.h | 10 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 140 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 21 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 15 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext.cpp | 24 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 75 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 73 |
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 */ |