1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4CODEGEN_P_H
4#define QV4CODEGEN_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qqmljsastvisitor_p.h>
18#include <private/qqmljsengine_p.h>
19#include <private/qqmljsast_p.h>
20#include <private/qqmljsdiagnosticmessage_p.h>
21#include <private/qv4compiler_p.h>
22#include <private/qv4compilercontext_p.h>
23#include <private/qv4util_p.h>
24#include <private/qv4bytecodegenerator_p.h>
25#include <private/qv4calldata_p.h>
26
27#include <QtCore/qsharedpointer.h>
28
29QT_BEGIN_NAMESPACE
30
31namespace QV4 {
32
33namespace Moth {
34struct Instruction;
35}
36
37namespace CompiledData {
38struct CompilationUnit;
39}
40
41namespace Compiler {
42
43struct ControlFlow;
44struct ControlFlowCatch;
45struct ControlFlowFinally;
46
47class Q_QML_COMPILER_PRIVATE_EXPORT CodegenWarningInterface
48{
49public:
50 virtual void reportVarUsedBeforeDeclaration(const QString &name, const QString &fileName,
51 QQmlJS::SourceLocation declarationLocation,
52 QQmlJS::SourceLocation accessLocation);
53 virtual ~CodegenWarningInterface() = default;
54};
55
56inline CodegenWarningInterface *defaultCodegenWarningInterface()
57{
58 static CodegenWarningInterface iface;
59 return &iface;
60}
61
62class Q_QML_COMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
63{
64protected:
65 using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
66 using Instruction = QV4::Moth::Instruction;
67public:
68 Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict,
69 CodegenWarningInterface *iface = defaultCodegenWarningInterface(),
70 bool storeSourceLocations = false);
71
72 void generateFromProgram(const QString &fileName,
73 const QString &finalUrl,
74 const QString &sourceCode,
75 QQmlJS::AST::Program *ast,
76 Module *module,
77 ContextType contextType = ContextType::Global);
78
79 void generateFromModule(const QString &fileName,
80 const QString &finalUrl,
81 const QString &sourceCode,
82 QQmlJS::AST::ESModule *ast,
83 Module *module);
84
85public:
86 class VolatileMemoryLocationScanner;
87 class VolatileMemoryLocations {
88 friend VolatileMemoryLocationScanner;
89 bool allVolatile = false;
90 QList<QStringView> specificLocations;
91 public:
92 bool isVolatile(QStringView name) {
93 if (allVolatile)
94 return true;
95 return specificLocations.contains(t: name);
96 }
97
98 void add(QStringView name) { if (!allVolatile) specificLocations.append(t: name); }
99 void setAllVolatile() { allVolatile = true; }
100 };
101 class RValue {
102 Codegen *codegen;
103 enum Type {
104 Invalid,
105 Accumulator,
106 StackSlot,
107 Const
108 } type;
109 union {
110 Moth::StackSlot theStackSlot;
111 QV4::ReturnedValue constant;
112 };
113
114 public:
115 static RValue fromStackSlot(Codegen *codegen, Moth::StackSlot stackSlot) {
116 RValue r;
117 r.codegen = codegen;
118 r.type = StackSlot;
119 r.theStackSlot = stackSlot;
120 return r;
121 }
122 static RValue fromAccumulator(Codegen *codegen) {
123 RValue r;
124 r.codegen = codegen;
125 r.type = Accumulator;
126 return r;
127 }
128 static RValue fromConst(Codegen *codegen, QV4::ReturnedValue value) {
129 RValue r;
130 r.codegen = codegen;
131 r.type = Const;
132 r.constant = value;
133 return r;
134 }
135
136 bool operator==(const RValue &other) const;
137
138 bool isValid() const { return type != Invalid; }
139 bool isAccumulator() const { return type == Accumulator; }
140 bool isStackSlot() const { return type == StackSlot; }
141 bool isConst() const { return type == Const; }
142
143 Moth::StackSlot stackSlot() const {
144 Q_ASSERT(isStackSlot());
145 return theStackSlot;
146 }
147
148 QV4::ReturnedValue constantValue() const {
149 Q_ASSERT(isConst());
150 return constant;
151 }
152
153 Q_REQUIRED_RESULT RValue storeOnStack() const;
154 void loadInAccumulator() const;
155 };
156 struct Reference {
157 enum Type {
158 Invalid,
159 Accumulator,
160 Super,
161 SuperProperty,
162 StackSlot,
163 ScopedLocal,
164 Name,
165 Member,
166 Subscript,
167 Import,
168 LastLValue = Import,
169 Const
170 } type = Invalid;
171
172 bool isLValue() const { return !isReadonly && type > Accumulator; }
173
174 Reference(Codegen *cg, Type t = Invalid) : Reference()
175 {
176 type = t;
177 codegen = cg;
178 }
179
180 Reference(const QString &name = QString()) :
181 constant(0),
182 name(name),
183 isArgOrEval(false),
184 isReadonly(false),
185 isReferenceToConst(false),
186 requiresTDZCheck(false),
187 subscriptRequiresTDZCheck(false),
188 stackSlotIsLocalOrArgument(false),
189 isVolatile(false),
190 global(false),
191 qmlGlobal(false),
192 throwsReferenceError(false),
193 subscriptLoadedForCall(false)
194 {}
195
196 Reference(const Reference &) = default;
197 Reference(Reference &&) = default;
198 Reference &operator =(const Reference &) = default;
199 Reference &operator =(Reference &&) = default;
200
201 bool operator==(const Reference &other) const;
202 bool operator!=(const Reference &other) const
203 { return !(*this == other); }
204
205 bool isValid() const { return type != Invalid; }
206 bool loadTriggersSideEffect() const {
207 switch (type) {
208 case Name:
209 case Member:
210 case Subscript:
211 case SuperProperty:
212 return true;
213 default:
214 return requiresTDZCheck;
215 }
216 }
217 bool isConstant() const { return type == Const; }
218 bool isAccumulator() const { return type == Accumulator; }
219 bool isSuper() const { return type == Super; }
220 bool isSuperProperty() const { return type == SuperProperty; }
221 bool isStackSlot() const { return type == StackSlot; }
222 bool isRegister() const {
223 return isStackSlot();
224 }
225
226 static Reference fromAccumulator(Codegen *cg) {
227 return Reference(cg, Accumulator);
228 }
229 static Reference fromSuper(Codegen *cg) {
230 return Reference(cg, Super);
231 }
232 static Reference fromStackSlot(Codegen *cg, int tempIndex = -1, bool isLocal = false) {
233 Reference r(cg, StackSlot);
234 if (tempIndex == -1)
235 tempIndex = cg->bytecodeGenerator->newRegister();
236 r.theStackSlot = Moth::StackSlot::createRegister(index: tempIndex);
237 r.stackSlotIsLocalOrArgument = isLocal;
238 return r;
239 }
240 static Reference fromScopedLocal(Codegen *cg, int index, int scope) {
241 Reference r(cg, ScopedLocal);
242 r.index = index;
243 r.scope = scope;
244 return r;
245 }
246 static Reference fromImport(Codegen *cg, int index) {
247 Reference r(cg, Import);
248 r.index = index;
249 return r;
250 }
251 static Reference fromName(Codegen *cg, const QString &name) {
252 Reference r(cg, Name);
253 r.name = name;
254 return r;
255 }
256 static Reference
257 fromMember(const Reference &baseRef, const QString &name,
258 QQmlJS::SourceLocation sourceLocation = QQmlJS::SourceLocation(),
259 Moth::BytecodeGenerator::Label jumpLabel = Moth::BytecodeGenerator::Label(),
260 Moth::BytecodeGenerator::Label targetLabel = Moth::BytecodeGenerator::Label())
261 {
262 Q_ASSERT(baseRef.isValid());
263 Reference r(baseRef.codegen, Member);
264 r.propertyBase = baseRef.asRValue();
265 r.propertyNameIndex = r.codegen->registerString(name);
266 r.requiresTDZCheck = baseRef.requiresTDZCheck;
267 r.sourceLocation = sourceLocation;
268 r.optionalChainJumpLabel.reset(t: new Moth::BytecodeGenerator::Label(jumpLabel));
269 r.optionalChainTargetLabel.reset(t: new Moth::BytecodeGenerator::Label(targetLabel));
270 return r;
271 }
272 static Reference fromSuperProperty(const Reference &property) {
273 Q_ASSERT(property.isStackSlot());
274 Reference r(property.codegen, SuperProperty);
275 r.property = property.stackSlot();
276 r.subscriptRequiresTDZCheck = property.requiresTDZCheck;
277 return r;
278 }
279 static Reference fromSubscript(const Reference &baseRef, const Reference &subscript, Moth::BytecodeGenerator::Label targetLabel = Moth::BytecodeGenerator::Label()) {
280 Q_ASSERT(baseRef.isStackSlot());
281 Reference r(baseRef.codegen, Subscript);
282 r.elementBase = baseRef.stackSlot();
283 r.elementSubscript = subscript.asRValue();
284 r.requiresTDZCheck = baseRef.requiresTDZCheck;
285 r.subscriptRequiresTDZCheck = subscript.requiresTDZCheck;
286 r.optionalChainTargetLabel.reset(t: new Moth::BytecodeGenerator::Label(targetLabel));
287 return r;
288 }
289 static Reference fromConst(Codegen *cg, QV4::ReturnedValue constant) {
290 Reference r(cg, Const);
291 r.constant = constant;
292 r.isReadonly = true;
293 return r;
294 }
295 static Reference fromThis(Codegen *cg) {
296 Reference r = fromStackSlot(cg, tempIndex: CallData::This);
297 r.isReadonly = true;
298 // ### Optimize this. Functions that are not derived constructors or arrow functions can't have an
299 // empty this object
300 r.requiresTDZCheck = true;
301 return r;
302 }
303
304 RValue asRValue() const;
305 Reference asLValue() const;
306
307 Q_REQUIRED_RESULT static Reference storeConstOnStack(Codegen *cg, QV4::ReturnedValue constant)
308 { return Reference::fromConst(cg, constant).storeOnStack(); }
309
310 static void storeConstOnStack(Codegen *cg, QV4::ReturnedValue constant, int stackSlot)
311 { Reference::fromConst(cg, constant).storeOnStack(tempIndex: stackSlot); }
312
313 Q_REQUIRED_RESULT Reference storeOnStack() const;
314 void storeOnStack(int tempIndex) const;
315 Q_REQUIRED_RESULT Reference storeRetainAccumulator() const;
316 Reference storeConsumeAccumulator() const;
317
318 Q_REQUIRED_RESULT Reference baseObject() const;
319
320 bool storeWipesAccumulator() const;
321 void loadInAccumulator() const;
322
323 int nameAsIndex() const {
324 Q_ASSERT(type == Name);
325 return codegen->registerString(name);
326 }
327
328 Moth::StackSlot stackSlot() const {
329 if (Q_UNLIKELY(!isStackSlot()))
330 Q_UNREACHABLE();
331 return theStackSlot;
332 }
333
334 void tdzCheck() const
335 {
336 if (isAccumulator())
337 tdzCheck(requiresCheck: requiresTDZCheck, throwsReferenceError);
338 else if (isStackSlot())
339 tdzCheckStackSlot(slot: stackSlot(), requiresCheck: requiresTDZCheck, throwsReferenceError);
340 }
341
342 union {
343 Moth::StackSlot theStackSlot;
344 QV4::ReturnedValue constant;
345 struct { // Scoped arguments/Local
346 int index;
347 int scope;
348 };
349 struct {
350 RValue propertyBase;
351 int propertyNameIndex;
352 };
353 struct {
354 Moth::StackSlot elementBase;
355 union {
356 RValue elementSubscript;
357 Moth::StackSlot element;
358 };
359 };
360 Moth::StackSlot property; // super property
361 };
362 QString name;
363 Codegen *codegen = nullptr;
364
365 quint32 isArgOrEval:1;
366 quint32 isReadonly:1;
367 quint32 isReferenceToConst:1;
368 quint32 requiresTDZCheck:1;
369 quint32 subscriptRequiresTDZCheck:1;
370 quint32 stackSlotIsLocalOrArgument:1;
371 quint32 isVolatile:1;
372 quint32 global:1;
373 quint32 qmlGlobal:1;
374 quint32 throwsReferenceError:1;
375 quint32 subscriptLoadedForCall:1;
376 QQmlJS::SourceLocation sourceLocation = QQmlJS::SourceLocation();
377 QSharedPointer<Moth::BytecodeGenerator::Label> optionalChainJumpLabel;
378 QSharedPointer<Moth::BytecodeGenerator::Label> optionalChainTargetLabel;
379
380 private:
381 void storeAccumulator() const;
382 Reference doStoreOnStack(int tempIndex) const;
383 void tdzCheck(bool requiresCheck, bool throwsReferenceError) const;
384 void tdzCheckStackSlot(
385 Moth::StackSlot slot, bool requiresCheck, bool throwsReferenceError) const;
386 };
387
388 struct RegisterScope {
389 RegisterScope(Codegen *cg)
390 : generator(cg->bytecodeGenerator),
391 regCountForScope(generator->currentReg) {}
392 ~RegisterScope() {
393 generator->currentReg = regCountForScope;
394 }
395 BytecodeGenerator *generator;
396 int regCountForScope;
397 };
398
399 struct ObjectPropertyValue {
400 ObjectPropertyValue() {}
401
402 Reference rvalue;
403 int getter = -1; // index in _module->functions or -1 if not set
404 int setter = -1;
405 uint keyAsIndex = UINT_MAX;
406
407 bool hasGetter() const { return getter >= 0; }
408 bool hasSetter() const { return setter >= 0; }
409 };
410protected:
411
412 enum Format { ex, cx, nx };
413 class Result {
414 Reference _result;
415
416 const BytecodeGenerator::Label *_iftrue = nullptr;
417 const BytecodeGenerator::Label *_iffalse = nullptr;
418 Format _format = ex;
419 Format _requested;
420 bool _trueBlockFollowsCondition = false;
421
422 public:
423 explicit Result(const QString &name)
424 : _result(name)
425 , _requested(ex)
426 {}
427
428 explicit Result(const Reference &lrvalue)
429 : _result(lrvalue)
430 , _requested(ex)
431 {}
432
433 explicit Result(Format requested = ex)
434 : _requested(requested) {}
435
436 explicit Result(const BytecodeGenerator::Label *iftrue,
437 const BytecodeGenerator::Label *iffalse,
438 bool trueBlockFollowsCondition)
439 : _iftrue(iftrue)
440 , _iffalse(iffalse)
441 , _requested(cx)
442 , _trueBlockFollowsCondition(trueBlockFollowsCondition)
443 {
444 Q_ASSERT(iftrue);
445 Q_ASSERT(iffalse);
446 }
447
448 const BytecodeGenerator::Label *iftrue() const {
449 Q_ASSERT(_requested == cx);
450 return _iftrue;
451 }
452
453 const BytecodeGenerator::Label *iffalse() const {
454 Q_ASSERT(_requested == cx);
455 return _iffalse;
456 }
457
458 Format format() const {
459 return _format;
460 }
461
462 bool accept(Format f)
463 {
464 if (_requested == f) {
465 _format = f;
466 return true;
467 }
468 return false;
469 }
470
471 bool trueBlockFollowsCondition() const {
472 return _trueBlockFollowsCondition;
473 }
474
475 const Reference &result() const {
476 return _result;
477 }
478
479 void setResult(const Reference &result) {
480 _result = result;
481 }
482
483 void setResult(Reference &&result) {
484 _result = std::move(result);
485 }
486
487 void clearResultName() {
488 _result.name.clear();
489 }
490 };
491
492 void enterContext(QQmlJS::AST::Node *node);
493 int leaveContext();
494public:
495 Context *enterBlock(QQmlJS::AST::Node *node);
496 int leaveBlock() { return leaveContext(); }
497protected:
498 void leaveLoop();
499
500 enum UnaryOperation {
501 UPlus,
502 UMinus,
503 PreIncrement,
504 PreDecrement,
505 PostIncrement,
506 PostDecrement,
507 Not,
508 Compl
509 };
510
511 Reference unop(UnaryOperation op, const Reference &expr);
512
513 void addCJump();
514
515public:
516 int registerString(const QString &name) {
517 return jsUnitGenerator->registerString(str: name);
518 }
519 int registerConstant(QV4::ReturnedValue v)
520 {
521 return jsUnitGenerator->registerConstant(v);
522 }
523 int registerGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
524 {
525 return jsUnitGenerator->registerGetterLookup(nameIndex, mode);
526 }
527 int registerSetterLookup(int nameIndex)
528 {
529 return jsUnitGenerator->registerSetterLookup(nameIndex);
530 }
531 int registerGlobalGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
532 {
533 return jsUnitGenerator->registerGlobalGetterLookup(nameIndex, mode);
534 }
535 int registerQmlContextPropertyGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
536 {
537 return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex, mode);
538 }
539
540 // Returns index in _module->functions
541 virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast,
542 QQmlJS::AST::FormalParameterList *formals,
543 QQmlJS::AST::StatementList *body);
544
545protected:
546 void statement(QQmlJS::AST::Statement *ast);
547 void statement(QQmlJS::AST::ExpressionNode *ast);
548 void condition(QQmlJS::AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
549 const BytecodeGenerator::Label *iffalse,
550 bool trueBlockFollowsCondition);
551
552 inline Reference expression(QQmlJS::AST::ExpressionNode *ast, const QString &name = QString())
553 {
554 if (!ast || hasError())
555 return Reference();
556
557 pushExpr(name);
558 ast->accept(visitor: this);
559 return popResult();
560 }
561
562 inline void accept(QQmlJS::AST::Node *node)
563 {
564 if (!hasError() && node)
565 node->accept(visitor: this);
566 }
567
568 void program(QQmlJS::AST::Program *ast);
569 void statementList(QQmlJS::AST::StatementList *ast);
570 void variableDeclaration(QQmlJS::AST::PatternElement *ast);
571 void variableDeclarationList(QQmlJS::AST::VariableDeclarationList *ast);
572
573 Reference targetForPatternElement(QQmlJS::AST::PatternElement *p);
574 void initializeAndDestructureBindingElement(QQmlJS::AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
575 void destructurePropertyList(const Reference &object, QQmlJS::AST::PatternPropertyList *bindingList, bool isDefinition = false);
576 void destructureElementList(const Reference &array, QQmlJS::AST::PatternElementList *bindingList, bool isDefinition = false);
577 void destructurePattern(QQmlJS::AST::Pattern *p, const Reference &rhs);
578
579 Reference referenceForPropertyName(const Codegen::Reference &object, QQmlJS::AST::PropertyName *name);
580
581 void emitReturn(const Reference &expr);
582
583 // nodes
584 bool visit(QQmlJS::AST::ArgumentList *ast) override;
585 bool visit(QQmlJS::AST::CaseBlock *ast) override;
586 bool visit(QQmlJS::AST::CaseClause *ast) override;
587 bool visit(QQmlJS::AST::CaseClauses *ast) override;
588 bool visit(QQmlJS::AST::Catch *ast) override;
589 bool visit(QQmlJS::AST::DefaultClause *ast) override;
590 bool visit(QQmlJS::AST::Elision *ast) override;
591 bool visit(QQmlJS::AST::Finally *ast) override;
592 bool visit(QQmlJS::AST::FormalParameterList *ast) override;
593 bool visit(QQmlJS::AST::Program *ast) override;
594 bool visit(QQmlJS::AST::StatementList *ast) override;
595 bool visit(QQmlJS::AST::UiArrayMemberList *ast) override;
596 bool visit(QQmlJS::AST::UiImport *ast) override;
597 bool visit(QQmlJS::AST::UiHeaderItemList *ast) override;
598 bool visit(QQmlJS::AST::UiPragmaValueList *ast) override;
599 bool visit(QQmlJS::AST::UiPragma *ast) override;
600 bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
601 bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
602 bool visit(QQmlJS::AST::UiParameterList *ast) override;
603 bool visit(QQmlJS::AST::UiProgram *ast) override;
604 bool visit(QQmlJS::AST::UiQualifiedId *ast) override;
605 bool visit(QQmlJS::AST::VariableDeclarationList *ast) override;
606
607 bool visit(QQmlJS::AST::PatternElement *ast) override;
608 bool visit(QQmlJS::AST::PatternElementList *ast) override;
609 bool visit(QQmlJS::AST::PatternProperty *ast) override;
610 bool visit(QQmlJS::AST::PatternPropertyList *ast) override;
611
612 bool visit(QQmlJS::AST::ExportDeclaration *ast) override;
613
614 bool visit(QQmlJS::AST::TypeAnnotation *ast) override;
615
616 // expressions
617 bool visit(QQmlJS::AST::Expression *ast) override;
618 bool visit(QQmlJS::AST::ArrayPattern *ast) override;
619 bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
620 bool visit(QQmlJS::AST::BinaryExpression *ast) override;
621 bool visit(QQmlJS::AST::CallExpression *ast) override;
622 void endVisit(QQmlJS::AST::CallExpression *ast) override;
623 bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
624 bool visit(QQmlJS::AST::DeleteExpression *ast) override;
625 void endVisit(QQmlJS::AST::DeleteExpression *ast) override;
626 bool visit(QQmlJS::AST::FalseLiteral *ast) override;
627 bool visit(QQmlJS::AST::SuperLiteral *ast) override;
628 bool visit(QQmlJS::AST::FieldMemberExpression *ast) override;
629 void endVisit(QQmlJS::AST::FieldMemberExpression *ast) override;
630 bool visit(QQmlJS::AST::TaggedTemplate *ast) override;
631 bool visit(QQmlJS::AST::FunctionExpression *ast) override;
632 bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
633 bool visit(QQmlJS::AST::NestedExpression *ast) override;
634 bool visit(QQmlJS::AST::NewExpression *ast) override;
635 bool visit(QQmlJS::AST::NewMemberExpression *ast) override;
636 bool visit(QQmlJS::AST::NotExpression *ast) override;
637 bool visit(QQmlJS::AST::NullExpression *ast) override;
638 bool visit(QQmlJS::AST::NumericLiteral *ast) override;
639 bool visit(QQmlJS::AST::ObjectPattern *ast) override;
640 bool visit(QQmlJS::AST::PostDecrementExpression *ast) override;
641 bool visit(QQmlJS::AST::PostIncrementExpression *ast) override;
642 bool visit(QQmlJS::AST::PreDecrementExpression *ast) override;
643 bool visit(QQmlJS::AST::PreIncrementExpression *ast) override;
644 bool visit(QQmlJS::AST::RegExpLiteral *ast) override;
645 bool visit(QQmlJS::AST::StringLiteral *ast) override;
646 bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
647 bool visit(QQmlJS::AST::ThisExpression *ast) override;
648 bool visit(QQmlJS::AST::TildeExpression *ast) override;
649 bool visit(QQmlJS::AST::TrueLiteral *ast) override;
650 bool visit(QQmlJS::AST::TypeOfExpression *ast) override;
651 bool visit(QQmlJS::AST::UnaryMinusExpression *ast) override;
652 bool visit(QQmlJS::AST::UnaryPlusExpression *ast) override;
653 bool visit(QQmlJS::AST::VoidExpression *ast) override;
654 bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
655 bool visit(QQmlJS::AST::YieldExpression *ast) override;
656 bool visit(QQmlJS::AST::ClassExpression *ast) override;
657 bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
658
659 // statements
660 bool visit(QQmlJS::AST::Block *ast) override;
661 bool visit(QQmlJS::AST::BreakStatement *ast) override;
662 bool visit(QQmlJS::AST::ContinueStatement *ast) override;
663 bool visit(QQmlJS::AST::DebuggerStatement *ast) override;
664 bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
665 bool visit(QQmlJS::AST::EmptyStatement *ast) override;
666 bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
667 bool visit(QQmlJS::AST::ForEachStatement *ast) override;
668 bool visit(QQmlJS::AST::ForStatement *ast) override;
669 bool visit(QQmlJS::AST::IfStatement *ast) override;
670 bool visit(QQmlJS::AST::LabelledStatement *ast) override;
671 bool visit(QQmlJS::AST::ReturnStatement *ast) override;
672 bool visit(QQmlJS::AST::SwitchStatement *ast) override;
673 bool visit(QQmlJS::AST::ThrowStatement *ast) override;
674 bool visit(QQmlJS::AST::TryStatement *ast) override;
675 bool visit(QQmlJS::AST::VariableStatement *ast) override;
676 bool visit(QQmlJS::AST::WhileStatement *ast) override;
677 bool visit(QQmlJS::AST::WithStatement *ast) override;
678
679 // ui object members
680 bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
681 bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
682 bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
683 bool visit(QQmlJS::AST::UiPublicMember *ast) override;
684 bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
685 bool visit(QQmlJS::AST::UiSourceElement *ast) override;
686
687 bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
688 const QQmlJS::SourceLocation &loc);
689 virtual void throwSyntaxError(const QQmlJS::SourceLocation &loc, const QString &detail);
690 virtual void throwReferenceError(const QQmlJS::SourceLocation &loc, const QString &detail);
691 void throwRecursionDepthError() override
692 {
693 throwSyntaxError(loc: QQmlJS::SourceLocation(),
694 QStringLiteral("Maximum statement or expression depth exceeded"));
695 }
696
697public:
698 enum ErrorType {
699 NoError,
700 SyntaxError,
701 ReferenceError
702 };
703
704 ErrorType errorType() const { return _errorType; }
705 bool hasError() const { return _errorType != NoError; }
706 QQmlJS::DiagnosticMessage error() const;
707 QUrl url() const;
708
709 Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
710 Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
711 struct Arguments { int argc; int argv; bool hasSpread; };
712 Arguments pushArgs(QQmlJS::AST::ArgumentList *args);
713 void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject, bool optional = false);
714
715 Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
716 bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
717 void createTemplateObject(QQmlJS::AST::TemplateLiteral *t);
718
719 void setUseFastLookups(bool b) { useFastLookups = b; }
720
721 void handleTryCatch(QQmlJS::AST::TryStatement *ast);
722 void handleTryFinally(QQmlJS::AST::TryStatement *ast);
723
724
725 Reference referenceForName(
726 const QString &name, bool lhs,
727 const QQmlJS::SourceLocation &accessLocation = QQmlJS::SourceLocation());
728
729 QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true);
730 static QV4::CompiledData::CompilationUnit compileModule(
731 bool debugMode, const QString &url, const QString &sourceCode,
732 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
733
734 Context *currentContext() const { return _context; }
735 BytecodeGenerator *generator() const { return bytecodeGenerator; }
736
737 void loadClosure(int index);
738
739 Module *module() const { return _module; }
740
741 BytecodeGenerator::Label returnLabel() {
742 if (!_returnLabel)
743 _returnLabel = new BytecodeGenerator::Label(bytecodeGenerator->newLabel());
744 return *_returnLabel;
745 }
746
747 void setGlobalNames(const QSet<QString>& globalNames) {
748 m_globalNames = globalNames;
749 }
750
751 static const char *s_globalNames[];
752
753protected:
754 friend class ScanFunctions;
755 friend struct ControlFlow;
756 friend struct ControlFlowCatch;
757 friend struct ControlFlowFinally;
758
759 inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
760 inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
761 inline Reference exprResult() const { return m_expressions.back().result(); }
762 inline void clearExprResultName() { m_expressions.back().clearResultName(); }
763
764 inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
765
766 inline const Result &currentExpr() const { return m_expressions.back(); }
767
768 inline void pushExpr(Result &&expr) { m_expressions.push_back(x: std::move(expr)); }
769 inline void pushExpr(const Result &expr) { m_expressions.push_back(x: expr); }
770 inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(args: name); }
771
772 inline Result popExpr()
773 {
774 const Result result = m_expressions.back();
775 m_expressions.pop_back();
776 return result;
777 }
778
779 inline Reference popResult() {
780 const Reference result = m_expressions.back().result();
781 m_expressions.pop_back();
782 return result;
783 }
784
785 std::vector<Result> m_expressions;
786 VolatileMemoryLocations _volatileMemoryLocations;
787 Module *_module;
788 int _returnAddress;
789 Context *_context;
790 Context *_functionContext = nullptr;
791 QQmlJS::AST::LabelledStatement *_labelledStatement;
792 QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
793 BytecodeGenerator *bytecodeGenerator = nullptr;
794 Moth::BytecodeGenerator::Label *_returnLabel = nullptr;
795 bool _strictMode;
796 bool useFastLookups = true;
797 bool requiresReturnValue = false;
798 bool insideSwitch = false;
799 bool inFormalParameterList = false;
800 bool functionEndsWithReturn = false;
801 bool _tailCallsAreAllowed = true;
802 bool storeSourceLocations = false;
803 QSet<QString> m_globalNames;
804 QSet<QQmlJS::AST::Node*> m_seenOptionalChainNodes;
805 QHash<QQmlJS::AST::Node*, Moth::BytecodeGenerator::Label> m_optionalChainLabels;
806
807 ControlFlow *controlFlow = nullptr;
808
809 bool _fileNameIsUrl;
810 ErrorType _errorType = NoError;
811 QQmlJS::DiagnosticMessage _error;
812 CodegenWarningInterface *_interface;
813
814 class TailCallBlocker
815 {
816 public:
817 TailCallBlocker(Codegen *cg, bool onoff = false)
818 : _cg(cg)
819 , _saved(_cg->_tailCallsAreAllowed)
820 , _onoff(onoff)
821 { _cg->_tailCallsAreAllowed = onoff; }
822
823 ~TailCallBlocker()
824 { _cg->_tailCallsAreAllowed = _saved; }
825
826 void unblock() const
827 { _cg->_tailCallsAreAllowed = _saved; }
828
829 void reblock() const
830 { _cg->_tailCallsAreAllowed = _onoff; }
831
832 private:
833 Codegen *_cg;
834 bool _saved;
835 bool _onoff;
836 };
837
838private:
839 VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
840 void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
841 void throwError(ErrorType errorType, const QQmlJS::SourceLocation &loc,
842 const QString &detail);
843 std::optional<Moth::BytecodeGenerator::Label> traverseOptionalChain(QQmlJS::AST::Node *node);
844 Reference loadSubscriptForCall(const Reference &base);
845 void generateThrowException(const QString &type, const QString &text = QString());
846};
847
848}
849
850}
851
852QT_END_NAMESPACE
853
854#endif // QV4CODEGEN_P_H
855

source code of qtdeclarative/src/qml/compiler/qv4codegen_p.h