7#include <private/qqmljsast_p.h>
8#include <private/qqmljsdiagnosticmessage_p.h>
9#include <private/qqmljslexer_p.h>
10#include <private/qqmljsparser_p.h>
11#include <private/qv4bytecodegenerator_p.h>
12#include <private/qv4compilercontext_p.h>
13#include <private/qv4compilercontrolflow_p.h>
14#include <private/qv4compilerscanfunctions_p.h>
15#include <private/qv4object_p.h>
16#include <private/qv4objectiterator_p.h>
17#include <private/qv4staticvalue_p.h>
18#include <private/qv4stringtoarrayindex_p.h>
20#include <QtCore/qcoreapplication.h>
21#include <QtCore/qloggingcategory.h>
22#include <QtCore/qscopeguard.h>
23#include <QtCore/qstack.h>
24#include <QtCore/qstringlist.h>
25#include <QtCore/qurl.h>
35using namespace Qt::StringLiterals;
42using namespace QQmlJS;
43using namespace QQmlJS::AST;
45void CodegenWarningInterface::reportVarUsedBeforeDeclaration(
46 const QString &name,
const QString &fileName, QQmlJS::SourceLocation declarationLocation,
47 QQmlJS::SourceLocation accessLocation)
49 qCWarning(lcQmlUsedBeforeDeclared).nospace().noquote()
50 << fileName <<
":" << accessLocation.startLine <<
":" << accessLocation.startColumn
51 <<
" Variable \"" << name <<
"\" is used before its declaration at "
52 << declarationLocation.startLine <<
":" << declarationLocation.startColumn <<
".";
55void CodegenWarningInterface::reportFunctionUsedBeforeDeclaration(
const QString &,
const QString &,
56 QQmlJS::SourceLocation,
57 QQmlJS::SourceLocation)
63 const Statement *body,
const SourceLocation &fallback)
68 case Statement::Kind_ConditionalExpression:
69 case Statement::Kind_ForEachStatement:
70 case Statement::Kind_ForStatement:
71 case Statement::Kind_IfStatement:
72 case Statement::Kind_WhileStatement:
73 bytecodeGenerator->setLocation(fallback);
76 bytecodeGenerator->setLocation(body->lastSourceLocation());
81void Codegen::generateThrowException(
const QString &type,
const QString &text)
83 RegisterScope scope(
this);
84 Instruction::Construct construct;
90 Instruction::LoadRuntimeString load;
91 load.stringId = registerString(text);
92 bytecodeGenerator->addInstruction(load);
93 construct.argv = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
95 Reference r = referenceForName(type,
false);
97 construct.func = r.stackSlot();
98 bytecodeGenerator->addInstruction(construct);
99 Instruction::ThrowException throwException;
100 bytecodeGenerator->addInstruction(throwException);
103Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
bool strict,
104 CodegenWarningInterface *iface,
bool storeSourceLocations)
108 _labelledStatement(
nullptr),
109 jsUnitGenerator(jsUnitGenerator),
111 storeSourceLocations(storeSourceLocations),
112 _fileNameIsUrl(
false),
115 jsUnitGenerator->codeGeneratorName = QStringLiteral(
"moth");
120 QLatin1StringView(
"Array"),
121 QLatin1StringView(
"ArrayBuffer"),
122 QLatin1StringView(
"Atomics"),
123 QLatin1StringView(
"Boolean"),
124 QLatin1StringView(
"DOMException"),
125 QLatin1StringView(
"DataView"),
126 QLatin1StringView(
"Date"),
127 QLatin1StringView(
"Error"),
128 QLatin1StringView(
"EvalError"),
129 QLatin1StringView(
"Float32Array"),
130 QLatin1StringView(
"Float64Array"),
131 QLatin1StringView(
"Function"),
132 QLatin1StringView(
"Infinity"),
133 QLatin1StringView(
"Int16Array"),
134 QLatin1StringView(
"Int32Array"),
135 QLatin1StringView(
"Int8Array"),
136 QLatin1StringView(
"JSON"),
137 QLatin1StringView(
"Map"),
138 QLatin1StringView(
"Math"),
139 QLatin1StringView(
"NaN"),
140 QLatin1StringView(
"Number"),
141 QLatin1StringView(
"Object"),
142 QLatin1StringView(
"Promise"),
143 QLatin1StringView(
"Proxy"),
144 QLatin1StringView(
"QT_TRANSLATE_NOOP"),
145 QLatin1StringView(
"QT_TRID_NOOP"),
146 QLatin1StringView(
"QT_TR_NOOP"),
147 QLatin1StringView(
"Qt"),
148 QLatin1StringView(
"RangeError"),
149 QLatin1StringView(
"ReferenceError"),
150 QLatin1StringView(
"Reflect"),
151 QLatin1StringView(
"RegExp"),
152 QLatin1StringView(
"SQLException"),
153 QLatin1StringView(
"Set"),
154 QLatin1StringView(
"SharedArrayBuffer"),
155 QLatin1StringView(
"String"),
156 QLatin1StringView(
"Symbol"),
157 QLatin1StringView(
"SyntaxError"),
158 QLatin1StringView(
"TypeError"),
159 QLatin1StringView(
"URIError"),
160 QLatin1StringView(
"URL"),
161 QLatin1StringView(
"URLSearchParams"),
162 QLatin1StringView(
"Uint16Array"),
163 QLatin1StringView(
"Uint32Array"),
164 QLatin1StringView(
"Uint8Array"),
165 QLatin1StringView(
"Uint8ClampedArray"),
166 QLatin1StringView(
"WeakMap"),
167 QLatin1StringView(
"WeakSet"),
168 QLatin1StringView(
"XMLHttpRequest"),
169 QLatin1StringView(
"console"),
170 QLatin1StringView(
"decodeURI"),
171 QLatin1StringView(
"decodeURIComponent"),
172 QLatin1StringView(
"encodeURI"),
173 QLatin1StringView(
"encodeURIComponent"),
174 QLatin1StringView(
"escape"),
175 QLatin1StringView(
"eval"),
176 QLatin1StringView(
"gc"),
177 QLatin1StringView(
"isFinite"),
178 QLatin1StringView(
"isNaN"),
179 QLatin1StringView(
"parseFloat"),
180 QLatin1StringView(
"parseInt"),
181 QLatin1StringView(
"print"),
182 QLatin1StringView(
"qsTr"),
183 QLatin1StringView(
"qsTrId"),
184 QLatin1StringView(
"qsTranslate"),
185 QLatin1StringView(
"undefined"),
186 QLatin1StringView(
"unescape"),
189bool Codegen::isNameGlobal(QAnyStringView name)
191 return std::binary_search(std::begin(s_globalNames), std::end(s_globalNames), name);
194void Codegen::forEachGlobalName(qxp::function_ref<
void (QLatin1StringView)> &&handler)
196 for (QLatin1StringView name : s_globalNames)
200void Codegen::generateFromProgram(
201 const QString &sourceCode, Program *node, Module *module, ContextType contextType)
208 ScanFunctions scan(
this, sourceCode, contextType);
214 defineFunction(QStringLiteral(
"%entry"), node,
nullptr, node->statements);
217void Codegen::generateFromModule(
const QString &sourceCode, ESModule *node, Module *module)
224 ScanFunctions scan(
this, sourceCode, ContextType::ESModule);
231 Compiler::Context *moduleContext = _module->contextMap.value(node);
232 for (
const auto &entry: moduleContext->exportEntries) {
233 if (entry.moduleRequest.isEmpty()) {
235 _module->localExportEntries << entry;
236 }
else if (entry.importName == QLatin1Char(
'*')) {
237 _module->starExportEntries << entry;
239 _module->indirectExportEntries << entry;
242 _module->importEntries = moduleContext->importEntries;
244 _module->moduleRequests = std::move(moduleContext->moduleRequests);
245 _module->moduleRequests.removeDuplicates();
248 std::sort(_module->localExportEntries.begin(), _module->localExportEntries.end(), ExportEntry::lessThan);
249 std::sort(_module->starExportEntries.begin(), _module->starExportEntries.end(), ExportEntry::lessThan);
250 std::sort(_module->indirectExportEntries.begin(), _module->indirectExportEntries.end(), ExportEntry::lessThan);
252 defineFunction(QStringLiteral(
"%entry"), node,
nullptr, node->body);
255void Codegen::generateFromModule(
const Value &value, Module *module)
260 _module->newContext(
nullptr,
nullptr, ContextType::ESModule);
261 enterContext(
nullptr);
263 _context->name = QStringLiteral(
"%entry");
264 _module->functions.append(_context);
265 _context->functionIndex = _module->functions.size() - 1;
268 entry.localName = entry.exportName = QLatin1String(
"default");
269 _module->localExportEntries << entry;
271 if (Object *o = value.objectValue()) {
273 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
274 QV4::PropertyAttributes attrs;
275 QV4::ScopedPropertyKey name(scope);
277 name = it.next(
nullptr, &attrs);
278 if (!name->isValid())
282 entry.localName = entry.exportName = name->toQString();
283 _module->localExportEntries << entry;
287 std::sort(_module->localExportEntries.begin(), _module->localExportEntries.end(),
288 ExportEntry::lessThan);
290 for (
auto it = _module->localExportEntries.cbegin(), end = _module->localExportEntries.cend();
292 Context::Member member;
293 member.index = _context->locals.size();
294 _context->locals.append(it->exportName);
295 _context->members.insert(it->exportName, member);
301void Codegen::enterContext(Node *node)
303 _context = _module->contextMap.value(node);
307int Codegen::leaveContext()
310 int functionIndex = _context->functionIndex;
311 _context = _context->parent;
312 return functionIndex;
315Context *Codegen::enterBlock(Node *node)
321Codegen::Reference Codegen::unop(UnaryOperation op,
const Reference &expr)
326 if (expr.isConstant()) {
327 auto v = StaticValue::fromReturnedValue(expr.constant);
331 return Reference::fromConst(
this, Encode(!v.toBoolean()));
336 int intVal = v.integerValue();
337 if (intVal && intVal != std::numeric_limits<
int>::min())
338 r = QV4::Encode(-intVal);
340 r = QV4::Encode(-
double(intVal));
341 }
else if (v.isDouble()) {
342 r = QV4::Encode(-v.doubleValue());
344 r = QV4::Encode(-v.int_32());
346 return Reference::fromConst(
this, r);
350 return Reference::fromConst(
this, Encode((
int)~v.toInt32()));
359 expr.loadInAccumulator();
360 Instruction::UMinus uminus = {};
361 bytecodeGenerator->addInstruction(uminus);
362 return Reference::fromAccumulator(
this);
365 expr.loadInAccumulator();
366 Instruction::UPlus uplus = {};
367 bytecodeGenerator->addInstruction(uplus);
368 return Reference::fromAccumulator(
this);
371 expr.loadInAccumulator();
372 Instruction::UNot unot;
373 bytecodeGenerator->addInstruction(unot);
374 return Reference::fromAccumulator(
this);
377 expr.loadInAccumulator();
378 Instruction::UCompl ucompl;
379 bytecodeGenerator->addInstruction(ucompl);
380 return Reference::fromAccumulator(
this);
383 if (!exprAccept(nx) || requiresReturnValue) {
384 Reference e = expr.asLValue();
385 e.loadInAccumulator();
386 Instruction::UPlus uplus = {};
387 bytecodeGenerator->addInstruction(uplus);
388 Reference originalValue = Reference::fromStackSlot(
this).storeRetainAccumulator();
389 Instruction::Increment inc = {};
390 bytecodeGenerator->addInstruction(inc);
391 e.storeConsumeAccumulator();
392 return originalValue;
399 Reference e = expr.asLValue();
400 e.loadInAccumulator();
401 Instruction::Increment inc = {};
402 bytecodeGenerator->addInstruction(inc);
404 return e.storeConsumeAccumulator();
406 return e.storeRetainAccumulator();
409 if (!exprAccept(nx) || requiresReturnValue) {
410 Reference e = expr.asLValue();
411 e.loadInAccumulator();
412 Instruction::UPlus uplus = {};
413 bytecodeGenerator->addInstruction(uplus);
414 Reference originalValue = Reference::fromStackSlot(
this).storeRetainAccumulator();
415 Instruction::Decrement dec = {};
416 bytecodeGenerator->addInstruction(dec);
417 e.storeConsumeAccumulator();
418 return originalValue;
425 Reference e = expr.asLValue();
426 e.loadInAccumulator();
427 Instruction::Decrement dec = {};
428 bytecodeGenerator->addInstruction(dec);
430 return e.storeConsumeAccumulator();
432 return e.storeRetainAccumulator();
439void Codegen::addCJump()
441 const Result &expression = currentExpr();
442 bytecodeGenerator->addCJumpInstruction(expression.trueBlockFollowsCondition(),
443 expression.iftrue(), expression.iffalse());
446void Codegen::statement(Statement *ast)
448 RegisterScope scope(
this);
450 bytecodeGenerator->incrementStatement();
451 bytecodeGenerator->setLocation(ast->firstSourceLocation());
453 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
454 qSwap(_volatileMemoryLocations, vLocs);
456 qSwap(_volatileMemoryLocations, vLocs);
459void Codegen::statement(ExpressionNode *ast)
464 RegisterScope scope(
this);
466 bytecodeGenerator->incrementStatement();
467 pushExpr(Result(nx));
468 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
469 qSwap(_volatileMemoryLocations, vLocs);
473 qSwap(_volatileMemoryLocations, vLocs);
474 Reference result = popResult();
478 if (result.loadTriggersSideEffect())
479 result.loadInAccumulator();
483void Codegen::condition(ExpressionNode *ast,
const BytecodeGenerator::Label *iftrue,
484 const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition)
492 pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition));
494 Result r = popExpr();
499 if (r.format() == ex) {
500 Q_ASSERT(iftrue == r.iftrue());
501 Q_ASSERT(iffalse == r.iffalse());
502 Q_ASSERT(r.result().isValid());
503 bytecodeGenerator->setLocation(ast->firstSourceLocation());
504 r.result().loadInAccumulator();
505 if (r.trueBlockFollowsCondition())
506 bytecodeGenerator->jumpFalse().link(*r.iffalse());
508 bytecodeGenerator->jumpTrue().link(*r.iftrue());
512void Codegen::program(Program *ast)
515 statementList(ast->statements);
527 for (StatementList *it = list; it; it = it->next) {
528 if (it->statement->kind == Statement::Kind_BreakStatement ||
529 it->statement->kind == Statement::Kind_ContinueStatement)
531 if (it->statement->kind == Statement::Kind_EmptyStatement ||
532 it->statement->kind == Statement::Kind_VariableDeclaration ||
533 it->statement->kind == Statement::Kind_FunctionDeclaration)
535 if (it->statement->kind == Statement::Kind_Block) {
536 CompletionState subState = completionState(
static_cast<Block *>(it->statement)->statements);
548 Node *completionStatement =
nullptr;
549 for (StatementList *it = list; it; it = it->next) {
550 if (it->statement->kind == Statement::Kind_BreakStatement ||
551 it->statement->kind == Statement::Kind_ContinueStatement)
552 return completionStatement;
553 if (it->statement->kind == Statement::Kind_ThrowStatement ||
554 it->statement->kind == Statement::Kind_ReturnStatement)
555 return it->statement;
556 if (it->statement->kind == Statement::Kind_EmptyStatement ||
557 it->statement->kind == Statement::Kind_VariableStatement ||
558 it->statement->kind == Statement::Kind_FunctionDeclaration)
560 if (it->statement->kind == Statement::Kind_Block) {
561 CompletionState state = completionState(
static_cast<Block *>(it->statement)->statements);
566 return it->statement;
571 completionStatement = it->statement;
573 return completionStatement;
576void Codegen::statementList(StatementList *ast)
581 bool _requiresReturnValue = requiresReturnValue;
584 if (!controlFlow || !controlFlow->hasLoop())
585 requiresReturnValue =
false;
587 Node *needsCompletion =
nullptr;
589 if (_requiresReturnValue && !requiresReturnValue)
590 needsCompletion = completionStatement(ast);
592 if (requiresReturnValue && !needsCompletion && !insideSwitch) {
594 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
597 bool _insideSwitch = insideSwitch;
598 insideSwitch =
false;
600 for (StatementList *it = ast; it; it = it->next) {
601 if (it->statement == needsCompletion)
602 requiresReturnValue =
true;
603 if (Statement *s = it->statement->statementCast())
606 statement(
static_cast<ExpressionNode *>(it->statement));
607 if (it->statement == needsCompletion)
608 requiresReturnValue =
false;
609 if (it->statement->kind == Statement::Kind_ThrowStatement
610 || it->statement->kind == Statement::Kind_BreakStatement
611 || it->statement->kind == Statement::Kind_ContinueStatement
612 || it->statement->kind == Statement::Kind_ReturnStatement) {
614 if (Visitor *visitor = _interface->unreachableVisitor())
615 Node::accept(it->next, visitor);
619 requiresReturnValue = _requiresReturnValue;
620 insideSwitch = _insideSwitch;
623void Codegen::variableDeclaration(PatternElement *ast)
625 TailCallBlocker blockTailCalls(
this);
626 RegisterScope scope(
this);
628 if (!ast->initializer) {
629 if (ast->isLexicallyScoped()) {
630 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
631 Reference varToStore = targetForPatternElement(ast);
632 varToStore.storeConsumeAccumulator();
636 initializeAndDestructureBindingElement(ast, Reference(),
true);
639void Codegen::variableDeclarationList(VariableDeclarationList *ast)
641 for (VariableDeclarationList *it = ast; it; it = it->next) {
642 variableDeclaration(it->declaration);
646Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
648 if (!p->bindingIdentifier.isNull())
649 return referenceForName(p->bindingIdentifier.toString(),
true, p->firstSourceLocation());
650 if (!p->bindingTarget || p->destructuringPattern())
651 return Codegen::Reference::fromStackSlot(
this);
652 Reference lhs = expression(p->bindingTarget);
655 if (!lhs.isLValue()) {
656 throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral(
"Binding target is not a reference."));
659 lhs = lhs.asLValue();
663void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e,
const Reference &base,
bool isDefinition)
665 Q_ASSERT(e->type == AST::PatternElement::Binding || e->type == AST::PatternElement::RestElement);
666 RegisterScope scope(
this);
667 Reference baseRef = (base.isAccumulator()) ? base.storeOnStack() : base;
668 Reference varToStore = targetForPatternElement(e);
670 varToStore.isReferenceToConst =
false;
674 accept(e->typeAnnotation);
676 if (e->initializer) {
677 if (!baseRef.isValid()) {
679 Reference expr = expression(e->initializer);
682 expr.loadInAccumulator();
683 varToStore.storeConsumeAccumulator();
684 }
else if (baseRef == varToStore) {
685 baseRef.loadInAccumulator();
686 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
687 Reference expr = expression(e->initializer);
692 expr.loadInAccumulator();
693 varToStore.storeConsumeAccumulator();
696 baseRef.loadInAccumulator();
697 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
698 Reference expr = expression(e->initializer);
703 expr.loadInAccumulator();
705 varToStore.storeConsumeAccumulator();
707 }
else if (baseRef != varToStore && baseRef.isValid()) {
708 baseRef.loadInAccumulator();
709 varToStore.storeConsumeAccumulator();
711 Pattern *p = e->destructuringPattern();
715 if (!varToStore.isStackSlot())
716 varToStore = varToStore.storeOnStack();
717 if (PatternElementList *l = e->elementList()) {
718 destructureElementList(varToStore, l, isDefinition);
719 }
else if (PatternPropertyList *p = e->propertyList()) {
720 destructurePropertyList(varToStore, p, isDefinition);
721 }
else if (e->bindingTarget) {
723 varToStore.loadInAccumulator();
724 Instruction::ToObject toObject;
725 bytecodeGenerator->addInstruction(toObject);
730Codegen::Reference Codegen::referenceForPropertyName(
const Codegen::Reference &object, AST::PropertyName *name)
732 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
735 Reference computedName = expression(cname->expression);
738 computedName = computedName.storeOnStack();
739 property = Reference::fromSubscript(object, computedName).asLValue();
741 QString propertyName = name->asString();
742 property = Reference::fromMember(object, propertyName);
747void Codegen::destructurePropertyList(
const Codegen::Reference &object, PatternPropertyList *bindingList,
bool isDefinition)
749 RegisterScope scope(
this);
751 object.loadInAccumulator();
752 Instruction::ThrowOnNullOrUndefined t;
753 bytecodeGenerator->addInstruction(t);
755 for (PatternPropertyList *it = bindingList; it; it = it->next) {
756 PatternProperty *p = it->property;
757 RegisterScope scope(
this);
758 Reference property = referenceForPropertyName(object, p->name);
761 initializeAndDestructureBindingElement(p, property, isDefinition);
767void Codegen::destructureElementList(
const Codegen::Reference &array, PatternElementList *bindingList,
bool isDefinition)
769 RegisterScope scope(
this);
771 Reference iterator = Reference::fromStackSlot(
this);
772 QVarLengthArray<Reference> iteratorValues;
775 array.loadInAccumulator();
776 Instruction::GetIterator iteratorObjInstr;
777 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
778 bytecodeGenerator->addInstruction(iteratorObjInstr);
779 iterator.storeConsumeAccumulator();
781 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
782 Reference needsClose = Reference::storeConstOnStack(
this, Encode(
false));
784 for (PatternElementList *p = bindingList; p; p = p->next) {
785 PatternElement *e = p->element;
786 for (Elision *elision = p->elision; elision; elision = elision->next) {
787 iterator.loadInAccumulator();
788 Instruction::IteratorNext next;
789 if (!ignored.isValid())
790 ignored = Reference::fromStackSlot(
this);
791 next.value = ignored.stackSlot();
792 bytecodeGenerator->addJumpInstruction(next).link(done);
798 if (e->type != PatternElement::RestElement) {
799 iterator.loadInAccumulator();
800 Instruction::IteratorNext next;
801 iteratorValues.push_back(Reference::fromStackSlot(
this));
802 next.value = iteratorValues.back().stackSlot();
803 bytecodeGenerator->addJumpInstruction(next).link(done);
811 Reference::fromConst(
this, Encode(
true)).storeOnStack(needsClose.stackSlot());
814 bytecodeGenerator->checkException();
817 ControlFlowUnwindCleanup flow(
this, [&]() {
818 BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
819 needsClose.loadInAccumulator();
820 bytecodeGenerator->jumpFalse().link(skipClose);
821 iterator.loadInAccumulator();
822 Instruction::IteratorClose close;
823 bytecodeGenerator->addInstruction(close);
827 auto it = iteratorValues.constBegin();
828 for (PatternElementList *p = bindingList; p; p = p->next) {
829 PatternElement *e = p->element;
834 if (e->type == PatternElement::RestElement) {
835 Q_ASSERT(it == iteratorValues.constEnd());
838 Reference::fromConst(
this, Encode(
false)).storeOnStack(needsClose.stackSlot());
840 iterator.loadInAccumulator();
841 bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
842 initializeAndDestructureBindingElement(
843 e, Reference::fromAccumulator(
this), isDefinition);
845 Q_ASSERT(it != iteratorValues.constEnd());
846 initializeAndDestructureBindingElement(e, *it++, isDefinition);
855void Codegen::destructurePattern(Pattern *p,
const Reference &rhs)
857 RegisterScope scope(
this);
858 if (
auto *o = AST::cast<ObjectPattern *>(p))
859 destructurePropertyList(rhs, o->properties);
860 else if (
auto *a = AST::cast<ArrayPattern *>(p))
861 destructureElementList(rhs, a->elements);
867bool Codegen::visit(ArgumentList *)
869 Q_UNREACHABLE_RETURN(
false);
872bool Codegen::visit(CaseBlock *)
874 Q_UNREACHABLE_RETURN(
false);
877bool Codegen::visit(CaseClause *)
879 Q_UNREACHABLE_RETURN(
false);
882bool Codegen::visit(CaseClauses *)
884 Q_UNREACHABLE_RETURN(
false);
887bool Codegen::visit(Catch *)
889 Q_UNREACHABLE_RETURN(
false);
892bool Codegen::visit(DefaultClause *)
894 Q_UNREACHABLE_RETURN(
false);
897bool Codegen::visit(Elision *)
899 Q_UNREACHABLE_RETURN(
false);
902bool Codegen::visit(Finally *)
904 Q_UNREACHABLE_RETURN(
false);
907bool Codegen::visit(FormalParameterList *)
909 Q_UNREACHABLE_RETURN(
false);
912bool Codegen::visit(Program *)
914 Q_UNREACHABLE_RETURN(
false);
917bool Codegen::visit(PatternElement *)
919 Q_UNREACHABLE_RETURN(
false);
922bool Codegen::visit(PatternElementList *)
924 Q_UNREACHABLE_RETURN(
false);
927bool Codegen::visit(PatternProperty *)
929 Q_UNREACHABLE_RETURN(
false);
932bool Codegen::visit(PatternPropertyList *)
934 Q_UNREACHABLE_RETURN(
false);
937bool Codegen::visit(ExportDeclaration *ast)
939 if (!ast->exportDefault)
942 TailCallBlocker blockTailCalls(
this);
943 Reference exportedValue;
945 if (
auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
947 visit(
static_cast<FunctionExpression*>(fdecl));
948 exportedValue = popResult();
949 }
else if (
auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
951 visit(
static_cast<ClassExpression*>(classDecl));
952 exportedValue = popResult();
953 }
else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
954 exportedValue = expression(expr);
957 exportedValue.loadInAccumulator();
959 const int defaultExportIndex = _context->locals.indexOf(_context->localNameForDefaultExport);
960 Q_ASSERT(defaultExportIndex != -1);
961 Reference defaultExportSlot = Reference::fromScopedLocal(
this, defaultExportIndex, 0);
962 defaultExportSlot.storeConsumeAccumulator();
967bool Codegen::visit(TypeAnnotation *ast)
969 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Type annotations are not supported (yet)."));
973bool Codegen::visit(StatementList *)
975 Q_UNREACHABLE_RETURN(
false);
978bool Codegen::visit(UiArrayMemberList *)
980 Q_UNREACHABLE_RETURN(
false);
983bool Codegen::visit(UiImport *)
985 Q_UNREACHABLE_RETURN(
false);
988bool Codegen::visit(UiHeaderItemList *)
990 Q_UNREACHABLE_RETURN(
false);
993bool Codegen::visit(UiPragmaValueList *)
995 Q_UNREACHABLE_RETURN(
false);
998bool Codegen::visit(UiPragma *)
1000 Q_UNREACHABLE_RETURN(
false);
1003bool Codegen::visit(UiObjectInitializer *)
1005 Q_UNREACHABLE_RETURN(
false);
1008bool Codegen::visit(UiObjectMemberList *)
1010 Q_UNREACHABLE_RETURN(
false);
1013bool Codegen::visit(UiParameterList *)
1015 Q_UNREACHABLE_RETURN(
false);
1018bool Codegen::visit(UiProgram *)
1020 Q_UNREACHABLE_RETURN(
false);
1023bool Codegen::visit(UiQualifiedId *)
1025 Q_UNREACHABLE_RETURN(
false);
1028bool Codegen::visit(VariableDeclarationList *)
1030 Q_UNREACHABLE_RETURN(
false);
1033bool Codegen::visit(ClassExpression *ast)
1035 TailCallBlocker blockTailCalls(
this);
1037 Compiler::Class jsClass;
1038 jsClass.nameIndex = registerString(ast->name.toString());
1040 ClassElementList *constructor =
nullptr;
1041 int nComputedNames = 0;
1042 int nStaticComputedNames = 0;
1044 RegisterScope scope(
this);
1045 ControlFlowBlock controlFlow(
this, ast);
1047 for (
auto *member = ast->elements; member; member = member->next) {
1048 PatternProperty *p = member->property;
1049 FunctionExpression *f = p->initializer->asFunctionDefinition();
1051 AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
1054 if (member->isStatic)
1055 ++nStaticComputedNames;
1057 QString name = p->name->asString();
1058 uint nameIndex = cname ? UINT_MAX : registerString(name);
1059 Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
1060 if (p->type == PatternProperty::Getter)
1061 type = Compiler::Class::Method::Getter;
1062 else if (p->type == PatternProperty::Setter)
1063 type = Compiler::Class::Method::Setter;
1064 Compiler::Class::Method m{ nameIndex, type,
static_cast<uint>(defineFunction(name, f, f->formals, f->body)) };
1066 if (member->isStatic) {
1067 if (name == QStringLiteral(
"prototype")) {
1068 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a static method named 'prototype'."));
1071 jsClass.staticMethods << m;
1073 if (name == QStringLiteral(
"constructor")) {
1075 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a multiple constructors in a class."));
1078 if (m.type != Compiler::Class::Method::Regular) {
1079 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a getter or setter named 'constructor'."));
1082 constructor = member;
1083 jsClass.constructorIndex = m.functionIndex;
1087 jsClass.methods << m;
1091 int classIndex = _module->classes.size();
1092 _module->classes.append(jsClass);
1094 Reference heritage = Reference::fromStackSlot(
this);
1095 if (ast->heritage) {
1096 bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
1097 Reference r = expression(ast->heritage);
1100 r.storeOnStack(heritage.stackSlot());
1102 Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1103 heritage.storeConsumeAccumulator();
1106 int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
1107 int currentStaticName = computedNames;
1108 int currentNonStaticName = computedNames + nStaticComputedNames;
1110 for (
auto *member = ast->elements; member; member = member->next) {
1111 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
1114 RegisterScope scope(
this);
1115 bytecodeGenerator->setLocation(cname->firstSourceLocation());
1116 Reference computedName = expression(cname->expression);
1119 computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
1122 Instruction::CreateClass createClass;
1123 createClass.classIndex = classIndex;
1124 createClass.heritage = heritage.stackSlot();
1125 createClass.computedNames = computedNames;
1127 bytecodeGenerator->addInstruction(createClass);
1129 if (!ast->name.isEmpty()) {
1130 Reference ctor = referenceForName(ast->name.toString(),
true);
1131 ctor.isReferenceToConst =
false;
1132 (
void) ctor.storeRetainAccumulator();
1135 setExprResult(Reference::fromAccumulator(
this));
1139bool Codegen::visit(ClassDeclaration *ast)
1141 TailCallBlocker blockTailCalls(
this);
1142 Reference outerVar = referenceForName(ast->name.toString(),
true);
1143 visit(
static_cast<ClassExpression *>(ast));
1144 (
void) outerVar.storeRetainAccumulator();
1148bool Codegen::visit(CommaExpression *ast)
1153 TailCallBlocker blockTailCalls(
this);
1154 statement(ast->left);
1155 blockTailCalls.unblock();
1156 clearExprResultName();
1161bool Codegen::visit(ArrayPattern *ast)
1166 TailCallBlocker blockTailCalls(
this);
1168 PatternElementList *it = ast->elements;
1172 RegisterScope scope(
this);
1175 auto push = [
this, &argc, &args](AST::ExpressionNode *arg) {
1176 int temp = bytecodeGenerator->newRegister();
1180 auto c = Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue());
1181 (
void) c.storeOnStack(temp);
1183 RegisterScope scope(
this);
1184 Reference r = expression(arg);
1187 (
void) r.storeOnStack(temp);
1192 for (; it; it = it->next) {
1193 PatternElement *e = it->element;
1194 if (e && e->type == PatternElement::SpreadElement)
1196 for (Elision *elision = it->elision; elision; elision = elision->next)
1202 push(e->initializer);
1208 Q_ASSERT(argc == 0);
1212 Instruction::DefineArray call;
1214 call.args = Moth::StackSlot::createRegister(args);
1215 bytecodeGenerator->addInstruction(call);
1219 setExprResult(Reference::fromAccumulator(
this));
1222 Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
1224 RegisterScope scope(
this);
1225 Reference array = Reference::fromStackSlot(
this);
1226 array.storeConsumeAccumulator();
1227 Reference index = Reference::storeConstOnStack(
this, Encode(argc));
1229 auto pushAccumulator = [&]() {
1230 Reference slot = Reference::fromSubscript(array, index);
1231 slot.storeConsumeAccumulator();
1233 index.loadInAccumulator();
1234 Instruction::Increment inc = {};
1235 bytecodeGenerator->addInstruction(inc);
1236 index.storeConsumeAccumulator();
1240 for (Elision *elision = it->elision; elision; elision = elision->next) {
1241 Reference::fromConst(
1242 this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1252 if (it->element->type == PatternElement::SpreadElement) {
1253 RegisterScope scope(
this);
1255 Reference iterator = Reference::fromStackSlot(
this);
1256 Reference lhsValue = Reference::fromStackSlot(
this);
1261 RegisterScope innerScope(
this);
1262 Reference expr = expression(it->element->initializer);
1266 expr.loadInAccumulator();
1267 Instruction::GetIterator iteratorObjInstr;
1268 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
1269 bytecodeGenerator->addInstruction(iteratorObjInstr);
1270 iterator.storeConsumeAccumulator();
1273 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
1274 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
1275 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
1278 auto cleanup = [
this, iterator, done]() {
1279 iterator.loadInAccumulator();
1280 Instruction::IteratorClose close;
1281 bytecodeGenerator->addInstruction(close);
1284 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
1287 bytecodeGenerator->addLoopStart(in);
1288 iterator.loadInAccumulator();
1289 Instruction::IteratorNext next;
1290 next.value = lhsValue.stackSlot();
1291 bytecodeGenerator->addJumpInstruction(next).link(done);
1293 lhsValue.loadInAccumulator();
1296 bytecodeGenerator->checkException();
1297 bytecodeGenerator->jump().link(in);
1301 RegisterScope innerScope(
this);
1302 Reference expr = expression(it->element->initializer);
1306 expr.loadInAccumulator();
1313 array.loadInAccumulator();
1314 setExprResult(Reference::fromAccumulator(
this));
1319bool Codegen::visit(ArrayMemberExpression *ast)
1324 const bool isTailOfChain = traverseOptionalChain(ast);
1326 TailCallBlocker blockTailCalls(
this);
1327 Reference base = expression(ast->base);
1329 auto writeSkip = [&]() {
1330 base.loadInAccumulator();
1331 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
1332 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
1333 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
1338 if (base.isSuper()) {
1339 Reference index = expression(ast->expression).storeOnStack();
1340 optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
1343 base = base.storeOnStack();
1346 if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
1347 QString s = str->value.toString();
1348 uint arrayIndex = stringToArrayIndex(s);
1349 if (arrayIndex == UINT_MAX) {
1350 auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
1352 &m_optionalChainsStates.top().jumpsToPatch);
1354 optionalChainFinalizer(ref, isTailOfChain);
1358 if (ast->isOptional)
1361 Reference index = Reference::fromConst(
this, QV4::Encode(arrayIndex));
1362 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1367 if (ast->isOptional)
1370 Reference index = expression(ast->expression);
1375 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1381 switch ((QSOperator::Op) op) {
1382 case QSOperator::InplaceAnd:
return QSOperator::BitAnd;
1383 case QSOperator::InplaceSub:
return QSOperator::Sub;
1384 case QSOperator::InplaceDiv:
return QSOperator::Div;
1385 case QSOperator::InplaceAdd:
return QSOperator::Add;
1386 case QSOperator::InplaceLeftShift:
return QSOperator::LShift;
1387 case QSOperator::InplaceMod:
return QSOperator::Mod;
1388 case QSOperator::InplaceExp:
return QSOperator::Exp;
1389 case QSOperator::InplaceMul:
return QSOperator::Mul;
1390 case QSOperator::InplaceOr:
return QSOperator::BitOr;
1391 case QSOperator::InplaceRightShift:
return QSOperator::RShift;
1392 case QSOperator::InplaceURightShift:
return QSOperator::URShift;
1393 case QSOperator::InplaceXor:
return QSOperator::BitXor;
1394 default:
return QSOperator::Invalid;
1398bool Codegen::visit(BinaryExpression *ast)
1403 TailCallBlocker blockTailCalls(
this);
1405 if (ast->op == QSOperator::And) {
1406 if (exprAccept(cx)) {
1407 auto iftrue = bytecodeGenerator->newLabel();
1408 condition(ast->left, &iftrue, currentExpr().iffalse(),
true);
1410 blockTailCalls.unblock();
1411 const Result &expr = currentExpr();
1412 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1414 auto iftrue = bytecodeGenerator->newLabel();
1415 auto endif = bytecodeGenerator->newLabel();
1417 Reference left = expression(ast->left);
1420 left.loadInAccumulator();
1422 bytecodeGenerator->setLocation(ast->operatorToken);
1423 bytecodeGenerator->jumpFalse().link(endif);
1426 blockTailCalls.unblock();
1427 Reference right = expression(ast->right);
1430 right.loadInAccumulator();
1434 setExprResult(Reference::fromAccumulator(
this));
1437 }
else if (ast->op == QSOperator::Or) {
1438 if (exprAccept(cx)) {
1439 auto iffalse = bytecodeGenerator->newLabel();
1440 condition(ast->left, currentExpr().iftrue(), &iffalse,
false);
1442 const Result &expr = currentExpr();
1443 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1445 auto iffalse = bytecodeGenerator->newLabel();
1446 auto endif = bytecodeGenerator->newLabel();
1448 Reference left = expression(ast->left);
1451 left.loadInAccumulator();
1453 bytecodeGenerator->setLocation(ast->operatorToken);
1454 bytecodeGenerator->jumpTrue().link(endif);
1457 blockTailCalls.unblock();
1458 Reference right = expression(ast->right);
1461 right.loadInAccumulator();
1465 setExprResult(Reference::fromAccumulator(
this));
1468 }
else if (ast->op == QSOperator::Coalesce) {
1470 Reference left = expression(ast->left);
1474 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
1476 Instruction::CmpEqNull cmp;
1478 left = left.storeOnStack();
1479 left.loadInAccumulator();
1480 bytecodeGenerator->addInstruction(cmp);
1482 bytecodeGenerator->jumpTrue().link(iftrue);
1484 blockTailCalls.unblock();
1486 left.loadInAccumulator();
1487 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
1490 Reference right = expression(ast->right);
1491 right.loadInAccumulator();
1493 setExprResult(Reference::fromAccumulator(
this));
1496 }
else if (ast->op == QSOperator::Assign) {
1497 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1498 if (AST::Pattern *p = ast->left->patternCast()) {
1499 RegisterScope scope(
this);
1500 Reference right = expression(ast->right);
1503 right = right.storeOnStack();
1504 destructurePattern(p, right);
1505 if (!exprAccept(nx)) {
1506 right.loadInAccumulator();
1507 setExprResult(Reference::fromAccumulator(
this));
1511 Reference left = expression(ast->left);
1515 if (!left.isLValue()) {
1516 throwReferenceError(ast->operatorToken, QStringLiteral(
"left-hand side of assignment operator is not an lvalue"));
1519 left = left.asLValue();
1520 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1522 blockTailCalls.unblock();
1523 Reference r = expression(ast->right);
1526 r.loadInAccumulator();
1528 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1530 setExprResult(left.storeConsumeAccumulator());
1532 setExprResult(left.storeRetainAccumulator());
1536 Reference left = expression(ast->left);
1541 case QSOperator::Or:
1542 case QSOperator::And:
1543 case QSOperator::Assign:
1547 case QSOperator::InplaceAnd:
1548 case QSOperator::InplaceSub:
1549 case QSOperator::InplaceDiv:
1550 case QSOperator::InplaceAdd:
1551 case QSOperator::InplaceLeftShift:
1552 case QSOperator::InplaceMod:
1553 case QSOperator::InplaceExp:
1554 case QSOperator::InplaceMul:
1555 case QSOperator::InplaceOr:
1556 case QSOperator::InplaceRightShift:
1557 case QSOperator::InplaceURightShift:
1558 case QSOperator::InplaceXor: {
1559 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1562 if (!left.isLValue()) {
1563 throwSyntaxError(ast->operatorToken, QStringLiteral(
"left-hand side of inplace operator is not an lvalue"));
1566 left = left.asLValue();
1568 Reference tempLeft = left.storeOnStack();
1569 Reference right = expression(ast->right);
1574 binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
1575 setExprResult(left.storeRetainAccumulator());
1580 case QSOperator::BitAnd:
1581 case QSOperator::BitOr:
1582 case QSOperator::BitXor:
1583 if (left.isConstant()) {
1584 Reference right = expression(ast->right);
1587 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), right, left));
1591 case QSOperator::In:
1592 case QSOperator::InstanceOf:
1593 case QSOperator::As:
1594 case QSOperator::Equal:
1595 case QSOperator::NotEqual:
1596 case QSOperator::Ge:
1597 case QSOperator::Gt:
1598 case QSOperator::Le:
1599 case QSOperator::Lt:
1600 case QSOperator::StrictEqual:
1601 case QSOperator::StrictNotEqual:
1602 case QSOperator::Add:
1603 case QSOperator::Div:
1604 case QSOperator::Exp:
1605 case QSOperator::Mod:
1606 case QSOperator::Mul:
1607 case QSOperator::Sub:
1608 case QSOperator::LShift:
1609 case QSOperator::RShift:
1610 case QSOperator::URShift: {
1612 if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
1614 right = exprResult();
1616 left = left.storeOnStack();
1617 right = expression(ast->right);
1622 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), left, right));
1631Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
1634 auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
1635 bytecodeGenerator->setLocation(loc);
1637 case QSOperator::Add: {
1638 left = left.storeOnStack();
1639 right.loadInAccumulator();
1640 Instruction::Add add;
1641 add.lhs = left.stackSlot();
1642 bytecodeGenerator->addInstruction(add);
1645 case QSOperator::Sub: {
1646 if (right.isConstant() && right.constant == Encode(
int(1))) {
1647 left.loadInAccumulator();
1648 Instruction::Decrement dec = {};
1649 bytecodeGenerator->addInstruction(dec);
1651 left = left.storeOnStack();
1652 right.loadInAccumulator();
1653 Instruction::Sub sub;
1654 sub.lhs = left.stackSlot();
1655 bytecodeGenerator->addInstruction(sub);
1659 case QSOperator::Exp: {
1660 left = left.storeOnStack();
1661 right.loadInAccumulator();
1662 Instruction::Exp exp;
1663 exp.lhs = left.stackSlot();
1664 bytecodeGenerator->addInstruction(exp);
1667 case QSOperator::Mul: {
1668 left = left.storeOnStack();
1669 right.loadInAccumulator();
1670 Instruction::Mul mul;
1671 mul.lhs = left.stackSlot();
1672 bytecodeGenerator->addInstruction(mul);
1675 case QSOperator::Div: {
1676 left = left.storeOnStack();
1677 right.loadInAccumulator();
1678 Instruction::Div div;
1679 div.lhs = left.stackSlot();
1680 bytecodeGenerator->addInstruction(div);
1683 case QSOperator::Mod: {
1684 left = left.storeOnStack();
1685 right.loadInAccumulator();
1686 Instruction::Mod mod;
1687 mod.lhs = left.stackSlot();
1688 bytecodeGenerator->addInstruction(mod);
1691 case QSOperator::BitAnd:
1692 if (right.isConstant()) {
1693 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1694 if (left.isConstant()) {
1695 int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
1696 return Reference::fromConst(
this, Encode(result));
1698 left.loadInAccumulator();
1699 Instruction::BitAndConst bitAnd;
1700 bitAnd.rhs = rightAsInt;
1701 bytecodeGenerator->addInstruction(bitAnd);
1703 right.loadInAccumulator();
1704 Instruction::BitAnd bitAnd;
1705 bitAnd.lhs = left.stackSlot();
1706 bytecodeGenerator->addInstruction(bitAnd);
1709 case QSOperator::BitOr:
1710 if (right.isConstant()) {
1711 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1712 if (left.isConstant()) {
1713 int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
1714 return Reference::fromConst(
this, Encode(result));
1716 left.loadInAccumulator();
1717 Instruction::BitOrConst bitOr;
1718 bitOr.rhs = rightAsInt;
1719 bytecodeGenerator->addInstruction(bitOr);
1721 right.loadInAccumulator();
1722 Instruction::BitOr bitOr;
1723 bitOr.lhs = left.stackSlot();
1724 bytecodeGenerator->addInstruction(bitOr);
1727 case QSOperator::BitXor:
1728 if (right.isConstant()) {
1729 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1730 if (left.isConstant()) {
1731 int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
1732 return Reference::fromConst(
this, Encode(result));
1734 left.loadInAccumulator();
1735 Instruction::BitXorConst bitXor;
1736 bitXor.rhs = rightAsInt;
1737 bytecodeGenerator->addInstruction(bitXor);
1739 right.loadInAccumulator();
1740 Instruction::BitXor bitXor;
1741 bitXor.lhs = left.stackSlot();
1742 bytecodeGenerator->addInstruction(bitXor);
1745 case QSOperator::URShift:
1746 if (right.isConstant()) {
1747 left.loadInAccumulator();
1748 Instruction::UShrConst ushr;
1749 ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1750 bytecodeGenerator->addInstruction(ushr);
1752 right.loadInAccumulator();
1753 Instruction::UShr ushr;
1754 ushr.lhs = left.stackSlot();
1755 bytecodeGenerator->addInstruction(ushr);
1758 case QSOperator::RShift:
1759 if (right.isConstant()) {
1760 left.loadInAccumulator();
1761 Instruction::ShrConst shr;
1762 shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1763 bytecodeGenerator->addInstruction(shr);
1765 right.loadInAccumulator();
1766 Instruction::Shr shr;
1767 shr.lhs = left.stackSlot();
1768 bytecodeGenerator->addInstruction(shr);
1771 case QSOperator::LShift:
1772 if (right.isConstant()) {
1773 left.loadInAccumulator();
1774 Instruction::ShlConst shl;
1775 shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1776 bytecodeGenerator->addInstruction(shl);
1778 right.loadInAccumulator();
1779 Instruction::Shl shl;
1780 shl.lhs = left.stackSlot();
1781 bytecodeGenerator->addInstruction(shl);
1784 case QSOperator::InstanceOf: {
1785 Instruction::CmpInstanceOf binop;
1786 left = left.storeOnStack();
1787 right.loadInAccumulator();
1788 binop.lhs = left.stackSlot();
1789 bytecodeGenerator->addInstruction(binop);
1792 case QSOperator::As: {
1794 left = left.storeOnStack();
1795 right.loadInAccumulator();
1796 as.lhs = left.stackSlot();
1797 bytecodeGenerator->addInstruction(as);
1800 case QSOperator::In: {
1801 Instruction::CmpIn binop;
1802 left = left.storeOnStack();
1803 right.loadInAccumulator();
1804 binop.lhs = left.stackSlot();
1805 bytecodeGenerator->addInstruction(binop);
1808 case QSOperator::StrictEqual: {
1810 return jumpBinop(oper, left, right);
1812 Instruction::CmpStrictEqual cmp;
1813 left = left.storeOnStack();
1814 right.loadInAccumulator();
1815 cmp.lhs = left.stackSlot();
1816 bytecodeGenerator->addInstruction(cmp);
1819 case QSOperator::StrictNotEqual: {
1821 return jumpBinop(oper, left, right);
1823 Instruction::CmpStrictNotEqual cmp;
1824 left = left.storeOnStack();
1825 right.loadInAccumulator();
1826 cmp.lhs = left.stackSlot();
1827 bytecodeGenerator->addInstruction(cmp);
1830 case QSOperator::Equal: {
1832 return jumpBinop(oper, left, right);
1834 Instruction::CmpEq cmp;
1835 left = left.storeOnStack();
1836 right.loadInAccumulator();
1837 cmp.lhs = left.stackSlot();
1838 bytecodeGenerator->addInstruction(cmp);
1841 case QSOperator::NotEqual: {
1843 return jumpBinop(oper, left, right);
1845 Instruction::CmpNe cmp;
1846 left = left.storeOnStack();
1847 right.loadInAccumulator();
1848 cmp.lhs = left.stackSlot();
1849 bytecodeGenerator->addInstruction(cmp);
1852 case QSOperator::Gt: {
1854 return jumpBinop(oper, left, right);
1856 Instruction::CmpGt cmp;
1857 left = left.storeOnStack();
1858 right.loadInAccumulator();
1859 cmp.lhs = left.stackSlot();
1860 bytecodeGenerator->addInstruction(cmp);
1863 case QSOperator::Ge: {
1865 return jumpBinop(oper, left, right);
1867 Instruction::CmpGe cmp;
1868 left = left.storeOnStack();
1869 right.loadInAccumulator();
1870 cmp.lhs = left.stackSlot();
1871 bytecodeGenerator->addInstruction(cmp);
1874 case QSOperator::Lt: {
1876 return jumpBinop(oper, left, right);
1878 Instruction::CmpLt cmp;
1879 left = left.storeOnStack();
1880 right.loadInAccumulator();
1881 cmp.lhs = left.stackSlot();
1882 bytecodeGenerator->addInstruction(cmp);
1885 case QSOperator::Le:
1887 return jumpBinop(oper, left, right);
1889 Instruction::CmpLe cmp;
1890 left = left.storeOnStack();
1891 right.loadInAccumulator();
1892 cmp.lhs = left.stackSlot();
1893 bytecodeGenerator->addInstruction(cmp);
1899 return Reference::fromAccumulator(
this);
1902Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
1905 if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
1907 if (left.isConstant() && !right.isConstant())
1910 if (right.isConstant()) {
1911 StaticValue c = StaticValue::fromReturnedValue(right.constant);
1912 if (c.isNull() || c.isUndefined()) {
1913 left.loadInAccumulator();
1914 if (oper == QSOperator::Equal) {
1915 Instruction::CmpEqNull cmp;
1916 bytecodeGenerator->addInstruction(cmp);
1919 }
else if (oper == QSOperator::NotEqual) {
1920 Instruction::CmpNeNull cmp;
1921 bytecodeGenerator->addInstruction(cmp);
1925 }
else if (c.isInt32()) {
1926 left.loadInAccumulator();
1927 if (oper == QSOperator::Equal) {
1928 Instruction::CmpEqInt cmp;
1929 cmp.lhs = c.int_32();
1930 bytecodeGenerator->addInstruction(cmp);
1933 }
else if (oper == QSOperator::NotEqual) {
1934 Instruction::CmpNeInt cmp;
1935 cmp.lhs = c.int_32();
1936 bytecodeGenerator->addInstruction(cmp);
1945 left = left.storeOnStack();
1946 right.loadInAccumulator();
1949 case QSOperator::StrictEqual: {
1950 Instruction::CmpStrictEqual cmp;
1951 cmp.lhs = left.stackSlot();
1952 bytecodeGenerator->addInstruction(cmp);
1956 case QSOperator::StrictNotEqual: {
1957 Instruction::CmpStrictNotEqual cmp;
1958 cmp.lhs = left.stackSlot();
1959 bytecodeGenerator->addInstruction(cmp);
1963 case QSOperator::Equal: {
1964 Instruction::CmpEq cmp;
1965 cmp.lhs = left.stackSlot();
1966 bytecodeGenerator->addInstruction(cmp);
1970 case QSOperator::NotEqual: {
1971 Instruction::CmpNe cmp;
1972 cmp.lhs = left.stackSlot();
1973 bytecodeGenerator->addInstruction(cmp);
1977 case QSOperator::Gt: {
1978 Instruction::CmpGt cmp;
1979 cmp.lhs = left.stackSlot();
1980 bytecodeGenerator->addInstruction(cmp);
1984 case QSOperator::Ge: {
1985 Instruction::CmpGe cmp;
1986 cmp.lhs = left.stackSlot();
1987 bytecodeGenerator->addInstruction(cmp);
1991 case QSOperator::Lt: {
1992 Instruction::CmpLt cmp;
1993 cmp.lhs = left.stackSlot();
1994 bytecodeGenerator->addInstruction(cmp);
1998 case QSOperator::Le: {
1999 Instruction::CmpLe cmp;
2000 cmp.lhs = left.stackSlot();
2001 bytecodeGenerator->addInstruction(cmp);
2011Codegen::Reference Codegen::loadSubscriptForCall(
const Codegen::Reference &base)
2015 base.elementSubscript.loadInAccumulator();
2016 Codegen::Instruction::LoadElement load;
2017 load.base = base.elementBase;
2018 bytecodeGenerator->addInstruction(load);
2019 return Reference::fromAccumulator(
this);
2022bool Codegen::visit(CallExpression *ast)
2027 const bool isTailOfChain = traverseOptionalChain(ast);
2029 RegisterScope scope(
this);
2030 TailCallBlocker blockTailCalls(
this);
2032 Reference expr = expression(ast->base);
2033 Reference base = expr;
2037 switch (base.type) {
2038 case Reference::Member:
2039 base = base.asLValue();
2041 case Reference::Subscript:
2042 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2043 base.subscriptLoadedForCall =
true;
2045 case Reference::Name:
2047 case Reference::Super:
2048 handleConstruct(base, ast->arguments);
2050 case Reference::SuperProperty:
2053 base = base.storeOnStack();
2057 if (expr.hasSavedCallBaseSlot) {
2059 base.hasSavedCallBaseSlot =
true;
2060 base.savedCallBaseSlot = expr.savedCallBaseSlot;
2061 base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
2064 int thisObject = bytecodeGenerator->newRegister();
2065 int functionObject = bytecodeGenerator->newRegister();
2067 if (ast->isOptional || m_optionalChainsStates.top().actuallyHasOptionals) {
2068 base.loadInAccumulator();
2069 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2070 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2071 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2074 auto calldata = pushArgs(ast->arguments);
2078 blockTailCalls.unblock();
2079 if (calldata.hasSpread || _tailCallsAreAllowed) {
2080 Reference baseObject = base.baseObject();
2081 if (!baseObject.isStackSlot()) {
2082 baseObject.storeOnStack(thisObject);
2083 baseObject = Reference::fromStackSlot(
this, thisObject);
2086 const int func = [&]() {
2087 if (base.type == Reference::Subscript)
2088 return base.element;
2090 if (!base.isStackSlot()) {
2091 base.storeOnStack(functionObject);
2092 base = Reference::fromStackSlot(
this, functionObject);
2095 return base.stackSlot();
2098 if (calldata.hasSpread) {
2099 Instruction::CallWithSpread call;
2101 call.thisObject = baseObject.stackSlot();
2102 call.argc = calldata.argc;
2103 call.argv = calldata.argv;
2104 bytecodeGenerator->addInstruction(call);
2106 Instruction::TailCall call;
2108 call.thisObject = baseObject.stackSlot();
2109 call.argc = calldata.argc;
2110 call.argv = calldata.argv;
2111 bytecodeGenerator->addInstruction(call);
2114 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2118 handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
2119 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2123void Codegen::endVisit(CallExpression *ast)
2125 m_seenOptionalChainNodes.remove(ast);
2128void Codegen::handleCall(Reference &base, Arguments calldata,
int slotForFunction,
int slotForThisObject,
bool optional)
2130 if (base.sourceLocation.isValid())
2131 bytecodeGenerator->setLocation(base.sourceLocation);
2134 if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
2135 if (useFastLookups) {
2136 Instruction::CallPropertyLookup call;
2137 if (base.hasSavedCallBaseSlot) {
2138 call.base = base.savedCallBaseSlot;
2139 call.lookupIndex = registerGetterLookup(
2140 base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
2142 call.base = base.propertyBase.stackSlot();
2143 call.lookupIndex = registerGetterLookup(
2144 base.propertyNameIndex, JSUnitGenerator::LookupForCall);
2146 call.argc = calldata.argc;
2147 call.argv = calldata.argv;
2148 bytecodeGenerator->addInstruction(call);
2150 Instruction::CallProperty call;
2151 if (base.hasSavedCallBaseSlot) {
2152 call.base = base.savedCallBaseSlot;
2153 call.name = base.savedCallPropertyNameIndex;
2155 call.base = base.propertyBase.stackSlot();
2156 call.name = base.propertyNameIndex;
2158 call.argc = calldata.argc;
2159 call.argv = calldata.argv;
2160 bytecodeGenerator->addInstruction(call);
2162 }
else if (base.type == Reference::Subscript) {
2163 Instruction::CallWithReceiver call;
2164 call.thisObject = base.elementBase.stackSlot();
2165 call.name = base.element;
2166 call.argc = calldata.argc;
2167 call.argv = calldata.argv;
2168 bytecodeGenerator->addInstruction(call);
2169 }
else if (base.type == Reference::Name) {
2170 if (base.name == QStringLiteral(
"eval") && !optional) {
2171 Instruction::CallPossiblyDirectEval call;
2172 call.argc = calldata.argc;
2173 call.argv = calldata.argv;
2174 bytecodeGenerator->addInstruction(call);
2175 }
else if (useFastLookups && base.global) {
2176 if (base.qmlGlobal) {
2177 Instruction::CallQmlContextPropertyLookup call;
2178 call.index = registerQmlContextPropertyGetterLookup(
2179 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2180 call.argc = calldata.argc;
2181 call.argv = calldata.argv;
2182 bytecodeGenerator->addInstruction(call);
2184 Instruction::CallGlobalLookup call;
2185 call.index = registerGlobalGetterLookup(
2186 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2187 call.argc = calldata.argc;
2188 call.argv = calldata.argv;
2189 bytecodeGenerator->addInstruction(call);
2192 Instruction::CallName call;
2193 call.name = base.nameAsIndex();
2194 call.argc = calldata.argc;
2195 call.argv = calldata.argv;
2196 bytecodeGenerator->addInstruction(call);
2198 }
else if (base.type == Reference::SuperProperty) {
2199 Reference receiver = base.baseObject();
2200 if (!base.isStackSlot()) {
2201 base.storeOnStack(slotForFunction);
2202 base = Reference::fromStackSlot(
this, slotForFunction);
2204 if (!receiver.isStackSlot()) {
2205 receiver.storeOnStack(slotForThisObject);
2206 receiver = Reference::fromStackSlot(
this, slotForThisObject);
2208 Instruction::CallWithReceiver call;
2209 call.name = base.stackSlot();
2210 call.thisObject = receiver.stackSlot();
2211 call.argc = calldata.argc;
2212 call.argv = calldata.argv;
2213 bytecodeGenerator->addInstruction(call);
2215 Q_ASSERT(base.isStackSlot());
2216 Instruction::CallValue call;
2217 call.name = base.stackSlot();
2218 call.argc = calldata.argc;
2219 call.argv = calldata.argv;
2220 bytecodeGenerator->addInstruction(call);
2224Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
2226 bool hasSpread =
false;
2228 for (ArgumentList *it = args; it; it = it->next) {
2229 if (it->isSpreadElement) {
2237 return { 0, 0,
false };
2239 int calldata = bytecodeGenerator->newRegisterArray(argc);
2242 for (ArgumentList *it = args; it; it = it->next) {
2243 if (it->isSpreadElement) {
2244 Reference::fromConst(
2246 StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
2249 RegisterScope scope(
this);
2250 Reference e = expression(it->expression);
2253 if (!argc && !it->next && !hasSpread) {
2255 if (e.isStackSlot()) {
2257 return { 1, e.stackSlot(), hasSpread };
2260 (
void) e.storeOnStack(calldata + argc);
2264 return { argc, calldata, hasSpread };
2267Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
2270 for (TemplateLiteral *it = args; it; it = it->next)
2274 return { 0, 0,
false };
2276 int calldata = bytecodeGenerator->newRegisterArray(argc);
2279 for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
2280 RegisterScope scope(
this);
2281 Reference e = expression(it->expression);
2284 (
void) e.storeOnStack(calldata + argc);
2288 return { argc, calldata,
false };
2291bool Codegen::visit(ConditionalExpression *ast)
2296 RegisterScope scope(
this);
2297 TailCallBlocker blockTailCalls(
this);
2299 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
2300 BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
2301 condition(ast->expression, &iftrue, &iffalse,
true);
2303 blockTailCalls.unblock();
2306 Reference ok = expression(ast->ok);
2309 ok.loadInAccumulator();
2310 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
2313 Reference ko = expression(ast->ko);
2318 ko.loadInAccumulator();
2321 setExprResult(Reference::fromAccumulator(
this));
2326bool Codegen::visit(DeleteExpression *ast)
2331 const bool isTailOfChain = traverseOptionalChain(ast);
2333 RegisterScope scope(
this);
2334 TailCallBlocker blockTailCalls(
this);
2335 Reference expr = expression(ast->expression);
2339 const bool chainActuallyHasOptionals = m_optionalChainsStates.top().actuallyHasOptionals;
2340 if (chainActuallyHasOptionals)
2341 Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
2343 switch (expr.type) {
2344 case Reference::SuperProperty:
2347 case Reference::StackSlot:
2348 if (!expr.stackSlotIsLocalOrArgument)
2351 case Reference::ScopedLocal:
2353 if (_context->isStrict) {
2354 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2357 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2359 case Reference::Name: {
2360 if (_context->isStrict) {
2361 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2364 Instruction::DeleteName del;
2365 del.name = expr.nameAsIndex();
2366 bytecodeGenerator->addInstruction(del);
2367 setExprResult(Reference::fromAccumulator(
this));
2370 case Reference::Member: {
2372 expr = expr.asLValue();
2374 if (chainActuallyHasOptionals) {
2375 expr.loadInAccumulator();
2376 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2377 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2378 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2381 Instruction::LoadRuntimeString instr;
2382 instr.stringId = expr.propertyNameIndex;
2383 bytecodeGenerator->addInstruction(instr);
2384 Reference index = Reference::fromStackSlot(
this);
2385 index.storeConsumeAccumulator();
2386 Instruction::DeleteProperty del;
2387 del.base = expr.propertyBase.stackSlot();
2388 del.index = index.stackSlot();
2389 bytecodeGenerator->addInstruction(del);
2390 auto ref = Reference::fromAccumulator(
this);
2392 optionalChainFinalizer(ref, isTailOfChain,
true);
2395 case Reference::Subscript: {
2397 expr = expr.asLValue();
2399 if (chainActuallyHasOptionals) {
2400 expr.loadInAccumulator();
2401 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2402 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2403 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2406 Instruction::DeleteProperty del;
2407 del.base = expr.elementBase;
2408 del.index = expr.elementSubscript.stackSlot();
2409 bytecodeGenerator->addInstruction(del);
2410 auto ref = Reference::fromAccumulator(
this);
2412 optionalChainFinalizer(ref, isTailOfChain,
true);
2419 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
2423void Codegen::endVisit(DeleteExpression *ast) {
2424 m_seenOptionalChainNodes.remove(ast);
2427bool Codegen::visit(FalseLiteral *)
2432 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2436bool Codegen::visit(SuperLiteral *)
2441 setExprResult(Reference::fromSuper(
this));
2445bool Codegen::traverseOptionalChain(Node *node)
2447 if (m_seenOptionalChainNodes.contains(node))
2450 const auto isOptionalChainableNode = [](
const Node *node) {
2451 return node->kind == Node::Kind_FieldMemberExpression ||
2452 node->kind == Node::Kind_CallExpression ||
2453 node->kind == Node::Kind_ArrayMemberExpression ||
2454 node->kind == Node::Kind_DeleteExpression;
2456 m_optionalChainsStates.emplace();
2457 while (isOptionalChainableNode(node)) {
2458 m_seenOptionalChainNodes.insert(node);
2460 switch (node->kind) {
2461 case Node::Kind_FieldMemberExpression: {
2462 auto *fme = AST::cast<FieldMemberExpression *>(node);
2463 m_optionalChainsStates.top().actuallyHasOptionals |= fme->isOptional;
2467 case Node::Kind_CallExpression: {
2468 auto *ce = AST::cast<CallExpression *>(node);
2469 m_optionalChainsStates.top().actuallyHasOptionals |= ce->isOptional;
2473 case Node::Kind_ArrayMemberExpression: {
2474 auto *ame = AST::cast<ArrayMemberExpression *>(node);
2475 m_optionalChainsStates.top().actuallyHasOptionals |= ame->isOptional;
2479 case Node::Kind_DeleteExpression:
2480 node = AST::cast<DeleteExpression *>(node)->expression;
2490void Codegen::optionalChainFinalizer(
const Reference &expressionResult,
bool tailOfChain,
2491 bool isDeleteExpression)
2493 auto &chainState = m_optionalChainsStates.top();
2495 setExprResult(expressionResult);
2497 }
else if (!chainState.actuallyHasOptionals) {
2498 setExprResult(expressionResult);
2499 m_optionalChainsStates.pop();
2503 auto savedBaseSlot = -1;
2504 if (expressionResult.type == Reference::Member)
2505 savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
2506 expressionResult.loadInAccumulator();
2508 std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
2509 if (!isDeleteExpression)
2510 jumpToDone.emplace(bytecodeGenerator->jump());
2512 for (
auto &jump : chainState.jumpsToPatch)
2515 if (isDeleteExpression)
2516 bytecodeGenerator->addInstruction(Instruction::LoadTrue());
2518 bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
2520 if (jumpToDone.has_value())
2521 jumpToDone.value().link();
2523 auto ref = Reference::fromAccumulator(
this);
2524 if (expressionResult.type == Reference::Member) {
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537 ref.hasSavedCallBaseSlot =
true;
2538 ref.savedCallBaseSlot = savedBaseSlot;
2539 ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
2542 m_optionalChainsStates.pop();
2545bool Codegen::visit(FieldMemberExpression *ast)
2550 const bool isTailOfChain = traverseOptionalChain(ast);
2552 TailCallBlocker blockTailCalls(
this);
2554 if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
2555 if (id->name == QLatin1String(
"new")) {
2557 Q_ASSERT(ast->name == QLatin1String(
"target"));
2559 if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
2560 Reference r = referenceForName(QStringLiteral(
"new.target"),
false);
2561 r.isReadonly =
true;
2567 auto ref = Reference::fromStackSlot(
this, CallData::NewTarget);
2568 optionalChainFinalizer(ref, isTailOfChain);
2573 Reference base = expression(ast->base);
2577 if (base.isSuper()) {
2578 Instruction::LoadRuntimeString load;
2579 load.stringId = registerString(ast->name.toString());
2580 bytecodeGenerator->addInstruction(load);
2581 Reference property = Reference::fromAccumulator(
this).storeOnStack();
2583 optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
2587 auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
2588 ast->isOptional, &m_optionalChainsStates.top().jumpsToPatch);
2590 optionalChainFinalizer(ref, isTailOfChain);
2594void Codegen::endVisit(FieldMemberExpression *ast)
2596 m_seenOptionalChainNodes.remove(ast);
2599bool Codegen::visit(TaggedTemplate *ast)
2604 RegisterScope scope(
this);
2605 return handleTaggedTemplate(expression(ast->base), ast);
2608bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
2613 int functionObject = -1, thisObject = -1;
2614 switch (base.type) {
2615 case Reference::Member:
2616 base = base.asLValue();
2618 case Reference::Subscript:
2619 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2620 base.subscriptLoadedForCall =
true;
2622 case Reference::Name:
2624 case Reference::SuperProperty:
2625 thisObject = bytecodeGenerator->newRegister();
2626 functionObject = bytecodeGenerator->newRegister();
2629 base = base.storeOnStack();
2633 createTemplateObject(ast->templateLiteral);
2634 int templateObjectTemp = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
2635 Q_UNUSED(templateObjectTemp);
2636 auto calldata = pushTemplateArgs(ast->templateLiteral);
2640 Q_ASSERT(calldata.argv == templateObjectTemp + 1);
2643 handleCall(base, calldata, functionObject, thisObject);
2644 setExprResult(Reference::fromAccumulator(
this));
2648void Codegen::createTemplateObject(TemplateLiteral *t)
2652 for (TemplateLiteral *it = t; it; it = it->next) {
2653 obj.strings.append(registerString(it->value.toString()));
2654 obj.rawStrings.append(registerString(it->rawValue.toString()));
2657 int index = _module->templateObjects.size();
2658 _module->templateObjects.append(obj);
2660 Instruction::GetTemplateObject getTemplateObject;
2661 getTemplateObject.index = index;
2662 bytecodeGenerator->addInstruction(getTemplateObject);
2665bool Codegen::visit(FunctionExpression *ast)
2670 TailCallBlocker blockTailCalls(
this);
2672 RegisterScope scope(
this);
2674 int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
2677 loadClosure(function);
2678 setExprResult(Reference::fromAccumulator(
this));
2682Codegen::Reference Codegen::referenceForName(
const QString &name,
bool isLhs,
const SourceLocation &accessLocation)
2684 Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
2685 bool throwsReferenceError =
false;
2687 if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
2688 || resolved.type == Context::ResolvedName::Import) {
2689 if (resolved.isArgOrEval && isLhs)
2691 throwSyntaxError(SourceLocation(), QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
2693 if (resolved.declarationLocation.isValid() && accessLocation.isValid()
2694 && resolved.declarationLocation.begin() > accessLocation.end()) {
2695 Q_ASSERT(_interface);
2696 if (resolved.memberType == Context::FunctionDefinition) {
2697 _interface->reportFunctionUsedBeforeDeclaration(
2698 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2700 _interface->reportVarUsedBeforeDeclaration(
2701 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2703 if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
2704 throwsReferenceError =
true;
2707 if (resolved.isInjected && accessLocation.isValid()) {
2708 qCWarning(lcQmlInjectedParameter).nospace().noquote()
2709 << url().toString() <<
":" << accessLocation.startLine
2710 <<
":" << accessLocation.startColumn <<
" Parameter \"" << name
2711 <<
"\" is not declared."
2712 <<
" Injection of parameters into signal handlers is deprecated."
2713 <<
" Use JavaScript functions with formal parameters instead.";
2717 switch (resolved.type) {
2718 case Context::ResolvedName::Local:
2719 r = Reference::fromScopedLocal(
this, resolved.index, resolved.scope);
break;
2720 case Context::ResolvedName::Stack:
2721 r = Reference::fromStackSlot(
this, resolved.index,
true );
break;
2722 case Context::ResolvedName::Import:
2723 r = Reference::fromImport(
this, resolved.index);
break;
2724 default: Q_UNREACHABLE();
2726 if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
2727 r.isVolatile =
true;
2728 r.isArgOrEval = resolved.isArgOrEval;
2729 r.isReferenceToConst = resolved.isConst;
2730 r.requiresTDZCheck = resolved.requiresTDZCheck;
2732 r.sourceLocation = accessLocation;
2733 r.throwsReferenceError = throwsReferenceError;
2737 Reference r = Reference::fromName(
this, name);
2738 r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
2739 r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
2740 r.sourceLocation = accessLocation;
2741 if (!r.global && !r.qmlGlobal
2742 && _context->contextType == ContextType::ScriptImportedByQML
2743 && Codegen::isNameGlobal(name)) {
2753void Codegen::loadClosure(
int closureId)
2755 if (closureId >= 0) {
2756 Instruction::LoadClosure load;
2757 load.value = closureId;
2758 bytecodeGenerator->addInstruction(load);
2760 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
2764bool Codegen::visit(IdentifierExpression *ast)
2769 setExprResult(referenceForName(ast->name.toString(),
false, ast->firstSourceLocation()));
2773bool Codegen::visit(NestedExpression *ast)
2778 accept(ast->expression);
2782void Codegen::handleConstruct(
const Reference &base, ArgumentList *arguments)
2784 Reference constructor;
2785 if (base.isSuper()) {
2786 Instruction::LoadSuperConstructor super;
2787 bytecodeGenerator->addInstruction(super);
2788 constructor = Reference::fromAccumulator(
this).storeOnStack();
2790 constructor = base.storeOnStack();
2793 auto calldata = pushArgs(arguments);
2798 Reference::fromStackSlot(
this, CallData::NewTarget).loadInAccumulator();
2800 constructor.loadInAccumulator();
2802 if (calldata.hasSpread) {
2803 Instruction::ConstructWithSpread create;
2804 create.func = constructor.stackSlot();
2805 create.argc = calldata.argc;
2806 create.argv = calldata.argv;
2807 bytecodeGenerator->addInstruction(create);
2809 Instruction::Construct create;
2810 create.func = constructor.stackSlot();
2811 create.argc = calldata.argc;
2812 create.argv = calldata.argv;
2813 bytecodeGenerator->addInstruction(create);
2817 Reference::fromAccumulator(
this).storeOnStack(CallData::This);
2819 setExprResult(Reference::fromAccumulator(
this));
2822bool Codegen::visit(NewExpression *ast)
2827 RegisterScope scope(
this);
2828 TailCallBlocker blockTailCalls(
this);
2830 Reference base = expression(ast->expression);
2833 if (base.isSuper()) {
2834 throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2838 handleConstruct(base,
nullptr);
2842bool Codegen::visit(NewMemberExpression *ast)
2847 RegisterScope scope(
this);
2848 TailCallBlocker blockTailCalls(
this);
2850 Reference base = expression(ast->base);
2853 if (base.isSuper()) {
2854 throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2858 handleConstruct(base, ast->arguments);
2862bool Codegen::visit(NotExpression *ast)
2867 TailCallBlocker blockTailCalls(
this);
2868 setExprResult(unop(Not, expression(ast->expression)));
2872bool Codegen::visit(NullExpression *)
2878 bytecodeGenerator->jump().link(*currentExpr().iffalse());
2880 setExprResult(Reference::fromConst(
this, Encode::null()));
2885bool Codegen::visit(NumericLiteral *ast)
2890 setExprResult(Reference::fromConst(
this, QV4::Encode::smallestNumber(ast->value)));
2894bool Codegen::visit(ObjectPattern *ast)
2899 TailCallBlocker blockTailCalls(
this);
2901 RegisterScope scope(
this);
2903 QStringList members;
2907 auto push = [
this, &args, &argc](
const Reference &arg) {
2908 int temp = bytecodeGenerator->newRegister();
2911 (
void) arg.storeOnStack(temp);
2915 PatternPropertyList *it = ast->properties;
2916 for (; it; it = it->next) {
2917 PatternProperty *p = it->property;
2918 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2919 if (cname || p->type != PatternProperty::Literal)
2921 QString name = p->name->asString();
2922 uint arrayIndex = stringToArrayIndex(name);
2923 if (arrayIndex != UINT_MAX)
2925 if (members.contains(name))
2927 members.append(name);
2930 RegisterScope innerScope(
this);
2931 Reference value = expression(p->initializer, name);
2934 value.loadInAccumulator();
2936 push(Reference::fromAccumulator(
this));
2939 int classId = jsUnitGenerator->registerJSClass(members);
2942 for (; it; it = it->next) {
2943 PatternProperty *p = it->property;
2944 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2945 ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
2946 if (p->type == PatternProperty::Method)
2947 argType = ObjectLiteralArgument::Method;
2948 else if (p->type == PatternProperty::Getter)
2949 argType = ObjectLiteralArgument::Getter;
2950 else if (p->type == PatternProperty::Setter)
2951 argType = ObjectLiteralArgument::Setter;
2953 Reference::fromConst(
this, Encode(
int(argType))).loadInAccumulator();
2954 push(Reference::fromAccumulator(
this));
2957 RegisterScope innerScope(
this);
2958 Reference name = expression(cname->expression);
2961 name.loadInAccumulator();
2963 QString name = p->name->asString();
2965 uint arrayIndex = QV4::String::toArrayIndex(name);
2966 if (arrayIndex != UINT_MAX) {
2967 Reference::fromConst(
this, Encode(arrayIndex)).loadInAccumulator();
2971 Instruction::LoadRuntimeString instr;
2972 instr.stringId = registerString(name);
2973 bytecodeGenerator->addInstruction(instr);
2976 push(Reference::fromAccumulator(
this));
2978 RegisterScope innerScope(
this);
2979 if (p->type != PatternProperty::Literal) {
2981 FunctionExpression *f = p->initializer->asFunctionDefinition();
2983 int function = defineFunction(f->name.toString(), f, f->formals, f->body);
2986 Reference::fromConst(
this, Encode(function)).loadInAccumulator();
2988 Reference value = expression(p->initializer);
2991 value.loadInAccumulator();
2994 push(Reference::fromAccumulator(
this));
2997 Instruction::DefineObjectLiteral call;
2998 call.internalClassId = classId;
3000 call.args = Moth::StackSlot::createRegister(args);
3001 bytecodeGenerator->addInstruction(call);
3002 setExprResult(Reference::fromAccumulator(
this));
3006bool Codegen::visit(PostDecrementExpression *ast)
3011 Reference expr = expression(ast->base);
3014 if (!expr.isLValue()) {
3015 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3018 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3021 setExprResult(unop(PostDecrement, expr));
3026bool Codegen::visit(PostIncrementExpression *ast)
3031 Reference expr = expression(ast->base);
3034 if (!expr.isLValue()) {
3035 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3038 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3041 setExprResult(unop(PostIncrement, expr));
3045bool Codegen::visit(PreDecrementExpression *ast)
3049 Reference expr = expression(ast->expression);
3052 if (!expr.isLValue()) {
3053 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3057 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3059 setExprResult(unop(PreDecrement, expr));
3063bool Codegen::visit(PreIncrementExpression *ast)
3068 Reference expr = expression(ast->expression);
3071 if (!expr.isLValue()) {
3072 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3076 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3078 setExprResult(unop(PreIncrement, expr));
3082bool Codegen::visit(RegExpLiteral *ast)
3087 auto r = Reference::fromStackSlot(
this);
3088 r.isReadonly =
true;
3091 Instruction::MoveRegExp instr;
3092 instr.regExpId = jsUnitGenerator->registerRegExp(ast);
3093 instr.destReg = r.stackSlot();
3094 bytecodeGenerator->addInstruction(instr);
3098bool Codegen::visit(StringLiteral *ast)
3103 auto r = Reference::fromAccumulator(
this);
3104 r.isReadonly =
true;
3107 Instruction::LoadRuntimeString instr;
3108 instr.stringId = registerString(ast->value.toString());
3109 bytecodeGenerator->addInstruction(instr);
3113bool Codegen::visit(TemplateLiteral *ast)
3118 TailCallBlocker blockTailCalls(
this);
3120 Instruction::LoadRuntimeString instr;
3121 instr.stringId = registerString(ast->value.toString());
3122 bytecodeGenerator->addInstruction(instr);
3124 if (ast->expression) {
3125 RegisterScope scope(
this);
3126 int temp = bytecodeGenerator->newRegister();
3127 Instruction::StoreReg store;
3129 bytecodeGenerator->addInstruction(store);
3131 Reference expr = expression(ast->expression);
3136 int temp2 = bytecodeGenerator->newRegister();
3137 expr.storeOnStack(temp2);
3140 Instruction::Add instr;
3142 bytecodeGenerator->addInstruction(instr);
3144 expr.loadInAccumulator();
3147 Instruction::Add instr;
3149 bytecodeGenerator->addInstruction(instr);
3152 auto r = Reference::fromAccumulator(
this);
3153 r.isReadonly =
true;
3160bool Codegen::visit(ThisExpression *)
3165 for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
3166 if (parentContext->isArrowFunction) {
3167 Reference r = referenceForName(QStringLiteral(
"this"),
false);
3168 r.isReadonly =
true;
3172 if (parentContext->contextType != ContextType::Block)
3176 setExprResult(Reference::fromThis(
this));
3180bool Codegen::visit(TildeExpression *ast)
3185 TailCallBlocker blockTailCalls(
this);
3186 setExprResult(unop(Compl, expression(ast->expression)));
3190bool Codegen::visit(TrueLiteral *)
3195 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
3199bool Codegen::visit(TypeOfExpression *ast)
3204 RegisterScope scope(
this);
3205 TailCallBlocker blockTailCalls(
this);
3207 Reference expr = expression(ast->expression);
3211 if (expr.type == Reference::Name) {
3213 Instruction::TypeofName instr;
3214 instr.name = expr.nameAsIndex();
3215 bytecodeGenerator->addInstruction(instr);
3217 expr.loadInAccumulator();
3218 Instruction::TypeofValue instr;
3219 bytecodeGenerator->addInstruction(instr);
3221 setExprResult(Reference::fromAccumulator(
this));
3226bool Codegen::visit(UnaryMinusExpression *ast)
3231 TailCallBlocker blockTailCalls(
this);
3232 setExprResult(unop(UMinus, expression(ast->expression)));
3236bool Codegen::visit(UnaryPlusExpression *ast)
3241 TailCallBlocker blockTailCalls(
this);
3242 setExprResult(unop(UPlus, expression(ast->expression)));
3246bool Codegen::visit(VoidExpression *ast)
3251 RegisterScope scope(
this);
3252 TailCallBlocker blockTailCalls(
this);
3254 statement(ast->expression);
3255 setExprResult(Reference::fromConst(
this, Encode::undefined()));
3259bool Codegen::visit(FunctionDeclaration * ast)
3265 RegisterScope scope(
this);
3267 if (_functionContext->contextType == ContextType::Binding)
3268 referenceForName(ast->name.toString(),
true).loadInAccumulator();
3273bool Codegen::visit(YieldExpression *ast)
3275 if (inFormalParameterList) {
3276 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"yield is not allowed inside parameter lists"));
3280 auto innerMostCurentFunctionContext = _context;
3281 while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
3282 innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
3284 Q_ASSERT(innerMostCurentFunctionContext);
3286 if (!innerMostCurentFunctionContext->isGenerator) {
3287 throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
3291 RegisterScope scope(
this);
3292 TailCallBlocker blockTailCalls(
this);
3293 Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(
this, Encode::undefined());
3297 Reference acc = Reference::fromAccumulator(
this);
3299 if (ast->isYieldStar) {
3300 Reference iterator = Reference::fromStackSlot(
this);
3301 Reference lhsValue = Reference::fromConst(
this, Encode::undefined()).storeOnStack();
3303 expr.loadInAccumulator();
3304 Instruction::GetIterator getIterator;
3305 getIterator.iterator =
static_cast<
int>(AST::ForEachType::Of);
3306 bytecodeGenerator->addInstruction(getIterator);
3307 iterator.storeConsumeAccumulator();
3308 Instruction::LoadUndefined load;
3309 bytecodeGenerator->addInstruction(load);
3311 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3312 bytecodeGenerator->jump().link(in);
3314 BytecodeGenerator::Label loop = bytecodeGenerator->label();
3316 lhsValue.loadInAccumulator();
3317 Instruction::YieldStar yield;
3318 bytecodeGenerator->addInstruction(yield);
3322 Instruction::IteratorNextForYieldStar next;
3323 next.object = lhsValue.stackSlot();
3324 next.iterator = iterator.stackSlot();
3325 BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
3326 bytecodeGenerator->jumpNotUndefined().link(loop);
3328 lhsValue.loadInAccumulator();
3333 bytecodeGenerator->checkException();
3335 lhsValue.loadInAccumulator();
3340 expr.loadInAccumulator();
3341 Instruction::Yield yield;
3342 bytecodeGenerator->addInstruction(yield);
3343 Instruction::Resume resume;
3344 BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
3355 if (AST::cast<ReturnStatement *>(node))
3357 if (AST::cast<ThrowStatement *>(node))
3359 if (Program *p = AST::cast<Program *>(node))
3360 return endsWithReturn(module, p->statements);
3361 if (StatementList *sl = AST::cast<StatementList *>(node)) {
3364 return endsWithReturn(module, sl->statement);
3366 if (Block *b = AST::cast<Block *>(node)) {
3367 Context *blockContext = module->contextMap.value(node);
3368 if (blockContext->requiresExecutionContext)
3372 return endsWithReturn(module, b->statements);
3374 if (IfStatement *is = AST::cast<IfStatement *>(node))
3375 return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
3379int Codegen::defineFunction(
const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
3380 AST::StatementList *body)
3384 if (_context->functionIndex >= 0)
3386 return leaveContext();
3388 _context->name = name.isEmpty() ? currentExpr().result().name : name;
3389 _module->functions.append(_context);
3390 _context->functionIndex = _module->functions.size() - 1;
3392 Context *savedFunctionContext = _functionContext;
3393 _functionContext = _context;
3394 ControlFlow *savedControlFlow = controlFlow;
3395 controlFlow =
nullptr;
3397 if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
3398 _module->blocks.append(_context);
3399 _context->blockIndex = _module->blocks.size() - 1;
3401 if (_module->debugMode)
3402 _context->argumentsCanEscape =
true;
3410 _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
3411 && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
3413 BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
3414 BytecodeGenerator *savedBytecodeGenerator;
3415 savedBytecodeGenerator = bytecodeGenerator;
3416 bytecodeGenerator = &bytecode;
3417 bytecodeGenerator->setLocation(ast->firstSourceLocation());
3418 BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
3419 _returnLabel =
nullptr;
3421 bool savedFunctionEndsWithReturn = functionEndsWithReturn;
3422 functionEndsWithReturn = endsWithReturn(_module, body);
3425 bytecodeGenerator->newRegisterArray(
3426 sizeof(CallData) /
sizeof(StaticValue) - 1 + _context->arguments.size());
3428 bool _inFormalParameterList =
false;
3429 qSwap(_inFormalParameterList, inFormalParameterList);
3431 int returnAddress = -1;
3432 bool _requiresReturnValue = _context->requiresImplicitReturnValue();
3433 qSwap(requiresReturnValue, _requiresReturnValue);
3434 returnAddress = bytecodeGenerator->newRegister();
3435 qSwap(_returnAddress, returnAddress);
3438 if (!_context->parent && _context->requiresExecutionContext) {
3439 _module->blocks.append(_context);
3440 _context->blockIndex = _module->blocks.size() - 1;
3443 TailCallBlocker maybeBlockTailCalls(
this, _context->canHaveTailCalls());
3445 RegisterScope registerScope(
this);
3446 _context->emitBlockHeader(
this);
3449 QScopedValueRollback<
bool> inFormals(inFormalParameterList,
true);
3450 TailCallBlocker blockTailCalls(
this);
3454 PatternElement *e = formals->element;
3462 Reference arg = referenceForName(e->bindingIdentifier.toString(),
true);
3463 if (e->type == PatternElement::RestElement) {
3464 Q_ASSERT(!formals->next);
3465 Instruction::CreateRestParameter rest;
3466 rest.argIndex = argc;
3467 bytecodeGenerator->addInstruction(rest);
3468 arg.storeConsumeAccumulator();
3470 if (e->bindingTarget || e->initializer) {
3471 initializeAndDestructureBindingElement(e, arg);
3476 formals = formals->next;
3481 if (_context->isGenerator) {
3482 Instruction::Yield yield;
3483 bytecodeGenerator->addInstruction(yield);
3486 statementList(body);
3489 bytecodeGenerator->setLocation(ast->lastSourceLocation());
3490 _context->emitBlockFooter(
this);
3492 if (_returnLabel || !functionEndsWithReturn) {
3494 _returnLabel->link();
3496 if (_returnLabel || requiresReturnValue) {
3497 Instruction::LoadReg load;
3498 load.reg = Moth::StackSlot::createRegister(_returnAddress);
3499 bytecodeGenerator->addInstruction(load);
3501 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
3504 bytecodeGenerator->addInstruction(Instruction::Ret());
3507 Q_ASSERT(_context == _functionContext);
3508 bytecodeGenerator->finalize(_context);
3509 _context->registerCountInFunction = bytecodeGenerator->registerCount();
3510 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
3512 qDebug() <<
"=== Bytecode for" << _context->name <<
"strict mode" << _context->isStrict
3513 <<
"register count" << _context->registerCountInFunction <<
"implicit return" << requiresReturnValue;
3514 qDebug().noquote() << QV4::Moth::dumpBytecode(
3515 _context->code, _context->locals.size(), _context->arguments.size(),
3516 _context->line, _context->lineAndStatementNumberMapping);
3521 qSwap(_returnAddress, returnAddress);
3522 qSwap(requiresReturnValue, _requiresReturnValue);
3523 qSwap(_inFormalParameterList, inFormalParameterList);
3524 bytecodeGenerator = savedBytecodeGenerator;
3525 delete _returnLabel;
3526 _returnLabel = savedReturnLabel;
3527 controlFlow = savedControlFlow;
3528 functionEndsWithReturn = savedFunctionEndsWithReturn;
3529 _functionContext = savedFunctionContext;
3531 return leaveContext();
3534bool Codegen::visit(Block *ast)
3539 RegisterScope scope(
this);
3541 ControlFlowBlock controlFlow(
this, ast);
3542 statementList(ast->statements);
3546bool Codegen::visit(BreakStatement *ast)
3553 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3557 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
3558 if (!target.linkLabel.isValid()) {
3559 if (ast->label.isEmpty())
3560 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3562 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3566 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3571bool Codegen::visit(ContinueStatement *ast)
3577 RegisterScope scope(
this);
3580 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Continue outside of loop"));
3584 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
3585 if (!target.linkLabel.isValid()) {
3586 if (ast->label.isEmpty())
3587 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3589 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"continue outside of loop"));
3593 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3598bool Codegen::visit(DebuggerStatement *)
3604bool Codegen::visit(DoWhileStatement *ast)
3609 RegisterScope scope(
this);
3611 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3612 BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
3613 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3615 ControlFlowLoop flow(
this, &end, &cond);
3619 if (!AST::cast<FalseLiteral *>(ast->expression))
3620 bytecodeGenerator->addLoopStart(body);
3623 statement(ast->statement);
3624 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
3627 if (AST::cast<TrueLiteral *>(ast->expression)) {
3629 bytecodeGenerator->checkException();
3630 bytecodeGenerator->jump().link(body);
3631 }
else if (AST::cast<FalseLiteral *>(ast->expression)) {
3634 TailCallBlocker blockTailCalls(
this);
3635 bytecodeGenerator->checkException();
3636 condition(ast->expression, &body, &end,
false);
3644bool Codegen::visit(EmptyStatement *)
3649bool Codegen::visit(ExpressionStatement *ast)
3654 RegisterScope scope(
this);
3655 TailCallBlocker blockTailCalls(
this);
3657 if (requiresReturnValue) {
3658 Reference e = expression(ast->expression);
3661 (
void) e.storeOnStack(_returnAddress);
3663 statement(ast->expression);
3668bool Codegen::visit(ForEachStatement *ast)
3673 RegisterScope scope(
this);
3674 TailCallBlocker blockTailCalls(
this);
3676 Reference iterator = Reference::fromStackSlot(
this);
3677 Reference lhsValue = Reference::fromStackSlot(
this);
3682 RegisterScope innerScope(
this);
3683 ControlFlowBlock controlFlow(
this, ast);
3684 Reference expr = expression(ast->expression);
3688 expr.loadInAccumulator();
3689 Instruction::GetIterator iteratorObjInstr;
3690 iteratorObjInstr.iterator =
static_cast<
int>(ast->type);
3691 bytecodeGenerator->addInstruction(iteratorObjInstr);
3692 iterator.storeConsumeAccumulator();
3695 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3696 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3697 BytecodeGenerator::Label done;
3700 std::function<
void()> cleanup;
3701 if (ast->type == ForEachType::Of) {
3702 done = bytecodeGenerator->newLabel();
3703 cleanup = [iterator,
this, done]() {
3704 iterator.loadInAccumulator();
3705 Instruction::IteratorClose close;
3706 bytecodeGenerator->addInstruction(close);
3712 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
3713 bytecodeGenerator->addLoopStart(in);
3715 iterator.loadInAccumulator();
3716 Instruction::IteratorNext next;
3717 next.value = lhsValue.stackSlot();
3718 bytecodeGenerator->addJumpInstruction(next).link(done);
3722 RegisterScope innerScope(
this);
3723 ControlFlowBlock controlFlow(
this, ast);
3725 if (ExpressionNode *e = ast->lhs->expressionCast()) {
3726 if (AST::Pattern *p = e->patternCast()) {
3727 RegisterScope scope(
this);
3728 destructurePattern(p, lhsValue);
3730 Reference lhs = expression(e);
3733 if (!lhs.isLValue()) {
3734 throwReferenceError(e->firstSourceLocation(), QStringLiteral(
"Invalid left-hand side expression for 'in' expression"));
3737 lhs = lhs.asLValue();
3738 lhsValue.loadInAccumulator();
3739 lhs.storeConsumeAccumulator();
3741 }
else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
3742 initializeAndDestructureBindingElement(p, lhsValue,
true);
3749 blockTailCalls.unblock();
3750 statement(ast->statement);
3751 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3754 bytecodeGenerator->checkException();
3755 bytecodeGenerator->jump().link(in);
3767bool Codegen::visit(ForStatement *ast)
3772 RegisterScope scope(
this);
3773 TailCallBlocker blockTailCalls(
this);
3775 ControlFlowBlock controlFlow(
this, ast);
3777 if (ast->initialiser)
3778 statement(ast->initialiser);
3779 else if (ast->declarations)
3780 variableDeclarationList(ast->declarations);
3782 BytecodeGenerator::Label cond = bytecodeGenerator->label();
3783 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3784 BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
3785 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3787 ControlFlowLoop flow(
this, &end, &step);
3788 bytecodeGenerator->addLoopStart(cond);
3789 condition(ast->condition, &body, &end,
true);
3792 blockTailCalls.unblock();
3793 statement(ast->statement);
3794 blockTailCalls.reblock();
3795 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3798 if (_context->requiresExecutionContext) {
3799 Instruction::CloneBlockContext clone;
3800 bytecodeGenerator->addInstruction(clone);
3802 statement(ast->expression);
3803 bytecodeGenerator->checkException();
3804 bytecodeGenerator->jump().link(cond);
3811bool Codegen::visit(IfStatement *ast)
3816 RegisterScope scope(
this);
3817 TailCallBlocker blockTailCalls(
this);
3819 BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
3820 BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
3821 condition(ast->expression, &trueLabel, &falseLabel,
true);
3822 blockTailCalls.unblock();
3827 if (endsWithReturn(_module, ast)) {
3831 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
3843bool Codegen::visit(LabelledStatement *ast)
3848 RegisterScope scope(
this);
3851 ControlFlow *l = controlFlow;
3853 if (l->label() == ast->label) {
3854 QString error = QString(QStringLiteral(
"Label '%1' has already been declared")).arg(ast->label.toString());
3855 throwSyntaxError(ast->firstSourceLocation(), error);
3860 _labelledStatement = ast;
3862 if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
3863 AST::cast<AST::WhileStatement *>(ast->statement) ||
3864 AST::cast<AST::DoWhileStatement *>(ast->statement) ||
3865 AST::cast<AST::ForStatement *>(ast->statement) ||
3866 AST::cast<AST::ForEachStatement *>(ast->statement)) {
3867 statement(ast->statement);
3869 BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
3870 ControlFlowLoop flow(
this, &breakLabel);
3871 statement(ast->statement);
3878void Codegen::emitReturn(
const Reference &expr)
3880 ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
3881 if (target.linkLabel.isValid() && target.unwindLevel) {
3882 Q_ASSERT(_returnAddress >= 0);
3883 (
void) expr.storeOnStack(_returnAddress);
3884 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3886 expr.loadInAccumulator();
3887 bytecodeGenerator->addInstruction(Instruction::Ret());
3891bool Codegen::visit(ReturnStatement *ast)
3896 if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
3897 throwSyntaxError(ast->returnToken, QStringLiteral(
"Return statement outside of function"));
3901 if (ast->expression) {
3902 expr = expression(ast->expression);
3906 expr = Reference::fromConst(
this, Encode::undefined());
3914bool Codegen::visit(SwitchStatement *ast)
3919 if (requiresReturnValue)
3920 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
3922 RegisterScope scope(
this);
3923 TailCallBlocker blockTailCalls(
this);
3926 BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
3928 Reference lhs = expression(ast->expression);
3931 lhs = lhs.storeOnStack();
3933 ControlFlowBlock controlFlow(
this, ast->block);
3936 QHash<Node *, BytecodeGenerator::Label> blockMap;
3937 for (CaseClauses *it = ast->block->clauses; it; it = it->next)
3938 blockMap[it->clause] = bytecodeGenerator->newLabel();
3939 if (ast->block->defaultClause)
3940 blockMap[ast->block->defaultClause] = bytecodeGenerator->newLabel();
3941 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next)
3942 blockMap[it->clause] = bytecodeGenerator->newLabel();
3945 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3946 CaseClause *clause = it->clause;
3947 Reference rhs = expression(clause->expression);
3950 rhs.loadInAccumulator();
3951 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3954 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3955 CaseClause *clause = it->clause;
3956 Reference rhs = expression(clause->expression);
3959 rhs.loadInAccumulator();
3960 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3963 if (DefaultClause *defaultClause = ast->block->defaultClause)
3964 bytecodeGenerator->jump().link(blockMap.value(defaultClause));
3966 bytecodeGenerator->jump().link(switchEnd);
3968 ControlFlowLoop flow(
this, &switchEnd);
3970 insideSwitch =
true;
3971 blockTailCalls.unblock();
3972 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3973 CaseClause *clause = it->clause;
3974 blockMap[clause].link();
3976 statementList(clause->statements);
3979 if (ast->block->defaultClause) {
3980 DefaultClause *clause = ast->block->defaultClause;
3981 blockMap[clause].link();
3983 statementList(clause->statements);
3986 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3987 CaseClause *clause = it->clause;
3988 blockMap[clause].link();
3990 statementList(clause->statements);
3992 insideSwitch =
false;
4001bool Codegen::visit(ThrowStatement *ast)
4006 RegisterScope scope(
this);
4007 TailCallBlocker blockTailCalls(
this);
4009 Reference expr = expression(ast->expression);
4013 expr.loadInAccumulator();
4014 Instruction::ThrowException instr;
4015 bytecodeGenerator->addInstruction(instr);
4019void Codegen::handleTryCatch(TryStatement *ast)
4022 RegisterScope scope(
this);
4024 ControlFlowCatch catchFlow(
this, ast->catchExpression);
4025 RegisterScope scope(
this);
4026 TailCallBlocker blockTailCalls(
this);
4027 statement(ast->statement);
4031void Codegen::handleTryFinally(TryStatement *ast)
4033 RegisterScope scope(
this);
4034 const bool hasCatchBlock = ast->catchExpression;
4035 ControlFlowFinally finally(
this, ast->finallyExpression, hasCatchBlock);
4036 TailCallBlocker blockTailCalls(
this);
4038 if (ast->catchExpression) {
4039 handleTryCatch(ast);
4041 RegisterScope scope(
this);
4042 statement(ast->statement);
4046bool Codegen::visit(TryStatement *ast)
4051 RegisterScope scope(
this);
4053 if (ast->finallyExpression && ast->finallyExpression->statement) {
4054 handleTryFinally(ast);
4056 handleTryCatch(ast);
4062bool Codegen::visit(VariableStatement *ast)
4067 variableDeclarationList(ast->declarations);
4071bool Codegen::visit(WhileStatement *ast)
4076 if (AST::cast<FalseLiteral *>(ast->expression))
4079 RegisterScope scope(
this);
4081 BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
4082 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
4083 BytecodeGenerator::Label cond = bytecodeGenerator->label();
4084 ControlFlowLoop flow(
this, &end, &cond);
4085 bytecodeGenerator->addLoopStart(cond);
4087 bytecodeGenerator->checkException();
4089 if (!AST::cast<TrueLiteral *>(ast->expression)) {
4090 TailCallBlocker blockTailCalls(
this);
4091 condition(ast->expression, &start, &end,
true);
4095 statement(ast->statement);
4096 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->whileToken);
4097 bytecodeGenerator->jump().link(cond);
4103bool Codegen::visit(WithStatement *ast)
4108 RegisterScope scope(
this);
4109 TailCallBlocker blockTailCalls(
this);
4111 Reference src = expression(ast->expression);
4114 src = src.storeOnStack();
4115 src.loadInAccumulator();
4119 blockTailCalls.unblock();
4120 ControlFlowWith flow(
this);
4121 statement(ast->statement);
4128bool Codegen::visit(UiArrayBinding *)
4134bool Codegen::visit(UiObjectBinding *)
4140bool Codegen::visit(UiObjectDefinition *)
4146bool Codegen::visit(UiPublicMember *)
4152bool Codegen::visit(UiScriptBinding *)
4158bool Codegen::visit(UiSourceElement *)
4164bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(
const Reference &r,
const SourceLocation& loc)
4166 if (!_context->isStrict)
4168 bool isArgOrEval =
false;
4169 if (r.type == Reference::Name) {
4170 QString str = jsUnitGenerator->stringForIndex(r.nameAsIndex());
4171 if (str == QLatin1String(
"eval") || str == QLatin1String(
"arguments")) {
4174 }
else if (r.type == Reference::ScopedLocal || r.isRegister()) {
4175 isArgOrEval = r.isArgOrEval;
4178 throwSyntaxError(loc, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
4182void Codegen::throwError(ErrorType errorType,
const SourceLocation &loc,
const QString &detail)
4187 _errorType = errorType;
4188 _error.message = detail;
4192void Codegen::throwSyntaxError(
const SourceLocation &loc,
const QString &detail)
4194 throwError(SyntaxError, loc, detail);
4197void Codegen::throwReferenceError(
const SourceLocation &loc,
const QString &detail)
4199 throwError(ReferenceError, loc, detail);
4202QQmlJS::DiagnosticMessage Codegen::error()
const
4207QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
4208 bool generateUnitData)
4210 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
4211 new QV4::CompiledData::CompilationUnit(
4212 generateUnitData ? jsUnitGenerator->generateUnit() :
nullptr),
4213 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
4216QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
4217 bool debugMode,
const QString &url,
const QString &sourceCode,
4218 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
4221 QQmlJS::Lexer lexer(&ee);
4222 lexer.setCode(sourceCode, 1,
false);
4223 QQmlJS::Parser parser(&ee);
4225 const bool parsed = parser.parseModule();
4228 *diagnostics = parser.diagnosticMessages();
4231 return QQmlRefPointer<CompiledData::CompilationUnit>();
4233 QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
4238 diagnostics->clear();
4242 using namespace QV4::Compiler;
4243 Compiler::Module compilerModule(url, url, debugMode);
4244 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4245 compilerModule.sourceTimeStamp = sourceTimeStamp;
4246 JSUnitGenerator jsGenerator(&compilerModule);
4247 Codegen cg(&jsGenerator,
true);
4248 cg.generateFromModule(sourceCode, moduleNode, &compilerModule);
4249 if (cg.hasError()) {
4251 *diagnostics << cg.error();
4252 return QQmlRefPointer<CompiledData::CompilationUnit>();
4255 return cg.generateCompilationUnit();
4258const QV4::CompiledData::Unit *Codegen::generateNativeModuleUnitData(
4259 bool debugMode,
const QString &url,
const Value &value)
4261 using namespace QV4::Compiler;
4262 Compiler::Module compilerModule(url, url, debugMode);
4263 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4264 JSUnitGenerator jsGenerator(&compilerModule);
4265 Codegen cg(&jsGenerator,
true);
4266 cg.generateFromModule(value, &compilerModule);
4267 Q_ASSERT(!cg.hasError());
4268 return jsGenerator.generateUnit();
4273 VolatileMemoryLocations locs;
4288 bool visit(ArrayMemberExpression *)
override
4290 locs.setAllVolatile();
4294 bool visit(FieldMemberExpression *)
override
4296 locs.setAllVolatile();
4300 bool visit(PostIncrementExpression *e)
override
4302 collectIdentifiers(locs.specificLocations, e->base);
4306 bool visit(PostDecrementExpression *e)
override
4308 collectIdentifiers(locs.specificLocations, e->base);
4312 bool visit(PreIncrementExpression *e)
override
4314 collectIdentifiers(locs.specificLocations, e->expression);
4318 bool visit(PreDecrementExpression *e)
override
4320 collectIdentifiers(locs.specificLocations, e->expression);
4324 bool visit(BinaryExpression *e)
override
4327 case QSOperator::InplaceAnd:
4328 case QSOperator::InplaceSub:
4329 case QSOperator::InplaceDiv:
4330 case QSOperator::InplaceAdd:
4331 case QSOperator::InplaceLeftShift:
4332 case QSOperator::InplaceMod:
4333 case QSOperator::InplaceMul:
4334 case QSOperator::InplaceOr:
4335 case QSOperator::InplaceRightShift:
4336 case QSOperator::InplaceURightShift:
4337 case QSOperator::InplaceXor:
4338 collectIdentifiers(locs.specificLocations, e);
4352 void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
4353 class Collector:
public QQmlJS::AST::Visitor {
4355 QList<QStringView> &ids;
4356 VolatileMemoryLocationScanner *parent;
4359 Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
4360 QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
4363 bool visit(IdentifierExpression *ie) final {
4364 ids.append(ie->name);
4368 void throwRecursionDepthError() final
4370 parent->throwRecursionDepthError();
4373 Collector collector(ids,
this);
4374 node->accept(&collector);
4378Codegen::VolatileMemoryLocations
Codegen::scanVolatileMemoryLocations(AST::Node *ast)
4380 VolatileMemoryLocationScanner scanner(
this);
4381 return scanner.scan(ast);
4386 return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
4389bool Codegen::RValue::operator==(
const RValue &other)
const
4393 return other.isAccumulator();
4395 return other.isStackSlot() && theStackSlot == other.theStackSlot;
4397 return other.isConst() && constant == other.constant;
4403Codegen::RValue Codegen::RValue::storeOnStack()
const
4407 return RValue::fromStackSlot(codegen, Reference::fromAccumulator(codegen).storeOnStack().stackSlot());
4411 return RValue::fromStackSlot(codegen, Reference::storeConstOnStack(codegen, constant).stackSlot());
4417void Codegen::RValue::loadInAccumulator()
const
4424 return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
4426 return Reference::fromConst(codegen, constant).loadInAccumulator();
4433bool Codegen::Reference::operator==(
const Codegen::Reference &other)
const
4435 if (type != other.type)
4444 return property == other.property;
4446 return theStackSlot == other.theStackSlot;
4448 return index == other.index && scope == other.scope;
4450 return nameAsIndex() == other.nameAsIndex();
4452 return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
4454 return elementBase == other.elementBase && other.subscriptLoadedForCall
4455 ? (subscriptLoadedForCall && element == other.element)
4456 : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
4458 return index == other.index;
4460 return constant == other.constant;
4465Codegen::RValue Codegen::Reference::asRValue()
const
4471 return RValue::fromAccumulator(codegen);
4473 return RValue::fromStackSlot(codegen, stackSlot());
4475 return RValue::fromConst(codegen, constant);
4477 loadInAccumulator();
4478 return RValue::fromAccumulator(codegen);
4482Codegen::Reference Codegen::Reference::asLValue()
const
4489 codegen->throwSyntaxError(SourceLocation(), QStringLiteral(
"Super lvalues not implemented."));
4492 if (!propertyBase.isStackSlot()) {
4493 Reference r = *
this;
4494 r.propertyBase = propertyBase.storeOnStack();
4499 if (!elementSubscript.isStackSlot()) {
4500 Reference r = *
this;
4501 r.elementSubscript = elementSubscript.storeOnStack();
4510Codegen::Reference Codegen::Reference::storeConsumeAccumulator()
const
4516Codegen::Reference Codegen::Reference::baseObject()
const
4518 if (type == Reference::Member) {
4519 RValue rval = propertyBase;
4520 if (!rval.isValid())
4521 return Reference::fromConst(codegen, Encode::undefined());
4522 if (rval.isAccumulator())
4523 return Reference::fromAccumulator(codegen);
4524 if (rval.isStackSlot())
4525 return Reference::fromStackSlot(codegen, rval.stackSlot());
4527 return Reference::fromConst(codegen, rval.constantValue());
4529 }
else if (type == Reference::Subscript) {
4530 return Reference::fromStackSlot(codegen, elementBase.stackSlot());
4531 }
else if (type == Reference::SuperProperty) {
4532 return Reference::fromStackSlot(codegen, CallData::This);
4534 return Reference::fromConst(codegen, Encode::undefined());
4538Codegen::Reference Codegen::Reference::storeOnStack()
const
4539{
return doStoreOnStack(-1); }
4541void Codegen::Reference::storeOnStack(
int slotIndex)
const
4542{ doStoreOnStack(slotIndex); }
4544Codegen::Reference Codegen::Reference::doStoreOnStack(
int slotIndex)
const
4546 Q_ASSERT(isValid());
4548 if (isStackSlot() && slotIndex == -1 && !(stackSlotIsLocalOrArgument && isVolatile) && !requiresTDZCheck)
4551 if (isStackSlot() && !requiresTDZCheck) {
4552 Reference dest = Reference::fromStackSlot(codegen, slotIndex);
4553 Instruction::MoveReg move;
4554 move.srcReg = stackSlot();
4555 move.destReg = dest.stackSlot();
4556 codegen->bytecodeGenerator->addInstruction(move);
4560 Reference slot = Reference::fromStackSlot(codegen, slotIndex);
4562 Instruction::MoveConst move;
4563 move.constIndex = codegen->registerConstant(constant);
4564 move.destTemp = slot.stackSlot();
4565 codegen->bytecodeGenerator->addInstruction(move);
4567 loadInAccumulator();
4568 slot.storeConsumeAccumulator();
4573void Codegen::Reference::tdzCheck(
bool requiresCheck,
bool throwsReferenceError)
const {
4574 if (throwsReferenceError) {
4575 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4576 name + QStringLiteral(
" is not defined"));
4581 Instruction::DeadTemporalZoneCheck check;
4582 check.name = codegen->registerString(name);
4583 codegen->bytecodeGenerator->addInstruction(check);
4586void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot,
bool requiresCheck,
bool throwsReferenceError)
const {
4589 Instruction::LoadReg load;
4591 codegen->bytecodeGenerator->addInstruction(load);
4592 tdzCheck(
true, throwsReferenceError);
4595Codegen::Reference Codegen::Reference::storeRetainAccumulator()
const
4597 if (storeWipesAccumulator()) {
4599 auto tmp = Reference::fromStackSlot(codegen);
4600 tmp.storeAccumulator();
4610bool Codegen::Reference::storeWipesAccumulator()
const
4629void Codegen::Reference::storeAccumulator()
const
4631 if (throwsReferenceError) {
4632 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4633 name + QStringLiteral(
" is not defined"));
4637 if (isReferenceToConst) {
4639 codegen->generateThrowException(QStringLiteral(
"TypeError"));
4645 Q_UNREACHABLE_RETURN();
4647 Instruction::StoreSuperProperty store;
4648 store.property = property.stackSlot();
4649 codegen->bytecodeGenerator->addInstruction(store);
4652 Instruction::StoreReg store;
4653 store.reg = theStackSlot;
4654 codegen->bytecodeGenerator->addInstruction(store);
4659 Instruction::StoreLocal store;
4660 store.index = index;
4661 codegen->bytecodeGenerator->addInstruction(store);
4663 Instruction::StoreScopedLocal store;
4664 store.index = index;
4665 store.scope = scope;
4666 codegen->bytecodeGenerator->addInstruction(store);
4671 Context *c = codegen->currentContext();
4673 Instruction::StoreNameStrict store;
4674 store.name = nameAsIndex();
4675 codegen->bytecodeGenerator->addInstruction(store);
4677 Instruction::StoreNameSloppy store;
4678 store.name = nameAsIndex();
4679 codegen->bytecodeGenerator->addInstruction(store);
4683 if (codegen->useFastLookups) {
4684 Instruction::SetLookup store;
4685 store.base = propertyBase.stackSlot();
4686 store.index = codegen->registerSetterLookup(propertyNameIndex);
4687 codegen->bytecodeGenerator->addInstruction(store);
4689 Instruction::StoreProperty store;
4690 store.base = propertyBase.stackSlot();
4691 store.name = propertyNameIndex;
4692 codegen->bytecodeGenerator->addInstruction(store);
4696 Instruction::StoreElement store;
4697 store.base = elementBase;
4698 store.index = elementSubscript.stackSlot();
4699 codegen->bytecodeGenerator->addInstruction(store);
4711void Codegen::Reference::loadInAccumulator()
const
4717 Q_UNREACHABLE_RETURN();
4719 tdzCheckStackSlot(property, subscriptRequiresTDZCheck,
false);
4720 Instruction::LoadSuperProperty load;
4721 load.property = property.stackSlot();
4722 codegen->bytecodeGenerator->addInstruction(load);
4726QT_WARNING_DISABLE_GCC(
"-Wmaybe-uninitialized")
4727 if (constant == Encode::null()) {
4728 Instruction::LoadNull load;
4729 codegen->bytecodeGenerator->addInstruction(load);
4730 }
else if (constant == Encode(
true)) {
4731 Instruction::LoadTrue load;
4732 codegen->bytecodeGenerator->addInstruction(load);
4733 }
else if (constant == Encode(
false)) {
4734 Instruction::LoadFalse load;
4735 codegen->bytecodeGenerator->addInstruction(load);
4736 }
else if (constant == Encode::undefined()) {
4737 Instruction::LoadUndefined load;
4738 codegen->bytecodeGenerator->addInstruction(load);
4740 StaticValue p = StaticValue::fromReturnedValue(constant);
4742 double d = p.asDouble();
4743 int i = QJSNumberCoercion::toInteger(d);
4744 if (d == i && (d != 0 || !std::signbit(d))) {
4746 Instruction::LoadZero load;
4747 codegen->bytecodeGenerator->addInstruction(load);
4750 Instruction::LoadInt load;
4751 load.value = StaticValue::fromReturnedValue(constant).toInt32();
4752 codegen->bytecodeGenerator->addInstruction(load);
4756 Instruction::LoadConst load;
4757 load.index = codegen->registerConstant(constant);
4758 codegen->bytecodeGenerator->addInstruction(load);
4763 Instruction::LoadReg load;
4764 load.reg = stackSlot();
4765 codegen->bytecodeGenerator->addInstruction(load);
4766 tdzCheck(requiresTDZCheck, throwsReferenceError);
4770 Instruction::LoadLocal load;
4772 codegen->bytecodeGenerator->addInstruction(load);
4774 Instruction::LoadScopedLocal load;
4777 codegen->bytecodeGenerator->addInstruction(load);
4779 tdzCheck(requiresTDZCheck, throwsReferenceError);
4786 if (name == QStringLiteral(
"undefined")) {
4787 Reference::fromConst(codegen, Encode::undefined()).loadInAccumulator();
4789 }
else if (name == QStringLiteral(
"Infinity")) {
4790 Reference::fromConst(codegen, Encode(qInf())).loadInAccumulator();
4792 }
else if (name == QStringLiteral(
"Nan")) {
4793 Reference::fromConst(codegen, Encode(qQNaN())).loadInAccumulator();
4798 if (sourceLocation.isValid())
4799 codegen->bytecodeGenerator->setLocation(sourceLocation);
4803 Instruction::LoadQmlContextPropertyLookup load;
4804 load.index = codegen->registerQmlContextPropertyGetterLookup(
4805 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4806 codegen->bytecodeGenerator->addInstruction(load);
4808 Instruction::LoadGlobalLookup load;
4809 load.index = codegen->registerGlobalGetterLookup(
4810 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4811 codegen->bytecodeGenerator->addInstruction(load);
4814 Instruction::LoadName load;
4815 load.name = nameAsIndex();
4816 codegen->bytecodeGenerator->addInstruction(load);
4820 propertyBase.loadInAccumulator();
4821 tdzCheck(requiresTDZCheck, throwsReferenceError);
4823 if (sourceLocation.isValid())
4824 codegen->bytecodeGenerator->setLocation(sourceLocation);
4826 if (codegen->useFastLookups) {
4827 if (optionalChainJumpsToPatch && isOptional) {
4828 auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
4829 codegen->registerGetterLookup(
4830 propertyNameIndex, JSUnitGenerator::LookupForStorage));
4831 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4833 Instruction::GetLookup load;
4834 load.index = codegen->registerGetterLookup(
4835 propertyNameIndex, JSUnitGenerator::LookupForStorage);
4836 codegen->bytecodeGenerator->addInstruction(load);
4839 if (optionalChainJumpsToPatch && isOptional) {
4840 auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
4841 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4843 Instruction::LoadProperty load;
4844 load.name = propertyNameIndex;
4845 codegen->bytecodeGenerator->addInstruction(load);
4850 Instruction::LoadImport load;
4852 codegen->bytecodeGenerator->addInstruction(load);
4853 tdzCheck(requiresTDZCheck, throwsReferenceError);
4856 tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
4857 elementSubscript.loadInAccumulator();
4858 tdzCheck(subscriptRequiresTDZCheck,
false);
4859 Instruction::LoadElement load;
4860 load.base = elementBase;
4861 codegen->bytecodeGenerator->addInstruction(load);
void throwRecursionDepthError() override
VolatileMemoryLocationScanner(Codegen *parent)
Codegen::VolatileMemoryLocations scan(AST::Node *s)
bool visit(ArrayMemberExpression *) override
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static Node * completionStatement(StatementList *list)
static CompletionState completionState(StatementList *list)
static QSOperator::Op baseOp(int op)
static bool endsWithReturn(Module *module, Node *node)
static void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGenerator, const Statement *body, const SourceLocation &fallback)
static constexpr const QLatin1StringView s_globalNames[]