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