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
63QT_BEGIN_NAMESPACE
64
65namespace QV4 {
66
67namespace Moth {
68struct Instruction;
69}
70
71namespace CompiledData {
72struct CompilationUnit;
73}
74
75namespace Compiler {
76
77struct ControlFlow;
78struct ControlFlowCatch;
79struct ControlFlowFinally;
80
81class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
82{
83protected:
84 using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
85 using Instruction = QV4::Moth::Instruction;
86public:
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
103public:
104 class VolatileMemoryLocationScanner;
105 class VolatileMemoryLocations {
106 friend VolatileMemoryLocationScanner;
107 bool allVolatile = false;
108 QVector<QStringView> specificLocations;
109 public:
110 bool isVolatile(const QStringView &name) {
111 if (allVolatile)
112 return true;
113 return specificLocations.contains(name);
114 }
115
116 void add(const QStringRef &name) { if (!allVolatile) specificLocations.append(name); }
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:
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 }
140 static RValue fromAccumulator(Codegen *codegen) {
141 RValue r;
142 r.codegen = codegen;
143 r.type = Accumulator;
144 return r;
145 }
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
156 bool isValid() const { return type != Invalid; }
157 bool isAccumulator() const { return type == Accumulator; }
158 bool isStackSlot() const { return type == StackSlot; }
159 bool isConst() const { return type == Const; }
160
161 Moth::StackSlot stackSlot() const {
162 Q_ASSERT(isStackSlot());
163 return theStackSlot;
164 }
165
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
190 bool isLValue() const { return !isReadonly && type > Accumulator; }
191
192 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
221 bool isValid() const { return type != Invalid; }
222 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 }
233 bool isConstant() const { return type == Const; }
234 bool isAccumulator() const { return type == Accumulator; }
235 bool isSuper() const { return type == Super; }
236 bool isSuperProperty() const { return type == SuperProperty; }
237 bool isStackSlot() const { return type == StackSlot; }
238 bool isRegister() const {
239 return isStackSlot();
240 }
241
242 static Reference fromAccumulator(Codegen *cg) {
243 return Reference(cg, Accumulator);
244 }
245 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 }
256 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 }
264 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 }
270 static Reference fromImport(Codegen *cg, int index) {
271 Reference r(cg, Import);
272 r.index = index;
273 return r;
274 }
275 static Reference fromName(Codegen *cg, const QString &name) {
276 Reference r(cg, Name);
277 r.name = name;
278 return r;
279 }
280 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 }
287 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 }
294 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 }
303 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 }
309 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
321 Q_REQUIRED_RESULT static Reference storeConstOnStack(Codegen *cg, QV4::ReturnedValue constant)
322 { return Reference::fromConst(cg, constant).storeOnStack(); }
323
324 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
337 int nameAsIndex() const {
338 Q_ASSERT(type == Name);
339 return codegen->registerString(name);
340 }
341
342 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 {
384 RegisterScope(Codegen *cg)
385 : generator(cg->bytecodeGenerator),
386 regCountForScope(generator->currentReg) {}
387 ~RegisterScope() {
388 generator->currentReg = regCountForScope;
389 }
390 BytecodeGenerator *generator;
391 int regCountForScope;
392 };
393
394 struct ObjectPropertyValue {
395 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
402 bool hasGetter() const { return getter >= 0; }
403 bool hasSetter() const { return setter >= 0; }
404 };
405protected:
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:
418 explicit Result(const QString &name)
419 : _result(name)
420 , _requested(ex)
421 {}
422
423 explicit Result(const Reference &lrvalue)
424 : _result(lrvalue)
425 , _requested(ex)
426 {}
427
428 explicit Result(Format requested = ex)
429 : _requested(requested) {}
430
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
443 const BytecodeGenerator::Label *iftrue() const {
444 Q_ASSERT(_requested == cx);
445 return _iftrue;
446 }
447
448 const BytecodeGenerator::Label *iffalse() const {
449 Q_ASSERT(_requested == cx);
450 return _iffalse;
451 }
452
453 Format format() const {
454 return _format;
455 }
456
457 bool accept(Format f)
458 {
459 if (_requested == f) {
460 _format = f;
461 return true;
462 }
463 return false;
464 }
465
466 bool trueBlockFollowsCondition() const {
467 return _trueBlockFollowsCondition;
468 }
469
470 const Reference &result() const {
471 return _result;
472 }
473
474 void setResult(const Reference &result) {
475 _result = result;
476 }
477
478 void setResult(Reference &&result) {
479 _result = std::move(result);
480 }
481
482 void clearResultName() {
483 _result.name.clear();
484 }
485 };
486
487 void enterContext(QQmlJS::AST::Node *node);
488 int leaveContext();
489public:
490 Context *enterBlock(QQmlJS::AST::Node *node);
491 int leaveBlock() { return leaveContext(); }
492protected:
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
510public:
511 int registerString(const QString &name) {
512 return jsUnitGenerator->registerString(name);
513 }
514 int registerConstant(QV4::ReturnedValue v) { return jsUnitGenerator->registerConstant(v); }
515 int registerGetterLookup(int nameIndex) { return jsUnitGenerator->registerGetterLookup(nameIndex); }
516 int registerSetterLookup(int nameIndex) { return jsUnitGenerator->registerSetterLookup(nameIndex); }
517 int registerGlobalGetterLookup(int nameIndex) { return jsUnitGenerator->registerGlobalGetterLookup(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
525protected:
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
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::AST::SourceLocation &loc);
665 virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
666 virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
667 void throwRecursionDepthError() override
668 {
669 throwSyntaxError(QQmlJS::AST::SourceLocation(),
670 QStringLiteral("Maximum statement or expression depth exceeded"));
671 }
672
673public:
674 enum ErrorType {
675 NoError,
676 SyntaxError,
677 ReferenceError
678 };
679
680 ErrorType errorType() const { return _errorType; }
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
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::AST::SourceLocation &accessLocation = QQmlJS::AST::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
710 Context *currentContext() const { return _context; }
711 BytecodeGenerator *generator() const { return bytecodeGenerator; }
712
713 void loadClosure(int index);
714
715 Module *module() const { return _module; }
716
717 BytecodeGenerator::Label returnLabel() {
718 if (!_returnLabel)
719 _returnLabel = new BytecodeGenerator::Label(bytecodeGenerator->newLabel());
720 return *_returnLabel;
721 }
722
723 void setGlobalNames(const QSet<QString>& globalNames) {
724 m_globalNames = globalNames;
725 }
726
727 static const char *s_globalNames[];
728
729protected:
730 friend class ScanFunctions;
731 friend struct ControlFlow;
732 friend struct ControlFlowCatch;
733 friend struct ControlFlowFinally;
734
735 inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
736 inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
737 inline Reference exprResult() const { return m_expressions.back().result(); }
738 inline void clearExprResultName() { m_expressions.back().clearResultName(); }
739
740 inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
741
742 inline const Result &currentExpr() const { return m_expressions.back(); }
743
744 inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(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
748 inline Result popExpr()
749 {
750 const Result result = m_expressions.back();
751 m_expressions.pop_back();
752 return result;
753 }
754
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)
790 : _cg(cg)
791 , _saved(_cg->_tailCallsAreAllowed)
792 , _onoff(onoff)
793 { _cg->_tailCallsAreAllowed = onoff; }
794
795 ~TailCallBlocker()
796 { _cg->_tailCallsAreAllowed = _saved; }
797
798 void unblock() const
799 { _cg->_tailCallsAreAllowed = _saved; }
800
801 void reblock() const
802 { _cg->_tailCallsAreAllowed = _onoff; }
803
804 private:
805 Codegen *_cg;
806 bool _saved;
807 bool _onoff;
808 };
809
810private:
811 VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
812 void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
813 void throwError(ErrorType errorType, const QQmlJS::AST::SourceLocation &loc,
814 const QString &detail);
815};
816
817}
818
819}
820
821QT_END_NAMESPACE
822
823#endif // QV4CODEGEN_P_H
824