18 populateBasicBlocks();
19 populateReaderLocations();
32template<
typename ContainerA,
typename ContainerB>
35 for (
const auto &element :
elements) {
36 if (container.contains(element))
42template<
class Key,
class T,
class Compare = std::less<Key>,
43 class KeyContainer = QList<Key>,
class MappedContainer = QList<T>>
64 typename OriginalFlatMap::key_container_type keys;
65 typename OriginalFlatMap::mapped_container_type
values;
68void QQmlJSOptimizations::populateReaderLocations()
70 using NewInstructionAnnotations = NewFlatMap<int, InstructionAnnotation>;
72 bool erasedReaders =
false;
73 auto eraseDeadStore = [&](
const InstructionAnnotations::iterator &
it) {
75 if (reader != m_readerLocations.
end()
76 && (
reader->typeReaders.isEmpty() ||
reader->registerReadersAndConversions.isEmpty())) {
78 if (
it->second.isRename) {
96 m_readerLocations.
erase(reader);
99 if (!
it->second.hasSideEffects) {
100 if (!
it->second.readRegisters.
isEmpty()) {
101 it->second.readRegisters.
clear();
102 erasedReaders =
true;
111 NewInstructionAnnotations newAnnotations;
113 writeIt != writeEnd; ++writeIt) {
114 const int writtenRegister = writeIt->second.changedRegisterIndex;
116 newAnnotations.appendOrdered(writeIt);
120 RegisterAccess &
access = m_readerLocations[writeIt.key()];
121 access.trackedRegister = writtenRegister;
122 if (writeIt->second.changedRegister.isConversion()) {
126 access.trackedTypes = writeIt->second.changedRegister.conversionOrigins();
128 access.trackedTypes.append(
133 QList<PendingBlock> blocks = { { {}, blockIt->first,
true } };
134 QHash<int, PendingBlock> processedBlocks;
135 bool isFirstBlock =
true;
137 while (!blocks.isEmpty()) {
143 processedBlocks.insert(block.
start, block);
146 auto currentBlock = nextBlock++;
154 auto blockInstr = isFirstBlock
157 for (; blockInstr != blockEnd; ++blockInstr) {
159 && blockInstr->second.typeConversions.contains(writtenRegister)) {
160 conversions.
insert(blockInstr.key());
163 for (
auto readIt = blockInstr->second.readRegisters.constBegin(),
164 end = blockInstr->second.readRegisters.constEnd();
165 readIt !=
end; ++readIt) {
167 readIt->second.content.conversionOrigins(),
access.trackedTypes)) {
168 Q_ASSERT(readIt->second.content.isConversion());
169 Q_ASSERT(readIt->second.content.conversionResult());
170 access.typeReaders[blockInstr.key()]
171 = readIt->second.content.conversionResult();
173 if (registerActive && readIt->first == writtenRegister)
174 access.registerReadersAndConversions[blockInstr.key()] = conversions;
177 if (blockInstr->second.changedRegisterIndex == writtenRegister) {
179 registerActive =
false;
183 auto scheduleBlock = [&](
int blockStart) {
186 const auto processed = processedBlocks.find(blockStart);
187 if (processed == processedBlocks.end()) {
188 blocks.append({conversions, blockStart, registerActive});
189 }
else if (registerActive && !processed->registerActive) {
190 blocks.append({conversions, blockStart, registerActive});
199 for (
const int conversion :
std::as_const(conversions)) {
200 if (!merged.contains(conversion))
201 merged.
insert(conversion);
204 if (merged.size() > processed->conversions.size())
205 blocks.append({std::move(merged), blockStart, registerActive});
209 if (!currentBlock->second.jumpIsUnconditional && nextBlock !=
m_basicBlocks.
end())
210 scheduleBlock(nextBlock->first);
212 const int jumpTarget = currentBlock->second.jumpTarget;
213 if (jumpTarget != -1)
214 scheduleBlock(jumpTarget);
217 isFirstBlock =
false;
220 if (!eraseDeadStore(writeIt))
221 newAnnotations.appendOrdered(writeIt);
225 while (erasedReaders) {
226 erasedReaders =
false;
229 InstructionAnnotation &instruction =
it->second;
231 newAnnotations.appendOrdered(
it);
235 auto readers = m_readerLocations.
find(
it.key());
236 if (readers != m_readerLocations.
end()) {
237 for (
auto typeIt = readers->typeReaders.begin();
238 typeIt != readers->typeReaders.end();) {
242 typeIt = readers->typeReaders.erase(typeIt);
245 for (
auto registerIt = readers->registerReadersAndConversions.begin();
246 registerIt != readers->registerReadersAndConversions.end();) {
250 registerIt = readers->registerReadersAndConversions.erase(registerIt);
254 if (!eraseDeadStore(
it))
255 newAnnotations.appendOrdered(
it);
262bool QQmlJSOptimizations::canMove(
int instructionOffset,
263 const QQmlJSOptimizations::RegisterAccess &
access)
const
265 if (
access.registerReadersAndConversions.size() != 1)
271QList<QQmlJSCompilePass::ObjectOrArrayDefinition>
274 return m_objectAndArrayDefinitions;
285 if (conversions.size() == 1)
290 if (!
types.isEmpty())
298void QQmlJSOptimizations::adjustTypes()
300 using NewVirtualRegisters = NewFlatMap<int, VirtualRegister>;
302 QHash<int, QList<int>> liveConversions;
303 QHash<int, QList<int>> movableReads;
305 const auto handleRegisterReadersAndConversions
307 for (
auto conversions =
it->registerReadersAndConversions.
constBegin(),
310 if (conversions->isEmpty() && canMove(
it.key(),
it.value()))
311 movableReads[conversions.key()].append(
it->trackedRegister);
312 for (
int conversion : *conversions)
313 liveConversions[conversion].
append(
it->trackedRegister);
326 auto adjustArray = [&](
int instructionOffset,
int mode) {
327 auto it = m_readerLocations.
find(instructionOffset);
328 if (
it == m_readerLocations.
end())
331 const InstructionAnnotation &annotation =
m_annotations[instructionOffset];
332 if (annotation.readRegisters.isEmpty())
338 if (
it->trackedTypes[0]->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence)
352 if (
mode != ObjectOrArrayDefinition::ArrayConstruct1ArgId
358 transformRegister(content);
362 handleRegisterReadersAndConversions(
it);
368 const auto adjustObject = [&](
const ObjectOrArrayDefinition &
object) {
369 auto it = m_readerLocations.
find(
object.instructionOffset);
370 if (
it == m_readerLocations.
end())
373 const InstructionAnnotation &annotation =
m_annotations[
object.instructionOffset];
379 Q_ASSERT(!annotation.readRegisters.isEmpty());
393 for (
int i = 0;
i < classSize; ++
i) {
416 transformRegister(content);
425 for (
auto it = m_objectAndArrayDefinitions.
crbegin(),
end = m_objectAndArrayDefinitions.
crend();
427 switch (
it->internalClassId) {
428 case ObjectOrArrayDefinition::ArrayClassId:
429 case ObjectOrArrayDefinition::ArrayConstruct1ArgId:
430 adjustArray(
it->instructionOffset,
it->internalClassId);
439 handleRegisterReadersAndConversions(
it);
443 if (
it->trackedTypes.
size() != 1)
447 const int writeLocation =
it.key();
448 if (writeLocation >= 0 &&
m_annotations[writeLocation].isRename)
456 NewVirtualRegisters newRegisters;
459 transformRegister(
i->second.changedRegister);
461 for (
auto conversion =
i->second.typeConversions.begin(),
462 conversionEnd =
i->second.typeConversions.end(); conversion != conversionEnd;
464 if (!liveConversions[
i.key()].contains(conversion.key()))
468 const auto content = conversion->second.content;
472 for (
const auto &origin : conversionOrigins)
477 transformRegister(content);
478 newRegisters.appendOrdered(conversion);
480 i->second.typeConversions = newRegisters.take();
482 for (
int movable :
std::as_const(movableReads[
i.
key()]))
483 i->second.readRegisters[movable].canMove = true;
487void QQmlJSOptimizations::populateBasicBlocks()
490 blockNext != blockEnd;) {
492 const auto blockIt = blockNext++;
493 BasicBlock &block = blockIt->second;
494 QList<QQmlJSScope::ConstPtr> writtenTypes;
495 QList<int> writtenRegisters;
499 for (
auto instrIt =
m_annotations.
find(blockIt->first); instrIt != instrEnd; ++instrIt) {
500 const InstructionAnnotation &instruction = instrIt->second;
501 for (
auto it = instruction.readRegisters.
begin(),
end = instruction.readRegisters.end();
503 if (!instruction.isRename) {
506 it->second.content.conversionOrigins()) {
507 if (!writtenTypes.contains(origin))
508 block.readTypes.append(origin);
511 if (!writtenRegisters.contains(
it->first))
512 block.readRegisters.append(
it->first);
517 if (!instruction.isRename) {
519 instruction.changedRegister));
521 writtenRegisters.append(instruction.changedRegisterIndex);
void appendOrdered(const typename OriginalFlatMap::iterator &i)
QFlatMap< Key, T, Compare, KeyContainer, MappedContainer > OriginalFlatMap
bool contains(const Key &key) const
iterator find(const Key &key)
std::pair< iterator, bool > insert(const Key &key, const T &value)
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
iterator erase(const_iterator it)
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
const_reverse_iterator crbegin() const noexcept
const_reverse_iterator crend() const noexcept
static BasicBlocks::iterator basicBlockForInstruction(QFlatMap< int, BasicBlock > &container, int instructionOffset)
QList< ObjectOrArrayDefinition > objectAndArrayDefinitions() const
const QV4::Compiler::JSUnitGenerator * m_jsUnitGenerator
const Function * m_function
const QQmlJSTypeResolver * m_typeResolver
QQmlJS::DiagnosticMessage * m_error
InstructionAnnotations m_annotations
BasicBlocks m_basicBlocks
void setError(const QString &message, int instructionOffset)
BlocksAndAnnotations run(const Function *function, QQmlJS::DiagnosticMessage *error)
QQmlJSScope::ConstPtr conversionResult() const
bool isConversion() const
QList< QQmlJSScope::ConstPtr > conversionOrigins() const
QString internalName() const
bool equals(const QQmlJSScope::ConstPtr &a, const QQmlJSScope::ConstPtr &b) const
QQmlJSScope::ConstPtr trackedContainedType(const QQmlJSRegisterContent &container) const
QQmlJSScope::ConstPtr storedType(const QQmlJSScope::ConstPtr &type) const
QQmlJSScope::ConstPtr containedType(const QQmlJSRegisterContent &container) const
bool adjustTrackedType(const QQmlJSScope::ConstPtr &tracked, const QQmlJSScope::ConstPtr &conversion) const
QQmlJSScope::ConstPtr voidType() const
QQmlJSScope::ConstPtr realType() const
QQmlJSScope::ConstPtr varType() const
QQmlJSScope::ConstPtr variantMapType() const
QList< T > values() const
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
iterator insert(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
list append(new Employee("Blackpool", "Stephen"))
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr OrderedUniqueRange_t OrderedUniqueRange
QImageReader reader("image.png")
[1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
GLenum GLsizei GLsizei GLint * values
[15]
GLsizei GLenum GLenum * types
static bool containsAny(const ContainerA &container, const ContainerB &elements)
static QString adjustErrorMessage(const QQmlJSScope::ConstPtr &origin, const QQmlJSScope::ConstPtr &conversion)
QLatin1StringView QLatin1String
static const QTextHtmlElement elements[Html_NumElements]
QQmlJSOptimizations::Conversions conversions
static void deduplicate(Container &container)
QString jsClassMember(int jsClassId, int member) const
int jsClassSize(int jsClassId) const