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 const VirtualRegister &source = registers[registerIndex];
185 VirtualRegister &target = m_readRegisters[registerIndex];
186 target.content = reg;
187 target.canMove = source.canMove;
188 target.affectedBySideEffects = source.affectedBySideEffects;
191 void addReadAccumulator(QQmlJSRegisterContent reg)
193 addReadRegister(Accumulator, reg);
196 VirtualRegisters takeReadRegisters()
const {
return std::move(m_readRegisters); }
197 void setReadRegisters(VirtualRegisters readReagisters)
199 m_readRegisters = std::move(readReagisters);
202 QQmlJSRegisterContent readRegister(
int registerIndex)
const
204 Q_ASSERT(m_readRegisters.contains(registerIndex));
205 return m_readRegisters[registerIndex].content;
208 bool canMoveReadRegister(
int registerIndex)
const
210 auto it = m_readRegisters.find(registerIndex);
211 return it != m_readRegisters.end() && it->second.canMove;
214 bool isRegisterAffectedBySideEffects(
int registerIndex)
const
216 auto it = m_readRegisters.find(registerIndex);
217 return it != m_readRegisters.end() && it->second.affectedBySideEffects;
221
222
223
224
225
226
227 QQmlJSRegisterContent readAccumulator()
const
229 return readRegister(Accumulator);
232 bool readsRegister(
int registerIndex)
const
234 return m_readRegisters.contains(registerIndex);
237 bool hasInternalSideEffects()
const {
return m_hasInternalSideEffects; }
238 bool hasExternalSideEffects()
const {
return m_hasExternalSideEffects; }
240 void resetSideEffects()
242 m_hasInternalSideEffects =
false;
243 m_hasExternalSideEffects =
false;
246 void applyExternalSideEffects(
bool hasExternalSideEffects)
248 if (!hasExternalSideEffects)
251 for (
auto it = registers.begin(), end = registers.end(); it != end; ++it)
252 it.value().affectedBySideEffects =
true;
254 for (
auto it = lookups.begin(), end = lookups.end(); it != end; ++it)
255 it.value().affectedBySideEffects =
true;
258 void setHasInternalSideEffects() { m_hasInternalSideEffects =
true; }
259 void setHasExternalSideEffects()
261 m_hasExternalSideEffects =
true;
262 m_hasInternalSideEffects =
true;
263 applyExternalSideEffects(
true);
267 bool isRename()
const {
return m_isRename; }
268 void setIsRename(
bool isRename) { m_isRename = isRename; }
270 bool isShadowable()
const {
return m_isShadowable; }
271 void setIsShadowable(
bool isShadowable) { m_isShadowable = isShadowable; }
273 int renameSourceRegisterIndex()
const
275 Q_ASSERT(m_isRename);
276 Q_ASSERT(m_readRegisters.size() == 1);
277 return m_readRegisters.begin().key();
280 void applyAnnotation(
const InstructionAnnotation &annotation)
282 m_readRegisters = annotation.readRegisters;
284 m_hasInternalSideEffects = annotation.hasInternalSideEffects;
285 m_hasExternalSideEffects = annotation.hasExternalSideEffects;
286 m_isRename = annotation.isRename;
287 m_isShadowable = annotation.isShadowable;
289 for (
auto it = annotation.typeConversions.constBegin(),
290 end = annotation.typeConversions.constEnd(); it != end; ++it) {
291 Q_ASSERT(it.key() != InvalidRegister);
292 registers[it.key()] = it.value();
295 if (annotation.changedRegisterIndex != InvalidRegister)
296 setRegister(annotation.changedRegisterIndex, annotation.changedRegister);
300 VirtualRegisters m_readRegisters;
301 QQmlJSRegisterContent m_changedRegister;
302 int m_changedRegisterIndex = InvalidRegister;
305 bool m_hasInternalSideEffects =
false;
309 bool m_hasExternalSideEffects =
false;
311 bool m_isRename =
false;
312 bool m_isShadowable =
false;
315 QQmlJSCompilePass(
const QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
316 const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
317 const BasicBlocks &basicBlocks = {},
318 const InstructionAnnotations &annotations = {})
319 : m_jsUnitGenerator(jsUnitGenerator)
320 , m_typeResolver(typeResolver)
321 , m_pool(typeResolver->registerContentPool())
323 , m_basicBlocks(basicBlocks)
324 , m_annotations(annotations)
328 const QV4::Compiler::JSUnitGenerator *m_jsUnitGenerator =
nullptr;
329 const QQmlJSTypeResolver *m_typeResolver =
nullptr;
330 QQmlJSRegisterContentPool *m_pool =
nullptr;
331 QQmlJSLogger *m_logger =
nullptr;
333 const Function *m_function =
nullptr;
334 BasicBlocks m_basicBlocks;
335 InstructionAnnotations m_annotations;
337 int firstRegisterIndex()
const
339 return FirstArgument + m_function->argumentTypes.size();
342 bool isArgument(
int registerIndex)
const
344 return registerIndex >= FirstArgument && registerIndex < firstRegisterIndex();
347 QQmlJSRegisterContent argumentType(
int registerIndex)
const
349 Q_ASSERT(isArgument(registerIndex));
350 return m_function->argumentTypes[registerIndex - FirstArgument];
354
355
356
357
358
359
360
361
362 bool isQmlScopeObject(QQmlJSRegisterContent content)
364 switch (content.variant()) {
365 case QQmlJSRegisterContent::ScopeObject:
366 return content.contains(m_function->qmlScope.containedType());
367 case QQmlJSRegisterContent::ModulePrefix:
368 return content.scope().contains(m_function->qmlScope.containedType());
376 State initialState(
const Function *function)
379 for (
int i = 0, end = function->argumentTypes.size(); i < end; ++i) {
380 state.registers[FirstArgument + i].content = function->argumentTypes.at(i);
381 Q_ASSERT(state.registers[FirstArgument + i].content.isValid());
383 for (
int i = 0, end = function->registerTypes.size(); i != end; ++i)
384 state.registers[firstRegisterIndex() + i].content = function->registerTypes[i];
388 State nextStateFromAnnotations(
389 const State &oldState,
const InstructionAnnotations &annotations)
393 const auto instruction = annotations.find(currentInstructionOffset());
394 newState.registers = oldState.registers;
395 newState.lookups = oldState.lookups;
398 if (oldState.changedRegisterIndex() != InvalidRegister) {
399 newState.registers[oldState.changedRegisterIndex()].affectedBySideEffects =
false;
400 newState.registers[oldState.changedRegisterIndex()].content
401 = oldState.changedRegister();
402 newState.registers[oldState.changedRegisterIndex()].isShadowable
403 = oldState.isShadowable();
408 newState.applyExternalSideEffects(oldState.hasExternalSideEffects());
410 if (instruction != annotations.constEnd())
411 newState.applyAnnotation(instruction->second);
416 QList<SourceLocationTable::Entry>::const_iterator sourceLocationEntry(
417 int instructionOffset)
const
419 Q_ASSERT(m_function);
420 Q_ASSERT(m_function->sourceLocations);
421 const auto &entries = m_function->sourceLocations->entries;
422 const auto entry = std::lower_bound(
423 entries.begin(), entries.end(), instructionOffset,
424 [](
auto entry, uint offset) {
return entry.offset < offset; });
425 Q_ASSERT(entry != entries.end());
429 QQmlJS::SourceLocation sourceLocation(
int instructionOffset)
const
431 return sourceLocationEntry(instructionOffset)->location;
434 QQmlJS::SourceLocation nonEmptySourceLocation(
int instructionOffset)
const
436 auto entry = sourceLocationEntry(instructionOffset);
439 const auto begin = m_function->sourceLocations->entries.begin();
440 while (entry->location.length == 0 && entry != begin)
443 return entry->location;
446 QQmlJS::SourceLocation currentSourceLocation()
const
448 return sourceLocation(currentInstructionOffset());
451 QQmlJS::SourceLocation currentNonEmptySourceLocation()
const
453 return nonEmptySourceLocation(currentInstructionOffset());
456 QQmlJS::SourceLocation currentFunctionSourceLocation()
const
458 Q_ASSERT(m_function->sourceLocations);
459 const auto &entries = m_function->sourceLocations->entries;
461 Q_ASSERT(!entries.isEmpty());
462 return combine(entries.constFirst().location, entries.constLast().location);
465 void addError(
const QString &message,
int instructionOffset)
467 m_logger->logCompileError(message, sourceLocation(instructionOffset));
470 void addSkip(
const QString &message,
int instructionOffset)
472 m_logger->logCompileSkip(message, sourceLocation(instructionOffset));
475 void addError(
const QString &message)
477 addError(message, currentInstructionOffset());
480 void addSkip(
const QString &message)
482 addSkip(message, currentInstructionOffset());
485 static bool instructionManipulatesContext(QV4::Moth::Instr::Type type)
487 using Type = QV4::Moth::Instr::Type;
489 case Type::PopContext:
490 case Type::PopScriptContext:
491 case Type::CreateCallContext:
492 case Type::CreateCallContext_Wide:
493 case Type::PushCatchContext:
494 case Type::PushCatchContext_Wide:
495 case Type::PushWithContext:
496 case Type::PushWithContext_Wide:
497 case Type::PushBlockContext:
498 case Type::PushBlockContext_Wide:
499 case Type::CloneBlockContext:
500 case Type::CloneBlockContext_Wide:
501 case Type::PushScriptContext:
502 case Type::PushScriptContext_Wide:
511 void generate_Add(
int) override {}
512 void generate_As(
int) override {}
513 void generate_BitAnd(
int) override {}
514 void generate_BitAndConst(
int) override {}
515 void generate_BitOr(
int) override {}
516 void generate_BitOrConst(
int) override {}
517 void generate_BitXor(
int) override {}
518 void generate_BitXorConst(
int) override {}
519 void generate_CallGlobalLookup(
int,
int,
int) override {}
520 void generate_CallName(
int,
int,
int) override {}
521 void generate_CallPossiblyDirectEval(
int,
int) override {}
522 void generate_CallProperty(
int,
int,
int,
int) override {}
523 void generate_CallPropertyLookup(
int,
int,
int,
int) override {}
524 void generate_CallQmlContextPropertyLookup(
int,
int,
int) override {}
525 void generate_CallValue(
int,
int,
int) override {}
526 void generate_CallWithReceiver(
int,
int,
int,
int) override {}
527 void generate_CallWithSpread(
int,
int,
int,
int) override {}
528 void generate_CheckException() override {}
529 void generate_CloneBlockContext() override {}
530 void generate_CmpEq(
int) override {}
531 void generate_CmpEqInt(
int) override {}
532 void generate_CmpEqNull() override {}
533 void generate_CmpGe(
int) override {}
534 void generate_CmpGt(
int) override {}
535 void generate_CmpIn(
int) override {}
536 void generate_CmpInstanceOf(
int) override {}
537 void generate_CmpLe(
int) override {}
538 void generate_CmpLt(
int) override {}
539 void generate_CmpNe(
int) override {}
540 void generate_CmpNeInt(
int) override {}
541 void generate_CmpNeNull() override {}
542 void generate_CmpStrictEqual(
int) override {}
543 void generate_CmpStrictNotEqual(
int) override {}
544 void generate_Construct(
int,
int,
int) override {}
545 void generate_ConstructWithSpread(
int,
int,
int) override {}
546 void generate_ConvertThisToObject() override {}
547 void generate_CreateCallContext() override {}
548 void generate_CreateClass(
int,
int,
int) override {}
549 void generate_CreateMappedArgumentsObject() override {}
550 void generate_CreateRestParameter(
int) override {}
551 void generate_CreateUnmappedArgumentsObject() override {}
552 void generate_DeadTemporalZoneCheck(
int) override {}
553 void generate_Debug() override {}
554 void generate_DeclareVar(
int,
int) override {}
555 void generate_Decrement() override {}
556 void generate_DefineArray(
int,
int) override {}
557 void generate_DefineObjectLiteral(
int,
int,
int) override {}
558 void generate_DeleteName(
int) override {}
559 void generate_DeleteProperty(
int,
int) override {}
560 void generate_DestructureRestElement() override {}
561 void generate_Div(
int) override {}
562 void generate_Exp(
int) override {}
563 void generate_GetException() override {}
564 void generate_GetIterator(
int) override {}
565 void generate_GetLookup(
int) override {}
566 void generate_GetOptionalLookup(
int,
int) override {}
567 void generate_GetTemplateObject(
int) override {}
568 void generate_Increment() override {}
569 void generate_InitializeBlockDeadTemporalZone(
int,
int) override {}
570 void generate_IteratorClose() override {}
571 void generate_IteratorNext(
int,
int) override {}
572 void generate_IteratorNextForYieldStar(
int,
int,
int) override {}
573 void generate_Jump(
int) override {}
574 void generate_JumpFalse(
int) override {}
575 void generate_JumpNoException(
int) override {}
576 void generate_JumpNotUndefined(
int) override {}
577 void generate_JumpTrue(
int) override {}
578 void generate_LoadClosure(
int) override {}
579 void generate_LoadConst(
int) override {}
580 void generate_LoadElement(
int) override {}
581 void generate_LoadFalse() override {}
582 void generate_LoadGlobalLookup(
int) override {}
583 void generate_LoadImport(
int) override {}
584 void generate_LoadInt(
int) override {}
585 void generate_LoadLocal(
int) override {}
586 void generate_LoadName(
int) override {}
587 void generate_LoadNull() override {}
588 void generate_LoadOptionalProperty(
int,
int) override {}
589 void generate_LoadProperty(
int) override {}
590 void generate_LoadQmlContextPropertyLookup(
int) override {}
591 void generate_LoadReg(
int) override {}
592 void generate_LoadRuntimeString(
int) override {}
593 void generate_LoadScopedLocal(
int,
int) override {}
594 void generate_LoadSuperConstructor() override {}
595 void generate_LoadSuperProperty(
int) override {}
596 void generate_LoadTrue() override {}
597 void generate_LoadUndefined() override {}
598 void generate_LoadZero() override {}
599 void generate_Mod(
int) override {}
600 void generate_MoveConst(
int,
int) override {}
601 void generate_MoveReg(
int,
int) override {}
602 void generate_MoveRegExp(
int,
int) override {}
603 void generate_Mul(
int) override {}
604 void generate_PopContext() override {}
605 void generate_PopScriptContext() override {}
606 void generate_PushBlockContext(
int) override {}
607 void generate_PushCatchContext(
int,
int) override {}
608 void generate_PushScriptContext(
int) override {}
609 void generate_PushWithContext() override {}
610 void generate_Resume(
int) override {}
611 void generate_Ret() override {}
612 void generate_SetException() override {}
613 void generate_SetLookup(
int,
int) override {}
614 void generate_SetUnwindHandler(
int) override {}
615 void generate_Shl(
int) override {}
616 void generate_ShlConst(
int) override {}
617 void generate_Shr(
int) override {}
618 void generate_ShrConst(
int) override {}
619 void generate_StoreElement(
int,
int) override {}
620 void generate_StoreLocal(
int) override {}
621 void generate_StoreNameSloppy(
int) override {}
622 void generate_StoreNameStrict(
int) override {}
623 void generate_StoreProperty(
int,
int) override {}
624 void generate_StoreReg(
int) override {}
625 void generate_StoreScopedLocal(
int,
int) override {}
626 void generate_StoreSuperProperty(
int) override {}
627 void generate_Sub(
int) override {}
628 void generate_TailCall(
int,
int,
int,
int) override {}
629 void generate_ThrowException() override {}
630 void generate_ThrowOnNullOrUndefined() override {}
631 void generate_ToObject() override {}
632 void generate_TypeofName(
int) override {}
633 void generate_TypeofValue() override {}
634 void generate_UCompl() override {}
635 void generate_UMinus() override {}
636 void generate_UNot() override {}
637 void generate_UPlus() override {}
638 void generate_UShr(
int) override {}
639 void generate_UShrConst(
int) override {}
640 void generate_UnwindDispatch() override {}
641 void generate_UnwindToLabel(
int,
int) override {}
642 void generate_Yield() override {}
643 void generate_YieldStar() override {}