aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2025-06-26 12:37:56 +0200
committerUlf Hermann <ulf.hermann@qt.io>2025-06-27 21:56:31 +0200
commitb9974d82cd134b51bd1833c3e62c7345c8ea2962 (patch)
tree9ec0ca62812dd11d388cd70473015ec6734eb074 /src/qmlcompiler
parentb1bdad8096a45098d6ac668142493cccfd019579 (diff)
QmlCompiler: Preserve external side effects across jumps
Now that we discern internal and external side effects, we cannot implicitly rely on every jump to generate a side effect anymore. We need to actually update the virtual registers and also merge the side effects (along with other flags). Amends commit 6b14ba5c2fbc2810bb62a87008e338cca571acf6 Pick-to: 6.10 6.9 6.8 6.5 Task-number: QTBUG-137540 Change-Id: I6b46c7a4773759c8f6f30308ba72082555ce3e61 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Diffstat (limited to 'src/qmlcompiler')
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp50
-rw-r--r--src/qmlcompiler/qqmljstypepropagator_p.h2
2 files changed, 35 insertions, 17 deletions
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index e5b0446e7d..76465ea214 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -1535,19 +1535,25 @@ void QQmlJSTypePropagator::setRegister(int index, QQmlJSRegisterContent content)
}
void QQmlJSTypePropagator::mergeRegister(
- int index, QQmlJSRegisterContent a, QQmlJSRegisterContent b)
+ int index, const VirtualRegister &a, const VirtualRegister &b)
{
- const QQmlJSRegisterContent merged = (a == b) ? a : m_typeResolver->merge(a, b);
- Q_ASSERT(merged.isValid());
+ const VirtualRegister merged = {
+ (a.content == b.content) ? a.content : m_typeResolver->merge(a.content, b.content),
+ a.canMove && b.canMove,
+ a.affectedBySideEffects || b.affectedBySideEffects,
+ a.isShadowable || b.isShadowable,
+ };
+
+ Q_ASSERT(merged.content.isValid());
- if (!merged.isConversion()) {
+ if (!merged.content.isConversion()) {
// The registers were the same. We're already tracking them.
- m_state.annotations[currentInstructionOffset()].typeConversions[index].content = merged;
- m_state.registers[index].content = merged;
+ m_state.annotations[currentInstructionOffset()].typeConversions[index] = merged;
+ m_state.registers[index] = merged;
return;
}
- auto tryPrevStateConversion = [this](int index, 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;
@@ -1562,23 +1568,35 @@ void QQmlJSTypePropagator::mergeRegister(
if (!lastTry.content.isConversion())
return false;
- if (lastTry.content.conversionResultType() != merged.conversionResultType()
- || lastTry.content.conversionOrigins() != merged.conversionOrigins()) {
+ if (lastTry.content.conversionResultType() != merged.content.conversionResultType()
+ || lastTry.content.conversionOrigins() != merged.content.conversionOrigins()
+ || lastTry.canMove != merged.canMove
+ || lastTry.affectedBySideEffects != merged.affectedBySideEffects
+ || lastTry.isShadowable != merged.isShadowable) {
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)) {
// if a != b, we have already re-tracked it.
- QQmlJSRegisterContent cloned = (a == b) ? m_pool->clone(merged) : merged;
- Q_ASSERT(cloned.isValid());
- m_state.annotations[currentInstructionOffset()].typeConversions[index].content = cloned;
- m_state.registers[index].content = cloned;
+ const VirtualRegister cloned = {
+ (a == b) ? m_pool->clone(merged.content) : merged.content,
+ merged.canMove,
+ merged.affectedBySideEffects,
+ merged.isShadowable,
+ };
+ Q_ASSERT(cloned.content.isValid());
+ m_state.annotations[currentInstructionOffset()].typeConversions[index] = cloned;
+ m_state.registers[index] = cloned;
}
}
@@ -3019,8 +3037,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()) {
addError(u"When reached from offset %1, %2 is undefined"_s
.arg(stateToMerge.originatingOffset)
.arg(registerName(registerIndex)));
@@ -3029,7 +3047,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);
}
diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h
index 4413a295b9..3da4ac73e7 100644
--- a/src/qmlcompiler/qqmljstypepropagator_p.h
+++ b/src/qmlcompiler/qqmljstypepropagator_p.h
@@ -234,7 +234,7 @@ private:
void setAccumulator(QQmlJSRegisterContent content);
void setRegister(int index, QQmlJSRegisterContent content);
- void mergeRegister(int index, QQmlJSRegisterContent a, QQmlJSRegisterContent b);
+ void mergeRegister(int index, const VirtualRegister &a, const VirtualRegister &b);
void addReadRegister(int index);
void addReadRegister(int index, QQmlJSRegisterContent convertTo);