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

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