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 ¤tExpr() 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