29class QQmlJSCompilePass :
public QV4::Moth::ByteCodeHandler
31 Q_DISABLE_COPY_MOVE(QQmlJSCompilePass)
33 enum RegisterShortcuts {
37 CurrentFunction = QV4::CallData::Function,
39 Context = QV4::CallData::Context,
40 Accumulator = QV4::CallData::Accumulator,
41 This = QV4::CallData::This,
42 NewTarget = QV4::CallData::NewTarget,
43 Argc = QV4::CallData::Argc,
44 FirstArgument = QV4::CallData::OffsetCount
47 using SourceLocationTable = QV4::Compiler::Context::SourceLocationTable;
49 struct VirtualRegister
51 QQmlJSRegisterContent content;
53 bool affectedBySideEffects =
false;
54 bool isShadowable =
false;
57 friend bool operator==(
const VirtualRegister &a,
const VirtualRegister &b)
59 return a.content == b.content && a.canMove == b.canMove
60 && a.affectedBySideEffects == b.affectedBySideEffects;
65 using VirtualRegisters = QFlatMap<
int, VirtualRegister>;
69 QList<
int> jumpOrigins;
70 QList<
int> readRegisters;
72 bool jumpIsUnconditional =
false;
73 bool isReturnBlock =
false;
74 bool isThrowBlock =
false;
77 using BasicBlocks = QFlatMap<
int, BasicBlock>;
79 struct InstructionAnnotation
82 VirtualRegisters readRegisters;
85 VirtualRegisters typeConversions;
87 QQmlJSRegisterContent changedRegister;
88 int changedRegisterIndex = InvalidRegister;
89 bool hasInternalSideEffects =
false;
90 bool hasExternalSideEffects =
false;
91 bool isRename =
false;
92 bool isShadowable =
false;
95 using InstructionAnnotations = QFlatMap<
int, InstructionAnnotation>;
96 struct BlocksAndAnnotations
98 BasicBlocks basicBlocks;
99 InstructionAnnotations annotations;
104 QQmlJSScopesById addressableScopes;
105 QList<QQmlJSRegisterContent> argumentTypes;
106 QList<QQmlJSRegisterContent> registerTypes;
107 QQmlJSRegisterContent returnType;
108 QQmlJSRegisterContent qmlScope;
110 const SourceLocationTable *sourceLocations =
nullptr;
111 bool isSignalHandler =
false;
112 bool isQPropertyBinding =
false;
113 bool isProperty =
false;
114 bool isFullyTyped =
false;
117 struct ObjectOrArrayDefinition
121 ArrayConstruct1ArgId = -2,
124 int instructionOffset = -1;
125 int internalClassId = ArrayClassId;
132 VirtualRegisters registers;
133 VirtualRegisters lookups;
136
137
138
139
140
141
142
143
144
145
146 QQmlJSRegisterContent accumulatorIn()
const
148 auto it = registers.find(Accumulator);
149 Q_ASSERT(it != registers.end());
150 return it.value().content;
154
155
156
157 QQmlJSRegisterContent accumulatorOut()
const
159 Q_ASSERT(m_changedRegisterIndex == Accumulator);
160 return m_changedRegister;
163 void setRegister(
int registerIndex, QQmlJSRegisterContent content)
165 const int lookupIndex = content.resultLookupIndex();
166 if (lookupIndex != QQmlJSRegisterContent::InvalidLookupIndex)
167 lookups[lookupIndex] = { content,
false,
false };
169 m_changedRegister = std::move(content);
170 m_changedRegisterIndex = registerIndex;
173 void clearChangedRegister()
175 m_changedRegisterIndex = InvalidRegister;
176 m_changedRegister = QQmlJSRegisterContent();
179 int changedRegisterIndex()
const {
return m_changedRegisterIndex; }
180 QQmlJSRegisterContent changedRegister()
const {
return m_changedRegister; }
182 void addReadRegister(
int registerIndex, QQmlJSRegisterContent reg)
184 VirtualRegister &target = m_readRegisters[registerIndex];
185 target.content = reg;
187 const auto source = registers.find(registerIndex);
188 if (source == registers.end()) {
189 target.canMove =
false;
190 target.affectedBySideEffects =
false;
192 target.canMove = source->second.canMove;
193 target.affectedBySideEffects = source->second.affectedBySideEffects;
197 void addReadAccumulator(QQmlJSRegisterContent reg)
199 addReadRegister(Accumulator, reg);
202 VirtualRegisters takeReadRegisters()
const {
return std::move(m_readRegisters); }
203 void setReadRegisters(VirtualRegisters readReagisters)
205 m_readRegisters = std::move(readReagisters);
208 QQmlJSRegisterContent readRegister(
int registerIndex)
const
210 Q_ASSERT(m_readRegisters.contains(registerIndex));
211 return m_readRegisters[registerIndex].content;
214 bool canMoveReadRegister(
int registerIndex)
const
216 auto it = m_readRegisters.find(registerIndex);
217 return it != m_readRegisters.end() && it->second.canMove;
220 bool isRegisterAffectedBySideEffects(
int registerIndex)
const
222 auto it = m_readRegisters.find(registerIndex);
223 return it != m_readRegisters.end() && it->second.affectedBySideEffects;
227
228
229
230
231
232
233 QQmlJSRegisterContent readAccumulator()
const
235 return readRegister(Accumulator);
238 bool readsRegister(
int registerIndex)
const
240 return m_readRegisters.contains(registerIndex);
243 bool hasInternalSideEffects()
const {
return m_hasInternalSideEffects; }
244 bool hasExternalSideEffects()
const {
return m_hasExternalSideEffects; }
246 void resetSideEffects()
248 m_hasInternalSideEffects =
false;
249 m_hasExternalSideEffects =
false;
252 void applyExternalSideEffects(
bool hasExternalSideEffects)
254 if (!hasExternalSideEffects)
257 for (
auto it = registers.begin(), end = registers.end(); it != end; ++it)
258 it.value().affectedBySideEffects =
true;
260 for (
auto it = lookups.begin(), end = lookups.end(); it != end; ++it)
261 it.value().affectedBySideEffects =
true;
264 void setHasInternalSideEffects() { m_hasInternalSideEffects =
true; }
265 void setHasExternalSideEffects()
267 m_hasExternalSideEffects =
true;
268 m_hasInternalSideEffects =
true;
269 applyExternalSideEffects(
true);
273 bool isRename()
const {
return m_isRename; }
274 void setIsRename(
bool isRename) { m_isRename = isRename; }
276 bool isShadowable()
const {
return m_isShadowable; }
277 void setIsShadowable(
bool isShadowable) { m_isShadowable = isShadowable; }
279 int renameSourceRegisterIndex()
const
281 Q_ASSERT(m_isRename);
282 Q_ASSERT(m_readRegisters.size() == 1);
283 return m_readRegisters.begin().key();
286 void applyAnnotation(
const InstructionAnnotation &annotation)
288 m_readRegisters = annotation.readRegisters;
290 m_hasInternalSideEffects = annotation.hasInternalSideEffects;
291 m_hasExternalSideEffects = annotation.hasExternalSideEffects;
292 m_isRename = annotation.isRename;
293 m_isShadowable = annotation.isShadowable;
295 for (
auto it = annotation.typeConversions.constBegin(),
296 end = annotation.typeConversions.constEnd(); it != end; ++it) {
297 Q_ASSERT(it.key() != InvalidRegister);
298 registers[it.key()] = it.value();
301 if (annotation.changedRegisterIndex != InvalidRegister)
302 setRegister(annotation.changedRegisterIndex, annotation.changedRegister);
306 VirtualRegisters m_readRegisters;
307 QQmlJSRegisterContent m_changedRegister;
308 int m_changedRegisterIndex = InvalidRegister;
311 bool m_hasInternalSideEffects =
false;
315 bool m_hasExternalSideEffects =
false;
317 bool m_isRename =
false;
318 bool m_isShadowable =
false;
321 QQmlJSCompilePass(
const QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
322 const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
323 const BasicBlocks &basicBlocks = {},
324 const InstructionAnnotations &annotations = {})
325 : m_jsUnitGenerator(jsUnitGenerator)
326 , m_typeResolver(typeResolver)
327 , m_pool(typeResolver->registerContentPool())
329 , m_basicBlocks(basicBlocks)
330 , m_annotations(annotations)
334 const QV4::Compiler::JSUnitGenerator *m_jsUnitGenerator =
nullptr;
335 const QQmlJSTypeResolver *m_typeResolver =
nullptr;
336 QQmlJSRegisterContentPool *m_pool =
nullptr;
337 QQmlJSLogger *m_logger =
nullptr;
339 const Function *m_function =
nullptr;
340 BasicBlocks m_basicBlocks;
341 InstructionAnnotations m_annotations;
343 int firstRegisterIndex()
const
345 return FirstArgument + m_function->argumentTypes.size();
348 bool isArgument(
int registerIndex)
const
350 return registerIndex >= FirstArgument && registerIndex < firstRegisterIndex();
353 QQmlJSRegisterContent argumentType(
int registerIndex)
const
355 Q_ASSERT(isArgument(registerIndex));
356 return m_function->argumentTypes[registerIndex - FirstArgument];
360
361
362
363
364
365
366
367
368 bool isQmlScopeObject(QQmlJSRegisterContent content)
370 switch (content.variant()) {
371 case QQmlJSRegisterContent::ScopeObject:
372 return content.contains(m_function->qmlScope.containedType());
373 case QQmlJSRegisterContent::ModulePrefix:
374 return content.scope().contains(m_function->qmlScope.containedType());
382 State initialState(
const Function *function)
385 for (
int i = 0, end = function->argumentTypes.size(); i < end; ++i) {
386 state.registers[FirstArgument + i].content = function->argumentTypes.at(i);
387 Q_ASSERT(state.registers[FirstArgument + i].content.isValid());
389 for (
int i = 0, end = function->registerTypes.size(); i != end; ++i)
390 state.registers[firstRegisterIndex() + i].content = function->registerTypes[i];
394 State nextStateFromAnnotations(
395 const State &oldState,
const InstructionAnnotations &annotations)
399 const auto instruction = annotations.find(currentInstructionOffset());
400 newState.registers = oldState.registers;
401 newState.lookups = oldState.lookups;
404 if (oldState.changedRegisterIndex() != InvalidRegister) {
405 newState.registers[oldState.changedRegisterIndex()].affectedBySideEffects =
false;
406 newState.registers[oldState.changedRegisterIndex()].content
407 = oldState.changedRegister();
408 newState.registers[oldState.changedRegisterIndex()].isShadowable
409 = oldState.isShadowable();
414 newState.applyExternalSideEffects(oldState.hasExternalSideEffects());
416 if (instruction != annotations.constEnd())
417 newState.applyAnnotation(instruction->second);
422 QList<SourceLocationTable::Entry>::const_iterator sourceLocationEntry(
423 int instructionOffset)
const
425 Q_ASSERT(m_function);
426 Q_ASSERT(m_function->sourceLocations);
427 const auto &entries = m_function->sourceLocations->entries;
428 const auto entry = std::lower_bound(
429 entries.begin(), entries.end(), instructionOffset,
430 [](
auto entry, uint offset) {
return entry.offset < offset; });
431 Q_ASSERT(entry != entries.end());
435 QQmlJS::SourceLocation sourceLocation(
int instructionOffset)
const
437 return sourceLocationEntry(instructionOffset)->location;
440 QQmlJS::SourceLocation nonEmptySourceLocation(
int instructionOffset)
const
442 auto entry = sourceLocationEntry(instructionOffset);
445 const auto begin = m_function->sourceLocations->entries.begin();
446 while (entry->location.length == 0 && entry != begin)
449 return entry->location;
452 QQmlJS::SourceLocation currentSourceLocation()
const
454 return sourceLocation(currentInstructionOffset());
457 QQmlJS::SourceLocation currentNonEmptySourceLocation()
const
459 return nonEmptySourceLocation(currentInstructionOffset());
462 QQmlJS::SourceLocation currentFunctionSourceLocation()
const
464 Q_ASSERT(m_function->sourceLocations);
465 const auto &entries = m_function->sourceLocations->entries;
467 Q_ASSERT(!entries.isEmpty());
468 return combine(entries.constFirst().location, entries.constLast().location);
471 void addError(
const QString &message,
int instructionOffset)
473 m_logger->logCompileError(message, sourceLocation(instructionOffset));
476 void addSkip(
const QString &message,
int instructionOffset)
478 m_logger->logCompileSkip(message, sourceLocation(instructionOffset));
481 void addError(
const QString &message)
483 addError(message, currentInstructionOffset());
486 void addSkip(
const QString &message)
488 addSkip(message, currentInstructionOffset());
491 static bool instructionManipulatesContext(QV4::Moth::Instr::Type type)
493 using Type = QV4::Moth::Instr::Type;
495 case Type::PopContext:
496 case Type::PopScriptContext:
497 case Type::CreateCallContext:
498 case Type::CreateCallContext_Wide:
499 case Type::PushCatchContext:
500 case Type::PushCatchContext_Wide:
501 case Type::PushWithContext:
502 case Type::PushWithContext_Wide:
503 case Type::PushBlockContext:
504 case Type::PushBlockContext_Wide:
505 case Type::CloneBlockContext:
506 case Type::CloneBlockContext_Wide:
507 case Type::PushScriptContext:
508 case Type::PushScriptContext_Wide:
517 void generate_Add(
int) override {}
518 void generate_As(
int) override {}
519 void generate_BitAnd(
int) override {}
520 void generate_BitAndConst(
int) override {}
521 void generate_BitOr(
int) override {}
522 void generate_BitOrConst(
int) override {}
523 void generate_BitXor(
int) override {}
524 void generate_BitXorConst(
int) override {}
525 void generate_CallGlobalLookup(
int,
int,
int) override {}
526 void generate_CallName(
int,
int,
int) override {}
527 void generate_CallPossiblyDirectEval(
int,
int) override {}
528 void generate_CallProperty(
int,
int,
int,
int) override {}
529 void generate_CallPropertyLookup(
int,
int,
int,
int) override {}
530 void generate_CallQmlContextPropertyLookup(
int,
int,
int) override {}
531 void generate_CallValue(
int,
int,
int) override {}
532 void generate_CallWithReceiver(
int,
int,
int,
int) override {}
533 void generate_CallWithSpread(
int,
int,
int,
int) override {}
534 void generate_CheckException() override {}
535 void generate_CloneBlockContext() override {}
536 void generate_CmpEq(
int) override {}
537 void generate_CmpEqInt(
int) override {}
538 void generate_CmpEqNull() override {}
539 void generate_CmpGe(
int) override {}
540 void generate_CmpGt(
int) override {}
541 void generate_CmpIn(
int) override {}
542 void generate_CmpInstanceOf(
int) override {}
543 void generate_CmpLe(
int) override {}
544 void generate_CmpLt(
int) override {}
545 void generate_CmpNe(
int) override {}
546 void generate_CmpNeInt(
int) override {}
547 void generate_CmpNeNull() override {}
548 void generate_CmpStrictEqual(
int) override {}
549 void generate_CmpStrictNotEqual(
int) override {}
550 void generate_Construct(
int,
int,
int) override {}
551 void generate_ConstructWithSpread(
int,
int,
int) override {}
552 void generate_ConvertThisToObject() override {}
553 void generate_CreateCallContext() override {}
554 void generate_CreateClass(
int,
int,
int) override {}
555 void generate_CreateMappedArgumentsObject() override {}
556 void generate_CreateRestParameter(
int) override {}
557 void generate_CreateUnmappedArgumentsObject() override {}
558 void generate_DeadTemporalZoneCheck(
int) override {}
559 void generate_Debug() override {}
560 void generate_DeclareVar(
int,
int) override {}
561 void generate_Decrement() override {}
562 void generate_DefineArray(
int,
int) override {}
563 void generate_DefineObjectLiteral(
int,
int,
int) override {}
564 void generate_DeleteName(
int) override {}
565 void generate_DeleteProperty(
int,
int) override {}
566 void generate_DestructureRestElement() override {}
567 void generate_Div(
int) override {}
568 void generate_Exp(
int) override {}
569 void generate_GetException() override {}
570 void generate_GetIterator(
int) override {}
571 void generate_GetLookup(
int) override {}
572 void generate_GetOptionalLookup(
int,
int) override {}
573 void generate_GetTemplateObject(
int) override {}
574 void generate_Increment() override {}
575 void generate_InitializeBlockDeadTemporalZone(
int,
int) override {}
576 void generate_IteratorClose() override {}
577 void generate_IteratorNext(
int,
int) override {}
578 void generate_IteratorNextForYieldStar(
int,
int,
int) override {}
579 void generate_Jump(
int) override {}
580 void generate_JumpFalse(
int) override {}
581 void generate_JumpNoException(
int) override {}
582 void generate_JumpNotUndefined(
int) override {}
583 void generate_JumpTrue(
int) override {}
584 void generate_LoadClosure(
int) override {}
585 void generate_LoadConst(
int) override {}
586 void generate_LoadElement(
int) override {}
587 void generate_LoadFalse() override {}
588 void generate_LoadGlobalLookup(
int) override {}
589 void generate_LoadImport(
int) override {}
590 void generate_LoadInt(
int) override {}
591 void generate_LoadLocal(
int) override {}
592 void generate_LoadName(
int) override {}
593 void generate_LoadNull() override {}
594 void generate_LoadOptionalProperty(
int,
int) override {}
595 void generate_LoadProperty(
int) override {}
596 void generate_LoadQmlContextPropertyLookup(
int) override {}
597 void generate_LoadReg(
int) override {}
598 void generate_LoadRuntimeString(
int) override {}
599 void generate_LoadScopedLocal(
int,
int) override {}
600 void generate_LoadSuperConstructor() override {}
601 void generate_LoadSuperProperty(
int) override {}
602 void generate_LoadTrue() override {}
603 void generate_LoadUndefined() override {}
604 void generate_LoadZero() override {}
605 void generate_Mod(
int) override {}
606 void generate_MoveConst(
int,
int) override {}
607 void generate_MoveReg(
int,
int) override {}
608 void generate_MoveRegExp(
int,
int) override {}
609 void generate_Mul(
int) override {}
610 void generate_PopContext() override {}
611 void generate_PopScriptContext() override {}
612 void generate_PushBlockContext(
int) override {}
613 void generate_PushCatchContext(
int,
int) override {}
614 void generate_PushScriptContext(
int) override {}
615 void generate_PushWithContext() override {}
616 void generate_Resume(
int) override {}
617 void generate_Ret() override {}
618 void generate_SetException() override {}
619 void generate_SetLookup(
int,
int) override {}
620 void generate_SetUnwindHandler(
int) override {}
621 void generate_Shl(
int) override {}
622 void generate_ShlConst(
int) override {}
623 void generate_Shr(
int) override {}
624 void generate_ShrConst(
int) override {}
625 void generate_StoreElement(
int,
int) override {}
626 void generate_StoreLocal(
int) override {}
627 void generate_StoreNameSloppy(
int) override {}
628 void generate_StoreNameStrict(
int) override {}
629 void generate_StoreProperty(
int,
int) override {}
630 void generate_StoreReg(
int) override {}
631 void generate_StoreScopedLocal(
int,
int) override {}
632 void generate_StoreSuperProperty(
int) override {}
633 void generate_Sub(
int) override {}
634 void generate_TailCall(
int,
int,
int,
int) override {}
635 void generate_ThrowException() override {}
636 void generate_ThrowOnNullOrUndefined() override {}
637 void generate_ToObject() override {}
638 void generate_TypeofName(
int) override {}
639 void generate_TypeofValue() override {}
640 void generate_UCompl() override {}
641 void generate_UMinus() override {}
642 void generate_UNot() override {}
643 void generate_UPlus() override {}
644 void generate_UShr(
int) override {}
645 void generate_UShrConst(
int) override {}
646 void generate_UnwindDispatch() override {}
647 void generate_UnwindToLabel(
int,
int) override {}
648 void generate_Yield() override {}
649 void generate_YieldStar() override {}