diff options
Diffstat (limited to 'src/qmlcompiler')
| -rw-r--r-- | src/qmlcompiler/qqmljsbasicblocks.cpp | 2 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 2 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscompilepass_p.h | 76 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 37 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 8 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsshadowcheck.cpp | 2 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 115 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstypepropagator_p.h | 2 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmlsa.cpp | 7 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmlsa_p.h | 3 |
10 files changed, 161 insertions, 93 deletions
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp index d5bbae037f..e95ad114e4 100644 --- a/src/qmlcompiler/qqmljsbasicblocks.cpp +++ b/src/qmlcompiler/qqmljsbasicblocks.cpp @@ -216,7 +216,7 @@ void QQmlJSBasicBlocks::populateReaderLocations() m_readerLocations.erase(reader); // If it's not a label and has no side effects, we can drop the instruction. - if (!it->second.hasSideEffects) { + if (!it->second.hasInternalSideEffects) { if (!it->second.readRegisters.isEmpty()) { it->second.readRegisters.clear(); erasedReaders = true; diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp index 01ef6a95e6..709dcbea8f 100644 --- a/src/qmlcompiler/qqmljscodegenerator.cpp +++ b/src/qmlcompiler/qqmljscodegenerator.cpp @@ -2561,7 +2561,7 @@ QV4::Moth::ByteCodeHandler::Verdict QQmlJSCodeGenerator::startInstruction( // If the instruction has no side effects and doesn't write any register, it's dead. // We might still need the label, though, and the source code comment. - if (!m_state.hasSideEffects() && changedRegisterVariable().isEmpty()) { + if (!m_state.hasInternalSideEffects() && changedRegisterVariable().isEmpty()) { generateJumpCodeWithTypeConversions(0); return SkipInstruction; } diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h index b35adfb66a..7ca9744bb1 100644 --- a/src/qmlcompiler/qqmljscompilepass_p.h +++ b/src/qmlcompiler/qqmljscompilepass_p.h @@ -64,7 +64,8 @@ public: QQmlJSRegisterContent changedRegister; int changedRegisterIndex = InvalidRegister; - bool hasSideEffects = false; + bool hasInternalSideEffects = false; + bool hasExternalSideEffects = false; bool isRename = false; }; @@ -158,16 +159,33 @@ public: return m_readRegisters.contains(registerIndex); } - bool hasSideEffects() const { return m_hasSideEffects; } - void setHasSideEffects(bool hasSideEffects) { - m_hasSideEffects = hasSideEffects; - if (!hasSideEffects) + bool hasInternalSideEffects() const { return m_hasInternalSideEffects; } + bool hasExternalSideEffects() const { return m_hasExternalSideEffects; } + + void resetSideEffects() + { + m_hasInternalSideEffects = false; + m_hasExternalSideEffects = false; + } + + void applyExternalSideEffects(bool hasExternalSideEffects) + { + if (!hasExternalSideEffects) return; for (auto it = registers.begin(), end = registers.end(); it != end; ++it) it.value().affectedBySideEffects = true; } + void setHasInternalSideEffects() { m_hasInternalSideEffects = true; } + void setHasExternalSideEffects() + { + m_hasExternalSideEffects = true; + m_hasInternalSideEffects = true; + applyExternalSideEffects(true); + } + + bool isRename() const { return m_isRename; } void setIsRename(bool isRename) { m_isRename = isRename; } @@ -178,11 +196,36 @@ public: return m_readRegisters.begin().key(); } + void applyAnnotation(const InstructionAnnotation &annotation) + { + m_readRegisters = annotation.readRegisters; + + m_hasInternalSideEffects = annotation.hasInternalSideEffects; + m_hasExternalSideEffects = annotation.hasExternalSideEffects; + m_isRename = annotation.isRename; + + for (auto it = annotation.typeConversions.constBegin(), + end = annotation.typeConversions.constEnd(); it != end; ++it) { + Q_ASSERT(it.key() != InvalidRegister); + registers[it.key()] = it.value(); + } + + if (annotation.changedRegisterIndex != InvalidRegister) + setRegister(annotation.changedRegisterIndex, annotation.changedRegister); + } + private: VirtualRegisters m_readRegisters; QQmlJSRegisterContent m_changedRegister; int m_changedRegisterIndex = InvalidRegister; - bool m_hasSideEffects = false; + + // If the instruction's value is unused, we still cannot optimize it out. + bool m_hasInternalSideEffects = false; + + // Side effect created by calls to other functions or writes to properties, + // affects tracked value types and lists. Implies the effects of Internal. + bool m_hasExternalSideEffects = false; + bool m_isRename = false; }; @@ -245,23 +288,12 @@ protected: = oldState.changedRegister(); } - if (instruction == annotations.constEnd()) - return newState; - - newState.setHasSideEffects(instruction->second.hasSideEffects); - newState.setReadRegisters(instruction->second.readRegisters); - newState.setIsRename(instruction->second.isRename); + // Side effects are applied at the end of an instruction: An instruction with side + // effects can still read its registers before the side effects happen. + newState.applyExternalSideEffects(oldState.hasExternalSideEffects()); - for (auto it = instruction->second.typeConversions.begin(), - end = instruction->second.typeConversions.end(); it != end; ++it) { - Q_ASSERT(it.key() != InvalidRegister); - newState.registers[it.key()] = it.value(); - } - - if (instruction->second.changedRegisterIndex != InvalidRegister) { - newState.setRegister(instruction->second.changedRegisterIndex, - instruction->second.changedRegister); - } + if (instruction != annotations.constEnd()) + newState.applyAnnotation(instruction->second); return newState; } diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 4bc215add7..bd693cc619 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -18,6 +18,7 @@ #include <QtQml/private/qqmlirbuilder_p.h> #include "qqmljsscope_p.h" #include "qqmljsutils_p.h" +#include "qqmlsa_p.h" #include <algorithm> #include <variant> @@ -799,8 +800,8 @@ void QQmlJSImportVisitor::checkRequiredProperties() } } - const auto isInComponent = [this](const QQmlJSScope::ConstPtr &requiredScope) { - const auto compType = m_rootScopeImports.type(u"Component"_s).scope; + const auto compType = m_rootScopeImports.type(u"Component"_s).scope; + const auto isInComponent = [&](const QQmlJSScope::ConstPtr &requiredScope) { for (auto s = requiredScope; s; s = s->parentScope()) { if (s->isWrappedInImplicitComponent() || s->baseType() == compType) return true; @@ -811,9 +812,11 @@ void QQmlJSImportVisitor::checkRequiredProperties() const auto requiredHasBinding = [](const QList<QQmlJSScope::ConstPtr> &scopesToSearch, const QString &propName) { for (const auto &scope : scopesToSearch) { + if (scope->property(propName).isAlias()) + continue; const auto &[begin, end] = scope->ownPropertyBindings(propName); for (auto it = begin; it != end; ++it) { - if (!scope->property(propName).isAlias()) + if (QQmlSA::isRegularBindingType(it->bindingType())) return true; } } @@ -880,16 +883,17 @@ void QQmlJSImportVisitor::checkRequiredProperties() : u"here"_s; if (!prevRequiredScope.isNull()) { - auto sourceScope = prevRequiredScope->baseType(); - suggestion = QQmlJSFixSuggestion{ - "%1:%2:%3: Property marked as required in %4."_L1 - .arg(sourceScope->filePath()) - .arg(sourceScope->sourceLocation().startLine) - .arg(sourceScope->sourceLocation().startColumn) - .arg(requiredScopeName), - sourceScope->sourceLocation() - }; - suggestion->setFilename(sourceScope->filePath()); + if (auto sourceScope = prevRequiredScope->baseType()) { + suggestion = QQmlJSFixSuggestion{ + "%1:%2:%3: Property marked as required in %4."_L1 + .arg(sourceScope->filePath()) + .arg(sourceScope->sourceLocation().startLine) + .arg(sourceScope->sourceLocation().startColumn) + .arg(requiredScopeName), + sourceScope->sourceLocation() + }; + suggestion->setFilename(sourceScope->filePath()); + } } else { message += " (marked as required by %1)"_L1.arg(requiredScopeName); } @@ -902,7 +906,8 @@ void QQmlJSImportVisitor::checkRequiredProperties() for (const auto &[_, defScope] : m_scopesByIrLocation.asKeyValueRange()) { if (defScope->parentScope() == m_globalScope || defScope->isInlineComponent() - || defScope->isComponentRootElement()) { + || defScope->isComponentRootElement() + || defScope->scopeType() != QQmlJSScope::QMLScope) { continue; } @@ -917,6 +922,8 @@ void QQmlJSImportVisitor::checkRequiredProperties() for (auto propertyIt = ownProperties.constBegin(); propertyIt != ownProperties.constEnd(); ++propertyIt) { const QString propName = propertyIt.key(); + if (descendant->hasOwnPropertyBindings(propName)) + continue; QQmlJSScope::ConstPtr prevRequiredScope; for (QQmlJSScope::ConstPtr requiredScope : std::as_const(scopesToSearch)) { @@ -1613,7 +1620,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember) auto tryParseAlias = [&]() { typeName.clear(); // type name is useless for alias here, so keep it empty if (!publicMember->statement) { - m_logger->log(QStringLiteral("Invalid alias expression – an initalizer is needed."), + m_logger->log(QStringLiteral("Invalid alias expression - an initalizer is needed."), qmlSyntax, publicMember->memberType->firstSourceLocation()); // TODO: extend warning to cover until endSourceLocation return; } diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index 5067210261..29a0db05cf 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -361,9 +361,15 @@ qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes & if (current->isInlineComponent() && current->inlineComponentName() == inlineComponentName) { return { current, inlineComponentParent.revision }; } + // check alternatively the inline components at layer 1 in current and basetype, then at // layer 2, etc... - candidatesForInlineComponents.append(current->childScopes()); + const auto &childScopes = current->childScopes(); + for (const auto &child : childScopes) { + if (child->scopeType() == QQmlJSScope::ScopeType::QMLScope) + candidatesForInlineComponents.enqueue(child); + } + if (const auto base = current->baseType()) candidatesForInlineComponents.enqueue(base); } diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp index ead1813afe..600e40d389 100644 --- a/src/qmlcompiler/qqmljsshadowcheck.cpp +++ b/src/qmlcompiler/qqmljsshadowcheck.cpp @@ -72,7 +72,7 @@ void QQmlJSShadowCheck::generate_SetLookup(int index, int base) QV4::Moth::ByteCodeHandler::Verdict QQmlJSShadowCheck::startInstruction(QV4::Moth::Instr::Type) { m_state = nextStateFromAnnotations(m_state, *m_annotations); - return (m_state.hasSideEffects() || m_state.changedRegisterIndex() != InvalidRegister) + return (m_state.hasInternalSideEffects() || m_state.changedRegisterIndex() != InvalidRegister) ? ProcessInstruction : SkipInstruction; } diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index 06b49d067d..bff83817fe 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -105,7 +105,7 @@ void QQmlJSTypePropagator::generate_Ret() addReadAccumulator(m_returnType); } - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); m_state.skipInstructionsUntilNextJumpTarget = true; } @@ -631,7 +631,7 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex) m_function->qmlScope, getCurrentSourceLocation()); } - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); if (m_typeResolver->canHoldUndefined(in) && !m_typeResolver->canHoldUndefined(type)) { if (type.property().reset().isEmpty()) @@ -725,7 +725,7 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index) // Writing to a JS array can have side effects all over the place since it's // passed by reference. - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); return; } @@ -742,7 +742,7 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index) // If we're writing to a list retrieved from a property, that _should_ have side effects, // but currently the QML engine doesn't implement them. // TODO: Figure out the above and accurately set the flag. - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); } void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName) @@ -963,7 +963,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base) addReadAccumulator(property); addReadRegister(base, callBase); - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); } void QQmlJSTypePropagator::generate_SetLookup(int index, int base) @@ -1000,7 +1000,7 @@ void QQmlJSTypePropagator::generate_Resume(int) void QQmlJSTypePropagator::generate_CallValue(int name, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(name) Q_UNUSED(argc) Q_UNUSED(argv) @@ -1009,7 +1009,7 @@ void QQmlJSTypePropagator::generate_CallValue(int name, int argc, int argv) void QQmlJSTypePropagator::generate_CallWithReceiver(int name, int thisObject, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(name) Q_UNUSED(thisObject) Q_UNUSED(argc) @@ -1075,7 +1075,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar for (int i = 1; i < argc; ++i) addReadRegister(argv + i, stringType); - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); setAccumulator(voidType); return; } @@ -1087,7 +1087,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar for (int i = 0; i < argc; ++i) addReadRegister(argv + i, jsValueType); setAccumulator(jsValueType); - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); return; } @@ -1238,14 +1238,17 @@ void QQmlJSTypePropagator::setRegister(int index, const QQmlJSRegisterContent &c } void QQmlJSTypePropagator::mergeRegister( - int index, const QQmlJSRegisterContent &a, const QQmlJSRegisterContent &b) + int index, const VirtualRegister &a, const VirtualRegister &b) { - auto merged = m_typeResolver->merge(a, b); + const VirtualRegister merged = { + m_typeResolver->merge(a.content, b.content), + a.affectedBySideEffects || b.affectedBySideEffects, + }; - Q_ASSERT(merged.isValid()); - Q_ASSERT(merged.isConversion()); + Q_ASSERT(merged.content.isValid()); + Q_ASSERT(merged.content.isConversion()); - auto tryPrevStateConversion = [this](int index, const QQmlJSRegisterContent &merged) -> bool { + auto tryPrevStateConversion = [this](int index, const VirtualRegister &merged) -> bool { auto it = m_prevStateAnnotations.find(currentInstructionOffset()); if (it == m_prevStateAnnotations.end()) return false; @@ -1259,22 +1262,31 @@ void QQmlJSTypePropagator::mergeRegister( Q_ASSERT(lastTry.content.isValid()); Q_ASSERT(lastTry.content.isConversion()); - if (!m_typeResolver->equals(lastTry.content.conversionResult(), merged.conversionResult()) - || lastTry.content.conversionOrigins() != merged.conversionOrigins()) { + if (!m_typeResolver->equals(lastTry.content.conversionResult(), + merged.content.conversionResult()) + || lastTry.content.conversionOrigins() != merged.content.conversionOrigins() + || lastTry.affectedBySideEffects != merged.affectedBySideEffects) { return false; } // We don't need to track it again if we've come to the same conclusion before. m_state.annotations[currentInstructionOffset()].typeConversions[index] = lastTry; + + // Do not reset the side effects + Q_ASSERT(!m_state.registers[index].affectedBySideEffects || lastTry.affectedBySideEffects); + m_state.registers[index] = lastTry; return true; }; if (!tryPrevStateConversion(index, merged)) { - merged = m_typeResolver->tracked(merged); - Q_ASSERT(merged.isValid()); - m_state.annotations[currentInstructionOffset()].typeConversions[index].content = merged; - m_state.registers[index].content = merged; + const VirtualRegister cloned = { + m_typeResolver->tracked(merged.content), + merged.affectedBySideEffects, + }; + Q_ASSERT(cloned.content.isValid()); + m_state.annotations[currentInstructionOffset()].typeConversions[index] = cloned; + m_state.registers[index] = cloned; } } @@ -1316,7 +1328,7 @@ void QQmlJSTypePropagator::propagateCall( if (!m_state.accumulatorOut().isValid()) setError(u"Cannot store return type of method %1()."_s.arg(match.methodName())); - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); const auto types = match.parameters(); for (int i = 0; i < argc; ++i) { if (i < types.size()) { @@ -1478,7 +1490,7 @@ void QQmlJSTypePropagator::generate_CallName(int name, int argc, int argv) void QQmlJSTypePropagator::generate_CallPossiblyDirectEval(int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(argc) Q_UNUSED(argv) INSTR_PROLOGUE_NOT_IMPLEMENTED(); @@ -1523,7 +1535,7 @@ void QQmlJSTypePropagator::generate_CallQmlContextPropertyLookup(int index, int void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(func) Q_UNUSED(thisObject) Q_UNUSED(argc) @@ -1533,7 +1545,7 @@ void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int void QQmlJSTypePropagator::generate_TailCall(int func, int thisObject, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(func) Q_UNUSED(thisObject) Q_UNUSED(argc) @@ -1543,7 +1555,7 @@ void QQmlJSTypePropagator::generate_TailCall(int func, int thisObject, int argc, void QQmlJSTypePropagator::generate_Construct(int func, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(func) Q_UNUSED(argv) @@ -1554,7 +1566,7 @@ void QQmlJSTypePropagator::generate_Construct(int func, int argc, int argv) void QQmlJSTypePropagator::generate_ConstructWithSpread(int func, int argc, int argv) { - m_state.setHasSideEffects(true); + m_state.setHasExternalSideEffects(); Q_UNUSED(func) Q_UNUSED(argc) Q_UNUSED(argv) @@ -1563,20 +1575,20 @@ void QQmlJSTypePropagator::generate_ConstructWithSpread(int func, int argc, int void QQmlJSTypePropagator::generate_SetUnwindHandler(int offset) { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); Q_UNUSED(offset) INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE(); } void QQmlJSTypePropagator::generate_UnwindDispatch() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE(); } void QQmlJSTypePropagator::generate_UnwindToLabel(int level, int offset) { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); Q_UNUSED(level) Q_UNUSED(offset) INSTR_PROLOGUE_NOT_IMPLEMENTED(); @@ -1591,7 +1603,7 @@ void QQmlJSTypePropagator::generate_DeadTemporalZoneCheck(int name) void QQmlJSTypePropagator::generate_ThrowException() { addReadAccumulator(m_typeResolver->globalType(m_typeResolver->jsValueType())); - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); m_state.skipInstructionsUntilNextJumpTarget = true; } @@ -1602,18 +1614,18 @@ void QQmlJSTypePropagator::generate_GetException() void QQmlJSTypePropagator::generate_SetException() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_CreateCallContext() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); } void QQmlJSTypePropagator::generate_PushCatchContext(int index, int name) { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); Q_UNUSED(index) Q_UNUSED(name) INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE(); @@ -1621,39 +1633,39 @@ void QQmlJSTypePropagator::generate_PushCatchContext(int index, int name) void QQmlJSTypePropagator::generate_PushWithContext() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_PushBlockContext(int index) { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); Q_UNUSED(index) INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_CloneBlockContext() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_PushScriptContext(int index) { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); Q_UNUSED(index) INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_PopScriptContext() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); INSTR_PROLOGUE_NOT_IMPLEMENTED(); } void QQmlJSTypePropagator::generate_PopContext() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); } void QQmlJSTypePropagator::generate_GetIterator(int iterator) @@ -1784,7 +1796,7 @@ void QQmlJSTypePropagator::generate_Jump(int offset) { saveRegisterStateForJump(offset); m_state.skipInstructionsUntilNextJumpTarget = true; - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); } void QQmlJSTypePropagator::generate_JumpTrue(int offset) @@ -1796,7 +1808,7 @@ void QQmlJSTypePropagator::generate_JumpTrue(int offset) return; } saveRegisterStateForJump(offset); - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); addReadAccumulator(m_typeResolver->globalType(m_typeResolver->boolType())); } @@ -1809,14 +1821,14 @@ void QQmlJSTypePropagator::generate_JumpFalse(int offset) return; } saveRegisterStateForJump(offset); - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); addReadAccumulator(m_typeResolver->globalType(m_typeResolver->boolType())); } void QQmlJSTypePropagator::generate_JumpNoException(int offset) { saveRegisterStateForJump(offset); - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); } void QQmlJSTypePropagator::generate_JumpNotUndefined(int offset) @@ -1827,7 +1839,7 @@ void QQmlJSTypePropagator::generate_JumpNotUndefined(int offset) void QQmlJSTypePropagator::generate_CheckException() { - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); } void QQmlJSTypePropagator::recordEqualsNullType() @@ -2199,7 +2211,7 @@ void QQmlJSTypePropagator::generate_InitializeBlockDeadTemporalZone(int firstReg { Q_UNUSED(firstReg) Q_UNUSED(count) - m_state.setHasSideEffects(true); + m_state.setHasInternalSideEffects(); // Ignore. We reject uninitialized values anyway. } @@ -2254,8 +2266,8 @@ QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type) registerIt != end; ++registerIt) { const int registerIndex = registerIt.key(); - auto newType = registerIt.value().content; - if (!newType.isValid()) { + const VirtualRegister &newType = registerIt.value(); + if (!newType.content.isValid()) { setError(u"When reached from offset %1, %2 is undefined"_s .arg(stateToMerge.originatingOffset) .arg(registerName(registerIndex))); @@ -2264,7 +2276,7 @@ QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type) auto currentRegister = m_state.registers.find(registerIndex); if (currentRegister != m_state.registers.end()) - mergeRegister(registerIndex, newType, currentRegister.value().content); + mergeRegister(registerIndex, newType, currentRegister.value()); else mergeRegister(registerIndex, newType, newType); } @@ -2279,7 +2291,8 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr) currentInstruction.changedRegister = m_state.changedRegister(); currentInstruction.changedRegisterIndex = m_state.changedRegisterIndex(); currentInstruction.readRegisters = m_state.takeReadRegisters(); - currentInstruction.hasSideEffects = m_state.hasSideEffects(); + currentInstruction.hasExternalSideEffects = m_state.hasExternalSideEffects(); + currentInstruction.hasInternalSideEffects = m_state.hasInternalSideEffects(); currentInstruction.isRename = m_state.isRename(); switch (instr) { @@ -2323,7 +2336,7 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr) && instr != QV4::Moth::Instr::Type::DeadTemporalZoneCheck) { // An instruction needs to have side effects or write to another register otherwise it's a // noop. DeadTemporalZoneCheck is not needed by the compiler and is ignored. - Q_ASSERT(m_state.hasSideEffects() || m_state.changedRegisterIndex() != -1); + Q_ASSERT(m_state.hasInternalSideEffects() || m_state.changedRegisterIndex() != -1); } if (m_state.changedRegisterIndex() != InvalidRegister) { @@ -2335,7 +2348,7 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr) m_state.clearChangedRegister(); } - m_state.setHasSideEffects(false); + m_state.resetSideEffects(); m_state.setIsRename(false); m_state.setReadRegisters(VirtualRegisters()); } diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h index dd0c0ec750..99a421a4a1 100644 --- a/src/qmlcompiler/qqmljstypepropagator_p.h +++ b/src/qmlcompiler/qqmljstypepropagator_p.h @@ -227,7 +227,7 @@ private: void setAccumulator(const QQmlJSRegisterContent &content); void setRegister(int index, const QQmlJSRegisterContent &content); - void mergeRegister(int index, const QQmlJSRegisterContent &a, const QQmlJSRegisterContent &b); + void mergeRegister(int index, const VirtualRegister &a, const VirtualRegister &b); void addReadRegister(int index, const QQmlJSRegisterContent &convertTo); void addReadAccumulator(const QQmlJSRegisterContent &convertTo) diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp index 7a209f52c1..388a5fe599 100644 --- a/src/qmlcompiler/qqmlsa.cpp +++ b/src/qmlcompiler/qqmlsa.cpp @@ -360,6 +360,13 @@ void DebugPropertyPass::onWrite(const QQmlSA::Element &element, const QString &p + QString::number(location.startColumn), qmlPlugin, location); } + +bool isRegularBindingType(QQmlJSMetaPropertyBinding::BindingType type) +{ + return type >= QQmlJSMetaPropertyBinding::BindingType::BoolLiteral + && type <= QQmlJSMetaPropertyBinding::BindingType::Object; +} + } QT_END_NAMESPACE diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h index 6bbbe9441b..18caee3640 100644 --- a/src/qmlcompiler/qqmlsa_p.h +++ b/src/qmlcompiler/qqmlsa_p.h @@ -183,6 +183,9 @@ public: const QQmlSA::Element &value, const QQmlSA::Element &writeScope, QQmlJS::SourceLocation location) override; }; + +bool isRegularBindingType(QQmlJSMetaPropertyBinding::BindingType type); + } #define QmlLintPluginInterface_iid "org.qt-project.Qt.Qml.SA.LintPlugin/1.0" |
