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

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