aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-01-18 10:04:17 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-01-21 07:14:35 +0000
commit2c460deadc08da2a43da7fc2b96452477c74fafd (patch)
treecb49b1a64d16014aedf0844b925aa4f3f0831d49
parent4b4af2a02cd85b2e4acf5940b256ff84817edb56 (diff)
QmlCompiler: Use a hash set for the list of conversions
There can be a lot of them and we don't want quadratic behavior. It might be possible to further improve on this using e.g. sorted lists and algorithms provided by the STL. However, such an implementation would be more complicated and would require weighing several trade-offs. Pick-to: 6.5 Fixes: QTBUG-121139 Change-Id: I717b49bd4af97abcaae9ae78d1e1b31d5d462952 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Marc Mutz <marc.mutz@qt.io> (cherry picked from commit af212e5e4edb73978298cd030b15deb8d8c28183) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 2108e416eabc68c0136faa5041d80866ce1da716)
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp38
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks_p.h4
2 files changed, 24 insertions, 18 deletions
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index 58b3da12c8..1db12e9528 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -157,16 +157,6 @@ static bool containsAny(const ContainerA &container, const ContainerB &elements)
return false;
}
-template<typename ContainerA, typename ContainerB>
-static bool containsAll(const ContainerA &container, const ContainerB &elements)
-{
- for (const auto &element : elements) {
- if (!container.contains(element))
- return false;
- }
- return true;
-}
-
template<class Key, class T, class Compare = std::less<Key>,
class KeyContainer = QList<Key>, class MappedContainer = QList<T>>
class NewFlatMap
@@ -193,7 +183,7 @@ private:
struct PendingBlock
{
- QList<int> conversions;
+ QQmlJSBasicBlocks::Conversions conversions;
int start = -1;
bool registerActive = false;
};
@@ -283,7 +273,7 @@ void QQmlJSBasicBlocks::populateReaderLocations()
auto nextBlock = m_basicBlocks.find(block.start);
auto currentBlock = nextBlock++;
bool registerActive = block.registerActive;
- QList<int> conversions = block.conversions;
+ Conversions conversions = block.conversions;
const auto blockEnd = (nextBlock == m_basicBlocks.end())
? m_annotations.end()
@@ -295,7 +285,7 @@ void QQmlJSBasicBlocks::populateReaderLocations()
for (; blockInstr != blockEnd; ++blockInstr) {
if (registerActive
&& blockInstr->second.typeConversions.contains(writtenRegister)) {
- conversions.append(blockInstr.key());
+ conversions.insert(blockInstr.key());
}
for (auto readIt = blockInstr->second.readRegisters.constBegin(),
@@ -322,12 +312,26 @@ void QQmlJSBasicBlocks::populateReaderLocations()
// If we find that an already processed block has the register activated by this jump,
// we need to re-evaluate it. We also need to propagate any newly found conversions.
const auto processed = processedBlocks.find(blockStart);
- if (processed == processedBlocks.end())
+ if (processed == processedBlocks.end()) {
blocks.append({conversions, blockStart, registerActive});
- else if (registerActive && !processed->registerActive)
+ } else if (registerActive && !processed->registerActive) {
blocks.append({conversions, blockStart, registerActive});
- else if (!containsAll(processed->conversions, conversions))
- blocks.append({processed->conversions + conversions, blockStart, registerActive});
+ } else {
+
+ // TODO: Use unite() once it is fixed.
+ // We don't use unite() here since it would be more expensive. unite()
+ // effectively loops on only insert() and insert() does a number of checks
+ // each time. We trade those checks for calculating the hash twice on each
+ // iteration. Calculating the hash is very cheap for integers.
+ Conversions merged = processed->conversions;
+ for (const int conversion : std::as_const(conversions)) {
+ if (!merged.contains(conversion))
+ merged.insert(conversion);
+ }
+
+ if (merged.size() > processed->conversions.size())
+ blocks.append({std::move(merged), blockStart, registerActive});
+ }
};
if (!currentBlock->second.jumpIsUnconditional && nextBlock != m_basicBlocks.end())
diff --git a/src/qmlcompiler/qqmljsbasicblocks_p.h b/src/qmlcompiler/qqmljsbasicblocks_p.h
index 7a3d394544..1053733ebc 100644
--- a/src/qmlcompiler/qqmljsbasicblocks_p.h
+++ b/src/qmlcompiler/qqmljsbasicblocks_p.h
@@ -23,6 +23,8 @@ QT_BEGIN_NAMESPACE
class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSBasicBlocks : public QQmlJSCompilePass
{
public:
+ using Conversions = QSet<int>;
+
struct BasicBlock {
QList<int> jumpOrigins;
QList<int> readRegisters;
@@ -48,7 +50,7 @@ private:
{
QList<QQmlJSScope::ConstPtr> trackedTypes;
QHash<int, QQmlJSScope::ConstPtr> typeReaders;
- QHash<int, QList<int>> registerReadersAndConversions;
+ QHash<int, Conversions> registerReadersAndConversions;
int trackedRegister;
};