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 if (e->typeAnnotation) {
675 throwSyntaxError(e->firstSourceLocation(),
676 QLatin1String(
"Type annotations on default parameters are not supported."));
679 if (e->initializer) {
680 if (!baseRef.isValid()) {
682 Reference expr = expression(e->initializer);
685 expr.loadInAccumulator();
686 varToStore.storeConsumeAccumulator();
687 }
else if (baseRef == varToStore) {
688 baseRef.loadInAccumulator();
689 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
690 Reference expr = expression(e->initializer);
695 expr.loadInAccumulator();
696 varToStore.storeConsumeAccumulator();
699 baseRef.loadInAccumulator();
700 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
701 Reference expr = expression(e->initializer);
706 expr.loadInAccumulator();
708 varToStore.storeConsumeAccumulator();
710 }
else if (baseRef != varToStore && baseRef.isValid()) {
711 baseRef.loadInAccumulator();
712 varToStore.storeConsumeAccumulator();
714 Pattern *p = e->destructuringPattern();
718 if (!varToStore.isStackSlot())
719 varToStore = varToStore.storeOnStack();
720 if (PatternElementList *l = e->elementList()) {
721 destructureElementList(varToStore, l, isDefinition);
722 }
else if (PatternPropertyList *p = e->propertyList()) {
723 destructurePropertyList(varToStore, p, isDefinition);
724 }
else if (e->bindingTarget) {
726 varToStore.loadInAccumulator();
727 Instruction::ToObject toObject;
728 bytecodeGenerator->addInstruction(toObject);
733Codegen::Reference Codegen::referenceForPropertyName(
const Codegen::Reference &object, AST::PropertyName *name)
735 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
738 Reference computedName = expression(cname->expression);
741 computedName = computedName.storeOnStack();
742 property = Reference::fromSubscript(object, computedName).asLValue();
744 QString propertyName = name->asString();
745 property = Reference::fromMember(object, propertyName);
750void Codegen::destructurePropertyList(
const Codegen::Reference &object, PatternPropertyList *bindingList,
bool isDefinition)
752 RegisterScope scope(
this);
754 object.loadInAccumulator();
755 Instruction::ThrowOnNullOrUndefined t;
756 bytecodeGenerator->addInstruction(t);
758 for (PatternPropertyList *it = bindingList; it; it = it->next) {
759 PatternProperty *p = it->property;
760 RegisterScope scope(
this);
761 Reference property = referenceForPropertyName(object, p->name);
764 initializeAndDestructureBindingElement(p, property, isDefinition);
770void Codegen::destructureElementList(
const Codegen::Reference &array, PatternElementList *bindingList,
bool isDefinition)
772 RegisterScope scope(
this);
774 Reference iterator = Reference::fromStackSlot(
this);
775 QVarLengthArray<Reference> iteratorValues;
778 array.loadInAccumulator();
779 Instruction::GetIterator iteratorObjInstr;
780 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
781 bytecodeGenerator->addInstruction(iteratorObjInstr);
782 iterator.storeConsumeAccumulator();
784 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
785 Reference needsClose = Reference::storeConstOnStack(
this, Encode(
false));
787 for (PatternElementList *p = bindingList; p; p = p->next) {
788 PatternElement *e = p->element;
789 for (Elision *elision = p->elision; elision; elision = elision->next) {
790 iterator.loadInAccumulator();
791 Instruction::IteratorNext next;
792 if (!ignored.isValid())
793 ignored = Reference::fromStackSlot(
this);
794 next.value = ignored.stackSlot();
795 bytecodeGenerator->addJumpInstruction(next).link(done);
801 if (e->type != PatternElement::RestElement) {
802 iterator.loadInAccumulator();
803 Instruction::IteratorNext next;
804 iteratorValues.push_back(Reference::fromStackSlot(
this));
805 next.value = iteratorValues.back().stackSlot();
806 bytecodeGenerator->addJumpInstruction(next).link(done);
814 Reference::fromConst(
this, Encode(
true)).storeOnStack(needsClose.stackSlot());
817 bytecodeGenerator->checkException();
820 ControlFlowUnwindCleanup flow(
this, [&]() {
821 BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
822 needsClose.loadInAccumulator();
823 bytecodeGenerator->jumpFalse().link(skipClose);
824 iterator.loadInAccumulator();
825 Instruction::IteratorClose close;
826 bytecodeGenerator->addInstruction(close);
830 auto it = iteratorValues.constBegin();
831 for (PatternElementList *p = bindingList; p; p = p->next) {
832 PatternElement *e = p->element;
837 if (e->type == PatternElement::RestElement) {
838 Q_ASSERT(it == iteratorValues.constEnd());
841 Reference::fromConst(
this, Encode(
false)).storeOnStack(needsClose.stackSlot());
843 iterator.loadInAccumulator();
844 bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
845 initializeAndDestructureBindingElement(
846 e, Reference::fromAccumulator(
this), isDefinition);
848 Q_ASSERT(it != iteratorValues.constEnd());
849 initializeAndDestructureBindingElement(e, *it++, isDefinition);
858void Codegen::destructurePattern(Pattern *p,
const Reference &rhs)
860 RegisterScope scope(
this);
861 if (
auto *o = AST::cast<ObjectPattern *>(p))
862 destructurePropertyList(rhs, o->properties);
863 else if (
auto *a = AST::cast<ArrayPattern *>(p))
864 destructureElementList(rhs, a->elements);
870bool Codegen::visit(ArgumentList *)
872 Q_UNREACHABLE_RETURN(
false);
875bool Codegen::visit(CaseBlock *)
877 Q_UNREACHABLE_RETURN(
false);
880bool Codegen::visit(CaseClause *)
882 Q_UNREACHABLE_RETURN(
false);
885bool Codegen::visit(CaseClauses *)
887 Q_UNREACHABLE_RETURN(
false);
890bool Codegen::visit(Catch *)
892 Q_UNREACHABLE_RETURN(
false);
895bool Codegen::visit(DefaultClause *)
897 Q_UNREACHABLE_RETURN(
false);
900bool Codegen::visit(Elision *)
902 Q_UNREACHABLE_RETURN(
false);
905bool Codegen::visit(Finally *)
907 Q_UNREACHABLE_RETURN(
false);
910bool Codegen::visit(FormalParameterList *)
912 Q_UNREACHABLE_RETURN(
false);
915bool Codegen::visit(Program *)
917 Q_UNREACHABLE_RETURN(
false);
920bool Codegen::visit(PatternElement *)
922 Q_UNREACHABLE_RETURN(
false);
925bool Codegen::visit(PatternElementList *)
927 Q_UNREACHABLE_RETURN(
false);
930bool Codegen::visit(PatternProperty *)
932 Q_UNREACHABLE_RETURN(
false);
935bool Codegen::visit(PatternPropertyList *)
937 Q_UNREACHABLE_RETURN(
false);
940bool Codegen::visit(ExportDeclaration *ast)
942 if (!ast->exportDefault)
945 TailCallBlocker blockTailCalls(
this);
946 Reference exportedValue;
948 if (
auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
950 visit(
static_cast<FunctionExpression*>(fdecl));
951 exportedValue = popResult();
952 }
else if (
auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
954 visit(
static_cast<ClassExpression*>(classDecl));
955 exportedValue = popResult();
956 }
else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
957 exportedValue = expression(expr);
960 exportedValue.loadInAccumulator();
962 const int defaultExportIndex = _context->locals.indexOf(_context->localNameForDefaultExport);
963 Q_ASSERT(defaultExportIndex != -1);
964 Reference defaultExportSlot = Reference::fromScopedLocal(
this, defaultExportIndex, 0);
965 defaultExportSlot.storeConsumeAccumulator();
970bool Codegen::visit(TypeAnnotation *ast)
972 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Type annotations are not supported (yet)."));
976bool Codegen::visit(StatementList *)
978 Q_UNREACHABLE_RETURN(
false);
981bool Codegen::visit(UiArrayMemberList *)
983 Q_UNREACHABLE_RETURN(
false);
986bool Codegen::visit(UiImport *)
988 Q_UNREACHABLE_RETURN(
false);
991bool Codegen::visit(UiHeaderItemList *)
993 Q_UNREACHABLE_RETURN(
false);
996bool Codegen::visit(UiPragmaValueList *)
998 Q_UNREACHABLE_RETURN(
false);
1001bool Codegen::visit(UiPragma *)
1003 Q_UNREACHABLE_RETURN(
false);
1006bool Codegen::visit(UiObjectInitializer *)
1008 Q_UNREACHABLE_RETURN(
false);
1011bool Codegen::visit(UiObjectMemberList *)
1013 Q_UNREACHABLE_RETURN(
false);
1016bool Codegen::visit(UiParameterList *)
1018 Q_UNREACHABLE_RETURN(
false);
1021bool Codegen::visit(UiProgram *)
1023 Q_UNREACHABLE_RETURN(
false);
1026bool Codegen::visit(UiQualifiedId *)
1028 Q_UNREACHABLE_RETURN(
false);
1031bool Codegen::visit(VariableDeclarationList *)
1033 Q_UNREACHABLE_RETURN(
false);
1036bool Codegen::visit(ClassExpression *ast)
1038 TailCallBlocker blockTailCalls(
this);
1040 Compiler::Class jsClass;
1041 jsClass.nameIndex = registerString(ast->name.toString());
1043 ClassElementList *constructor =
nullptr;
1044 int nComputedNames = 0;
1045 int nStaticComputedNames = 0;
1047 RegisterScope scope(
this);
1048 ControlFlowBlock controlFlow(
this, ast);
1050 for (
auto *member = ast->elements; member; member = member->next) {
1051 PatternProperty *p = member->property;
1052 FunctionExpression *f = p->initializer->asFunctionDefinition();
1054 AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
1057 if (member->isStatic)
1058 ++nStaticComputedNames;
1060 QString name = p->name->asString();
1061 uint nameIndex = cname ? UINT_MAX : registerString(name);
1062 Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
1063 if (p->type == PatternProperty::Getter)
1064 type = Compiler::Class::Method::Getter;
1065 else if (p->type == PatternProperty::Setter)
1066 type = Compiler::Class::Method::Setter;
1067 Compiler::Class::Method m{ nameIndex, type,
static_cast<uint>(defineFunction(name, f, f->formals, f->body)) };
1069 if (member->isStatic) {
1070 if (name == QStringLiteral(
"prototype")) {
1071 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a static method named 'prototype'."));
1074 jsClass.staticMethods << m;
1076 if (name == QStringLiteral(
"constructor")) {
1078 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a multiple constructors in a class."));
1081 if (m.type != Compiler::Class::Method::Regular) {
1082 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a getter or setter named 'constructor'."));
1085 constructor = member;
1086 jsClass.constructorIndex = m.functionIndex;
1090 jsClass.methods << m;
1094 int classIndex = _module->classes.size();
1095 _module->classes.append(jsClass);
1097 Reference heritage = Reference::fromStackSlot(
this);
1098 if (ast->heritage) {
1099 bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
1100 Reference r = expression(ast->heritage);
1103 r.storeOnStack(heritage.stackSlot());
1105 Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1106 heritage.storeConsumeAccumulator();
1109 int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
1110 int currentStaticName = computedNames;
1111 int currentNonStaticName = computedNames + nStaticComputedNames;
1113 for (
auto *member = ast->elements; member; member = member->next) {
1114 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
1117 RegisterScope scope(
this);
1118 bytecodeGenerator->setLocation(cname->firstSourceLocation());
1119 Reference computedName = expression(cname->expression);
1122 computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
1125 Instruction::CreateClass createClass;
1126 createClass.classIndex = classIndex;
1127 createClass.heritage = heritage.stackSlot();
1128 createClass.computedNames = computedNames;
1130 bytecodeGenerator->addInstruction(createClass);
1132 if (!ast->name.isEmpty()) {
1133 Reference ctor = referenceForName(ast->name.toString(),
true);
1134 ctor.isReferenceToConst =
false;
1135 (
void) ctor.storeRetainAccumulator();
1138 setExprResult(Reference::fromAccumulator(
this));
1142bool Codegen::visit(ClassDeclaration *ast)
1144 TailCallBlocker blockTailCalls(
this);
1145 Reference outerVar = referenceForName(ast->name.toString(),
true);
1146 visit(
static_cast<ClassExpression *>(ast));
1147 (
void) outerVar.storeRetainAccumulator();
1151bool Codegen::visit(CommaExpression *ast)
1156 TailCallBlocker blockTailCalls(
this);
1157 statement(ast->left);
1158 blockTailCalls.unblock();
1159 clearExprResultName();
1164bool Codegen::visit(ArrayPattern *ast)
1169 TailCallBlocker blockTailCalls(
this);
1171 PatternElementList *it = ast->elements;
1175 RegisterScope scope(
this);
1178 auto push = [
this, &argc, &args](AST::ExpressionNode *arg) {
1179 int temp = bytecodeGenerator->newRegister();
1183 auto c = Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue());
1184 (
void) c.storeOnStack(temp);
1186 RegisterScope scope(
this);
1187 Reference r = expression(arg);
1190 (
void) r.storeOnStack(temp);
1195 for (; it; it = it->next) {
1196 PatternElement *e = it->element;
1197 if (e && e->type == PatternElement::SpreadElement)
1199 for (Elision *elision = it->elision; elision; elision = elision->next)
1205 push(e->initializer);
1211 Q_ASSERT(argc == 0);
1215 Instruction::DefineArray call;
1217 call.args = Moth::StackSlot::createRegister(args);
1218 bytecodeGenerator->addInstruction(call);
1222 setExprResult(Reference::fromAccumulator(
this));
1225 Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
1227 RegisterScope scope(
this);
1228 Reference array = Reference::fromStackSlot(
this);
1229 array.storeConsumeAccumulator();
1230 Reference index = Reference::storeConstOnStack(
this, Encode(argc));
1232 auto pushAccumulator = [&]() {
1233 Reference slot = Reference::fromSubscript(array, index);
1234 slot.storeConsumeAccumulator();
1236 index.loadInAccumulator();
1237 Instruction::Increment inc = {};
1238 bytecodeGenerator->addInstruction(inc);
1239 index.storeConsumeAccumulator();
1243 for (Elision *elision = it->elision; elision; elision = elision->next) {
1244 Reference::fromConst(
1245 this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1255 if (it->element->type == PatternElement::SpreadElement) {
1256 RegisterScope scope(
this);
1258 Reference iterator = Reference::fromStackSlot(
this);
1259 Reference lhsValue = Reference::fromStackSlot(
this);
1264 RegisterScope innerScope(
this);
1265 Reference expr = expression(it->element->initializer);
1269 expr.loadInAccumulator();
1270 Instruction::GetIterator iteratorObjInstr;
1271 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
1272 bytecodeGenerator->addInstruction(iteratorObjInstr);
1273 iterator.storeConsumeAccumulator();
1276 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
1277 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
1278 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
1281 auto cleanup = [
this, iterator, done]() {
1282 iterator.loadInAccumulator();
1283 Instruction::IteratorClose close;
1284 bytecodeGenerator->addInstruction(close);
1287 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
1290 bytecodeGenerator->addLoopStart(in);
1291 iterator.loadInAccumulator();
1292 Instruction::IteratorNext next;
1293 next.value = lhsValue.stackSlot();
1294 bytecodeGenerator->addJumpInstruction(next).link(done);
1296 lhsValue.loadInAccumulator();
1299 bytecodeGenerator->checkException();
1300 bytecodeGenerator->jump().link(in);
1304 RegisterScope innerScope(
this);
1305 Reference expr = expression(it->element->initializer);
1309 expr.loadInAccumulator();
1316 array.loadInAccumulator();
1317 setExprResult(Reference::fromAccumulator(
this));
1322bool Codegen::visit(ArrayMemberExpression *ast)
1327 const bool isTailOfChain = traverseOptionalChain(ast);
1329 TailCallBlocker blockTailCalls(
this);
1330 Reference base = expression(ast->base);
1332 auto writeSkip = [&]() {
1333 base.loadInAccumulator();
1334 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
1335 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
1336 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
1341 if (base.isSuper()) {
1342 Reference index = expression(ast->expression).storeOnStack();
1343 optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
1346 base = base.storeOnStack();
1349 if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
1350 QString s = str->value.toString();
1351 uint arrayIndex = stringToArrayIndex(s);
1352 if (arrayIndex == UINT_MAX) {
1353 auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
1355 &m_optionalChainsStates.top().jumpsToPatch);
1357 optionalChainFinalizer(ref, isTailOfChain);
1361 if (ast->isOptional)
1364 Reference index = Reference::fromConst(
this, QV4::Encode(arrayIndex));
1365 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1370 if (ast->isOptional)
1373 Reference index = expression(ast->expression);
1378 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1384 switch ((QSOperator::Op) op) {
1385 case QSOperator::InplaceAnd:
return QSOperator::BitAnd;
1386 case QSOperator::InplaceSub:
return QSOperator::Sub;
1387 case QSOperator::InplaceDiv:
return QSOperator::Div;
1388 case QSOperator::InplaceAdd:
return QSOperator::Add;
1389 case QSOperator::InplaceLeftShift:
return QSOperator::LShift;
1390 case QSOperator::InplaceMod:
return QSOperator::Mod;
1391 case QSOperator::InplaceExp:
return QSOperator::Exp;
1392 case QSOperator::InplaceMul:
return QSOperator::Mul;
1393 case QSOperator::InplaceOr:
return QSOperator::BitOr;
1394 case QSOperator::InplaceRightShift:
return QSOperator::RShift;
1395 case QSOperator::InplaceURightShift:
return QSOperator::URShift;
1396 case QSOperator::InplaceXor:
return QSOperator::BitXor;
1397 default:
return QSOperator::Invalid;
1401bool Codegen::visit(BinaryExpression *ast)
1406 TailCallBlocker blockTailCalls(
this);
1408 if (ast->op == QSOperator::And) {
1409 if (exprAccept(cx)) {
1410 auto iftrue = bytecodeGenerator->newLabel();
1411 condition(ast->left, &iftrue, currentExpr().iffalse(),
true);
1413 blockTailCalls.unblock();
1414 const Result &expr = currentExpr();
1415 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1417 auto iftrue = bytecodeGenerator->newLabel();
1418 auto endif = bytecodeGenerator->newLabel();
1420 Reference left = expression(ast->left);
1423 left.loadInAccumulator();
1425 bytecodeGenerator->setLocation(ast->operatorToken);
1426 bytecodeGenerator->jumpFalse().link(endif);
1429 blockTailCalls.unblock();
1430 Reference right = expression(ast->right);
1433 right.loadInAccumulator();
1437 setExprResult(Reference::fromAccumulator(
this));
1440 }
else if (ast->op == QSOperator::Or) {
1441 if (exprAccept(cx)) {
1442 auto iffalse = bytecodeGenerator->newLabel();
1443 condition(ast->left, currentExpr().iftrue(), &iffalse,
false);
1445 const Result &expr = currentExpr();
1446 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1448 auto iffalse = bytecodeGenerator->newLabel();
1449 auto endif = bytecodeGenerator->newLabel();
1451 Reference left = expression(ast->left);
1454 left.loadInAccumulator();
1456 bytecodeGenerator->setLocation(ast->operatorToken);
1457 bytecodeGenerator->jumpTrue().link(endif);
1460 blockTailCalls.unblock();
1461 Reference right = expression(ast->right);
1464 right.loadInAccumulator();
1468 setExprResult(Reference::fromAccumulator(
this));
1471 }
else if (ast->op == QSOperator::Coalesce) {
1473 Reference left = expression(ast->left);
1477 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
1479 Instruction::CmpEqNull cmp;
1481 left = left.storeOnStack();
1482 left.loadInAccumulator();
1483 bytecodeGenerator->addInstruction(cmp);
1485 bytecodeGenerator->jumpTrue().link(iftrue);
1487 blockTailCalls.unblock();
1489 left.loadInAccumulator();
1490 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
1493 Reference right = expression(ast->right);
1494 right.loadInAccumulator();
1496 setExprResult(Reference::fromAccumulator(
this));
1499 }
else if (ast->op == QSOperator::Assign) {
1500 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1501 if (AST::Pattern *p = ast->left->patternCast()) {
1502 RegisterScope scope(
this);
1503 Reference right = expression(ast->right);
1506 right = right.storeOnStack();
1507 destructurePattern(p, right);
1508 if (!exprAccept(nx)) {
1509 right.loadInAccumulator();
1510 setExprResult(Reference::fromAccumulator(
this));
1514 Reference left = expression(ast->left);
1518 if (!left.isLValue()) {
1519 throwReferenceError(ast->operatorToken, QStringLiteral(
"left-hand side of assignment operator is not an lvalue"));
1522 left = left.asLValue();
1523 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1525 blockTailCalls.unblock();
1526 Reference r = expression(ast->right);
1529 r.loadInAccumulator();
1531 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1533 setExprResult(left.storeConsumeAccumulator());
1535 setExprResult(left.storeRetainAccumulator());
1539 Reference left = expression(ast->left);
1544 case QSOperator::Or:
1545 case QSOperator::And:
1546 case QSOperator::Assign:
1550 case QSOperator::InplaceAnd:
1551 case QSOperator::InplaceSub:
1552 case QSOperator::InplaceDiv:
1553 case QSOperator::InplaceAdd:
1554 case QSOperator::InplaceLeftShift:
1555 case QSOperator::InplaceMod:
1556 case QSOperator::InplaceExp:
1557 case QSOperator::InplaceMul:
1558 case QSOperator::InplaceOr:
1559 case QSOperator::InplaceRightShift:
1560 case QSOperator::InplaceURightShift:
1561 case QSOperator::InplaceXor: {
1562 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1565 if (!left.isLValue()) {
1566 throwSyntaxError(ast->operatorToken, QStringLiteral(
"left-hand side of inplace operator is not an lvalue"));
1569 left = left.asLValue();
1571 Reference tempLeft = left.storeOnStack();
1572 Reference right = expression(ast->right);
1577 binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
1578 setExprResult(left.storeRetainAccumulator());
1583 case QSOperator::BitAnd:
1584 case QSOperator::BitOr:
1585 case QSOperator::BitXor:
1586 if (left.isConstant()) {
1587 Reference right = expression(ast->right);
1590 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), right, left));
1594 case QSOperator::In:
1595 case QSOperator::InstanceOf:
1596 case QSOperator::As:
1597 case QSOperator::Equal:
1598 case QSOperator::NotEqual:
1599 case QSOperator::Ge:
1600 case QSOperator::Gt:
1601 case QSOperator::Le:
1602 case QSOperator::Lt:
1603 case QSOperator::StrictEqual:
1604 case QSOperator::StrictNotEqual:
1605 case QSOperator::Add:
1606 case QSOperator::Div:
1607 case QSOperator::Exp:
1608 case QSOperator::Mod:
1609 case QSOperator::Mul:
1610 case QSOperator::Sub:
1611 case QSOperator::LShift:
1612 case QSOperator::RShift:
1613 case QSOperator::URShift: {
1615 if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
1617 right = exprResult();
1619 left = left.storeOnStack();
1620 right = expression(ast->right);
1625 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), left, right));
1634Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
1637 auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
1638 bytecodeGenerator->setLocation(loc);
1640 case QSOperator::Add: {
1641 left = left.storeOnStack();
1642 right.loadInAccumulator();
1643 Instruction::Add add;
1644 add.lhs = left.stackSlot();
1645 bytecodeGenerator->addInstruction(add);
1648 case QSOperator::Sub: {
1649 if (right.isConstant() && right.constant == Encode(
int(1))) {
1650 left.loadInAccumulator();
1651 Instruction::Decrement dec = {};
1652 bytecodeGenerator->addInstruction(dec);
1654 left = left.storeOnStack();
1655 right.loadInAccumulator();
1656 Instruction::Sub sub;
1657 sub.lhs = left.stackSlot();
1658 bytecodeGenerator->addInstruction(sub);
1662 case QSOperator::Exp: {
1663 left = left.storeOnStack();
1664 right.loadInAccumulator();
1665 Instruction::Exp exp;
1666 exp.lhs = left.stackSlot();
1667 bytecodeGenerator->addInstruction(exp);
1670 case QSOperator::Mul: {
1671 left = left.storeOnStack();
1672 right.loadInAccumulator();
1673 Instruction::Mul mul;
1674 mul.lhs = left.stackSlot();
1675 bytecodeGenerator->addInstruction(mul);
1678 case QSOperator::Div: {
1679 left = left.storeOnStack();
1680 right.loadInAccumulator();
1681 Instruction::Div div;
1682 div.lhs = left.stackSlot();
1683 bytecodeGenerator->addInstruction(div);
1686 case QSOperator::Mod: {
1687 left = left.storeOnStack();
1688 right.loadInAccumulator();
1689 Instruction::Mod mod;
1690 mod.lhs = left.stackSlot();
1691 bytecodeGenerator->addInstruction(mod);
1694 case QSOperator::BitAnd:
1695 if (right.isConstant()) {
1696 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1697 if (left.isConstant()) {
1698 int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
1699 return Reference::fromConst(
this, Encode(result));
1701 left.loadInAccumulator();
1702 Instruction::BitAndConst bitAnd;
1703 bitAnd.rhs = rightAsInt;
1704 bytecodeGenerator->addInstruction(bitAnd);
1706 right.loadInAccumulator();
1707 Instruction::BitAnd bitAnd;
1708 bitAnd.lhs = left.stackSlot();
1709 bytecodeGenerator->addInstruction(bitAnd);
1712 case QSOperator::BitOr:
1713 if (right.isConstant()) {
1714 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1715 if (left.isConstant()) {
1716 int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
1717 return Reference::fromConst(
this, Encode(result));
1719 left.loadInAccumulator();
1720 Instruction::BitOrConst bitOr;
1721 bitOr.rhs = rightAsInt;
1722 bytecodeGenerator->addInstruction(bitOr);
1724 right.loadInAccumulator();
1725 Instruction::BitOr bitOr;
1726 bitOr.lhs = left.stackSlot();
1727 bytecodeGenerator->addInstruction(bitOr);
1730 case QSOperator::BitXor:
1731 if (right.isConstant()) {
1732 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1733 if (left.isConstant()) {
1734 int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
1735 return Reference::fromConst(
this, Encode(result));
1737 left.loadInAccumulator();
1738 Instruction::BitXorConst bitXor;
1739 bitXor.rhs = rightAsInt;
1740 bytecodeGenerator->addInstruction(bitXor);
1742 right.loadInAccumulator();
1743 Instruction::BitXor bitXor;
1744 bitXor.lhs = left.stackSlot();
1745 bytecodeGenerator->addInstruction(bitXor);
1748 case QSOperator::URShift:
1749 if (right.isConstant()) {
1750 left.loadInAccumulator();
1751 Instruction::UShrConst ushr;
1752 ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1753 bytecodeGenerator->addInstruction(ushr);
1755 right.loadInAccumulator();
1756 Instruction::UShr ushr;
1757 ushr.lhs = left.stackSlot();
1758 bytecodeGenerator->addInstruction(ushr);
1761 case QSOperator::RShift:
1762 if (right.isConstant()) {
1763 left.loadInAccumulator();
1764 Instruction::ShrConst shr;
1765 shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1766 bytecodeGenerator->addInstruction(shr);
1768 right.loadInAccumulator();
1769 Instruction::Shr shr;
1770 shr.lhs = left.stackSlot();
1771 bytecodeGenerator->addInstruction(shr);
1774 case QSOperator::LShift:
1775 if (right.isConstant()) {
1776 left.loadInAccumulator();
1777 Instruction::ShlConst shl;
1778 shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1779 bytecodeGenerator->addInstruction(shl);
1781 right.loadInAccumulator();
1782 Instruction::Shl shl;
1783 shl.lhs = left.stackSlot();
1784 bytecodeGenerator->addInstruction(shl);
1787 case QSOperator::InstanceOf: {
1788 Instruction::CmpInstanceOf binop;
1789 left = left.storeOnStack();
1790 right.loadInAccumulator();
1791 binop.lhs = left.stackSlot();
1792 bytecodeGenerator->addInstruction(binop);
1795 case QSOperator::As: {
1797 left = left.storeOnStack();
1798 right.loadInAccumulator();
1799 as.lhs = left.stackSlot();
1800 bytecodeGenerator->addInstruction(as);
1803 case QSOperator::In: {
1804 Instruction::CmpIn binop;
1805 left = left.storeOnStack();
1806 right.loadInAccumulator();
1807 binop.lhs = left.stackSlot();
1808 bytecodeGenerator->addInstruction(binop);
1811 case QSOperator::StrictEqual: {
1813 return jumpBinop(oper, left, right);
1815 Instruction::CmpStrictEqual cmp;
1816 left = left.storeOnStack();
1817 right.loadInAccumulator();
1818 cmp.lhs = left.stackSlot();
1819 bytecodeGenerator->addInstruction(cmp);
1822 case QSOperator::StrictNotEqual: {
1824 return jumpBinop(oper, left, right);
1826 Instruction::CmpStrictNotEqual cmp;
1827 left = left.storeOnStack();
1828 right.loadInAccumulator();
1829 cmp.lhs = left.stackSlot();
1830 bytecodeGenerator->addInstruction(cmp);
1833 case QSOperator::Equal: {
1835 return jumpBinop(oper, left, right);
1837 Instruction::CmpEq cmp;
1838 left = left.storeOnStack();
1839 right.loadInAccumulator();
1840 cmp.lhs = left.stackSlot();
1841 bytecodeGenerator->addInstruction(cmp);
1844 case QSOperator::NotEqual: {
1846 return jumpBinop(oper, left, right);
1848 Instruction::CmpNe cmp;
1849 left = left.storeOnStack();
1850 right.loadInAccumulator();
1851 cmp.lhs = left.stackSlot();
1852 bytecodeGenerator->addInstruction(cmp);
1855 case QSOperator::Gt: {
1857 return jumpBinop(oper, left, right);
1859 Instruction::CmpGt cmp;
1860 left = left.storeOnStack();
1861 right.loadInAccumulator();
1862 cmp.lhs = left.stackSlot();
1863 bytecodeGenerator->addInstruction(cmp);
1866 case QSOperator::Ge: {
1868 return jumpBinop(oper, left, right);
1870 Instruction::CmpGe cmp;
1871 left = left.storeOnStack();
1872 right.loadInAccumulator();
1873 cmp.lhs = left.stackSlot();
1874 bytecodeGenerator->addInstruction(cmp);
1877 case QSOperator::Lt: {
1879 return jumpBinop(oper, left, right);
1881 Instruction::CmpLt cmp;
1882 left = left.storeOnStack();
1883 right.loadInAccumulator();
1884 cmp.lhs = left.stackSlot();
1885 bytecodeGenerator->addInstruction(cmp);
1888 case QSOperator::Le:
1890 return jumpBinop(oper, left, right);
1892 Instruction::CmpLe cmp;
1893 left = left.storeOnStack();
1894 right.loadInAccumulator();
1895 cmp.lhs = left.stackSlot();
1896 bytecodeGenerator->addInstruction(cmp);
1902 return Reference::fromAccumulator(
this);
1905Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
1908 if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
1910 if (left.isConstant() && !right.isConstant())
1913 if (right.isConstant()) {
1914 StaticValue c = StaticValue::fromReturnedValue(right.constant);
1915 if (c.isNull() || c.isUndefined()) {
1916 left.loadInAccumulator();
1917 if (oper == QSOperator::Equal) {
1918 Instruction::CmpEqNull cmp;
1919 bytecodeGenerator->addInstruction(cmp);
1922 }
else if (oper == QSOperator::NotEqual) {
1923 Instruction::CmpNeNull cmp;
1924 bytecodeGenerator->addInstruction(cmp);
1928 }
else if (c.isInt32()) {
1929 left.loadInAccumulator();
1930 if (oper == QSOperator::Equal) {
1931 Instruction::CmpEqInt cmp;
1932 cmp.lhs = c.int_32();
1933 bytecodeGenerator->addInstruction(cmp);
1936 }
else if (oper == QSOperator::NotEqual) {
1937 Instruction::CmpNeInt cmp;
1938 cmp.lhs = c.int_32();
1939 bytecodeGenerator->addInstruction(cmp);
1948 left = left.storeOnStack();
1949 right.loadInAccumulator();
1952 case QSOperator::StrictEqual: {
1953 Instruction::CmpStrictEqual cmp;
1954 cmp.lhs = left.stackSlot();
1955 bytecodeGenerator->addInstruction(cmp);
1959 case QSOperator::StrictNotEqual: {
1960 Instruction::CmpStrictNotEqual cmp;
1961 cmp.lhs = left.stackSlot();
1962 bytecodeGenerator->addInstruction(cmp);
1966 case QSOperator::Equal: {
1967 Instruction::CmpEq cmp;
1968 cmp.lhs = left.stackSlot();
1969 bytecodeGenerator->addInstruction(cmp);
1973 case QSOperator::NotEqual: {
1974 Instruction::CmpNe cmp;
1975 cmp.lhs = left.stackSlot();
1976 bytecodeGenerator->addInstruction(cmp);
1980 case QSOperator::Gt: {
1981 Instruction::CmpGt cmp;
1982 cmp.lhs = left.stackSlot();
1983 bytecodeGenerator->addInstruction(cmp);
1987 case QSOperator::Ge: {
1988 Instruction::CmpGe cmp;
1989 cmp.lhs = left.stackSlot();
1990 bytecodeGenerator->addInstruction(cmp);
1994 case QSOperator::Lt: {
1995 Instruction::CmpLt cmp;
1996 cmp.lhs = left.stackSlot();
1997 bytecodeGenerator->addInstruction(cmp);
2001 case QSOperator::Le: {
2002 Instruction::CmpLe cmp;
2003 cmp.lhs = left.stackSlot();
2004 bytecodeGenerator->addInstruction(cmp);
2014Codegen::Reference Codegen::loadSubscriptForCall(
const Codegen::Reference &base)
2018 base.elementSubscript.loadInAccumulator();
2019 Codegen::Instruction::LoadElement load;
2020 load.base = base.elementBase;
2021 bytecodeGenerator->addInstruction(load);
2022 return Reference::fromAccumulator(
this);
2025bool Codegen::visit(CallExpression *ast)
2030 const bool isTailOfChain = traverseOptionalChain(ast);
2032 RegisterScope scope(
this);
2033 TailCallBlocker blockTailCalls(
this);
2035 Reference expr = expression(ast->base);
2036 Reference base = expr;
2040 switch (base.type) {
2041 case Reference::Member:
2042 base = base.asLValue();
2044 case Reference::Subscript:
2045 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2046 base.subscriptLoadedForCall =
true;
2048 case Reference::Name:
2050 case Reference::Super:
2051 handleConstruct(base, ast->arguments);
2053 case Reference::SuperProperty:
2056 base = base.storeOnStack();
2060 if (expr.hasSavedCallBaseSlot) {
2062 base.hasSavedCallBaseSlot =
true;
2063 base.savedCallBaseSlot = expr.savedCallBaseSlot;
2064 base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
2067 int thisObject = bytecodeGenerator->newRegister();
2068 int functionObject = bytecodeGenerator->newRegister();
2070 if (ast->isOptional || m_optionalChainsStates.top().actuallyHasOptionals) {
2071 base.loadInAccumulator();
2072 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2073 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2074 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2077 auto calldata = pushArgs(ast->arguments);
2081 blockTailCalls.unblock();
2082 if (calldata.hasSpread || _tailCallsAreAllowed) {
2083 Reference baseObject = base.baseObject();
2084 if (!baseObject.isStackSlot()) {
2085 baseObject.storeOnStack(thisObject);
2086 baseObject = Reference::fromStackSlot(
this, thisObject);
2089 const int func = [&]() {
2090 if (base.type == Reference::Subscript)
2091 return base.element;
2093 if (!base.isStackSlot()) {
2094 base.storeOnStack(functionObject);
2095 base = Reference::fromStackSlot(
this, functionObject);
2098 return base.stackSlot();
2101 if (calldata.hasSpread) {
2102 Instruction::CallWithSpread call;
2104 call.thisObject = baseObject.stackSlot();
2105 call.argc = calldata.argc;
2106 call.argv = calldata.argv;
2107 bytecodeGenerator->addInstruction(call);
2109 Instruction::TailCall call;
2111 call.thisObject = baseObject.stackSlot();
2112 call.argc = calldata.argc;
2113 call.argv = calldata.argv;
2114 bytecodeGenerator->addInstruction(call);
2117 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2121 handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
2122 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2126void Codegen::endVisit(CallExpression *ast)
2128 m_seenOptionalChainNodes.remove(ast);
2131void Codegen::handleCall(Reference &base, Arguments calldata,
int slotForFunction,
int slotForThisObject,
bool optional)
2133 if (base.sourceLocation.isValid())
2134 bytecodeGenerator->setLocation(base.sourceLocation);
2137 if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
2138 if (useFastLookups) {
2139 Instruction::CallPropertyLookup call;
2140 if (base.hasSavedCallBaseSlot) {
2141 call.base = base.savedCallBaseSlot;
2142 call.lookupIndex = registerGetterLookup(
2143 base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
2145 call.base = base.propertyBase.stackSlot();
2146 call.lookupIndex = registerGetterLookup(
2147 base.propertyNameIndex, JSUnitGenerator::LookupForCall);
2149 call.argc = calldata.argc;
2150 call.argv = calldata.argv;
2151 bytecodeGenerator->addInstruction(call);
2153 Instruction::CallProperty call;
2154 if (base.hasSavedCallBaseSlot) {
2155 call.base = base.savedCallBaseSlot;
2156 call.name = base.savedCallPropertyNameIndex;
2158 call.base = base.propertyBase.stackSlot();
2159 call.name = base.propertyNameIndex;
2161 call.argc = calldata.argc;
2162 call.argv = calldata.argv;
2163 bytecodeGenerator->addInstruction(call);
2165 }
else if (base.type == Reference::Subscript) {
2166 Instruction::CallWithReceiver call;
2167 call.thisObject = base.elementBase.stackSlot();
2168 call.name = base.element;
2169 call.argc = calldata.argc;
2170 call.argv = calldata.argv;
2171 bytecodeGenerator->addInstruction(call);
2172 }
else if (base.type == Reference::Name) {
2173 if (base.name == QStringLiteral(
"eval") && !optional) {
2174 Instruction::CallPossiblyDirectEval call;
2175 call.argc = calldata.argc;
2176 call.argv = calldata.argv;
2177 bytecodeGenerator->addInstruction(call);
2178 }
else if (useFastLookups && base.global) {
2179 if (base.qmlGlobal) {
2180 Instruction::CallQmlContextPropertyLookup call;
2181 call.index = registerQmlContextPropertyGetterLookup(
2182 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2183 call.argc = calldata.argc;
2184 call.argv = calldata.argv;
2185 bytecodeGenerator->addInstruction(call);
2187 Instruction::CallGlobalLookup call;
2188 call.index = registerGlobalGetterLookup(
2189 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2190 call.argc = calldata.argc;
2191 call.argv = calldata.argv;
2192 bytecodeGenerator->addInstruction(call);
2195 Instruction::CallName call;
2196 call.name = base.nameAsIndex();
2197 call.argc = calldata.argc;
2198 call.argv = calldata.argv;
2199 bytecodeGenerator->addInstruction(call);
2201 }
else if (base.type == Reference::SuperProperty) {
2202 Reference receiver = base.baseObject();
2203 if (!base.isStackSlot()) {
2204 base.storeOnStack(slotForFunction);
2205 base = Reference::fromStackSlot(
this, slotForFunction);
2207 if (!receiver.isStackSlot()) {
2208 receiver.storeOnStack(slotForThisObject);
2209 receiver = Reference::fromStackSlot(
this, slotForThisObject);
2211 Instruction::CallWithReceiver call;
2212 call.name = base.stackSlot();
2213 call.thisObject = receiver.stackSlot();
2214 call.argc = calldata.argc;
2215 call.argv = calldata.argv;
2216 bytecodeGenerator->addInstruction(call);
2218 Q_ASSERT(base.isStackSlot());
2219 Instruction::CallValue call;
2220 call.name = base.stackSlot();
2221 call.argc = calldata.argc;
2222 call.argv = calldata.argv;
2223 bytecodeGenerator->addInstruction(call);
2227Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
2229 bool hasSpread =
false;
2231 for (ArgumentList *it = args; it; it = it->next) {
2232 if (it->isSpreadElement) {
2240 return { 0, 0,
false };
2242 int calldata = bytecodeGenerator->newRegisterArray(argc);
2245 for (ArgumentList *it = args; it; it = it->next) {
2246 if (it->isSpreadElement) {
2247 Reference::fromConst(
2249 StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
2252 RegisterScope scope(
this);
2253 Reference e = expression(it->expression);
2256 if (!argc && !it->next && !hasSpread) {
2258 if (e.isStackSlot()) {
2260 return { 1, e.stackSlot(), hasSpread };
2263 (
void) e.storeOnStack(calldata + argc);
2267 return { argc, calldata, hasSpread };
2270Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
2273 for (TemplateLiteral *it = args; it; it = it->next)
2277 return { 0, 0,
false };
2279 int calldata = bytecodeGenerator->newRegisterArray(argc);
2282 for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
2283 RegisterScope scope(
this);
2284 Reference e = expression(it->expression);
2287 (
void) e.storeOnStack(calldata + argc);
2291 return { argc, calldata,
false };
2294bool Codegen::visit(ConditionalExpression *ast)
2299 RegisterScope scope(
this);
2300 TailCallBlocker blockTailCalls(
this);
2302 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
2303 BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
2304 condition(ast->expression, &iftrue, &iffalse,
true);
2306 blockTailCalls.unblock();
2309 Reference ok = expression(ast->ok);
2312 ok.loadInAccumulator();
2313 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
2316 Reference ko = expression(ast->ko);
2321 ko.loadInAccumulator();
2324 setExprResult(Reference::fromAccumulator(
this));
2329bool Codegen::visit(DeleteExpression *ast)
2334 const bool isTailOfChain = traverseOptionalChain(ast);
2336 RegisterScope scope(
this);
2337 TailCallBlocker blockTailCalls(
this);
2338 Reference expr = expression(ast->expression);
2342 const bool chainActuallyHasOptionals = m_optionalChainsStates.top().actuallyHasOptionals;
2343 if (chainActuallyHasOptionals)
2344 Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
2346 switch (expr.type) {
2347 case Reference::SuperProperty:
2350 case Reference::StackSlot:
2351 if (!expr.stackSlotIsLocalOrArgument)
2354 case Reference::ScopedLocal:
2356 if (_context->isStrict) {
2357 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2360 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2362 case Reference::Name: {
2363 if (_context->isStrict) {
2364 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2367 Instruction::DeleteName del;
2368 del.name = expr.nameAsIndex();
2369 bytecodeGenerator->addInstruction(del);
2370 setExprResult(Reference::fromAccumulator(
this));
2373 case Reference::Member: {
2375 expr = expr.asLValue();
2377 if (chainActuallyHasOptionals) {
2378 expr.loadInAccumulator();
2379 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2380 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2381 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2384 Instruction::LoadRuntimeString instr;
2385 instr.stringId = expr.propertyNameIndex;
2386 bytecodeGenerator->addInstruction(instr);
2387 Reference index = Reference::fromStackSlot(
this);
2388 index.storeConsumeAccumulator();
2389 Instruction::DeleteProperty del;
2390 del.base = expr.propertyBase.stackSlot();
2391 del.index = index.stackSlot();
2392 bytecodeGenerator->addInstruction(del);
2393 auto ref = Reference::fromAccumulator(
this);
2395 optionalChainFinalizer(ref, isTailOfChain,
true);
2398 case Reference::Subscript: {
2400 expr = expr.asLValue();
2402 if (chainActuallyHasOptionals) {
2403 expr.loadInAccumulator();
2404 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2405 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2406 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2409 Instruction::DeleteProperty del;
2410 del.base = expr.elementBase;
2411 del.index = expr.elementSubscript.stackSlot();
2412 bytecodeGenerator->addInstruction(del);
2413 auto ref = Reference::fromAccumulator(
this);
2415 optionalChainFinalizer(ref, isTailOfChain,
true);
2422 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
2426void Codegen::endVisit(DeleteExpression *ast) {
2427 m_seenOptionalChainNodes.remove(ast);
2430bool Codegen::visit(FalseLiteral *)
2435 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2439bool Codegen::visit(SuperLiteral *)
2444 setExprResult(Reference::fromSuper(
this));
2448bool Codegen::traverseOptionalChain(Node *node)
2450 if (m_seenOptionalChainNodes.contains(node))
2453 const auto isOptionalChainableNode = [](
const Node *node) {
2454 return node->kind == Node::Kind_FieldMemberExpression ||
2455 node->kind == Node::Kind_CallExpression ||
2456 node->kind == Node::Kind_ArrayMemberExpression ||
2457 node->kind == Node::Kind_DeleteExpression;
2459 m_optionalChainsStates.emplace();
2460 while (isOptionalChainableNode(node)) {
2461 m_seenOptionalChainNodes.insert(node);
2463 switch (node->kind) {
2464 case Node::Kind_FieldMemberExpression: {
2465 auto *fme = AST::cast<FieldMemberExpression *>(node);
2466 m_optionalChainsStates.top().actuallyHasOptionals |= fme->isOptional;
2470 case Node::Kind_CallExpression: {
2471 auto *ce = AST::cast<CallExpression *>(node);
2472 m_optionalChainsStates.top().actuallyHasOptionals |= ce->isOptional;
2476 case Node::Kind_ArrayMemberExpression: {
2477 auto *ame = AST::cast<ArrayMemberExpression *>(node);
2478 m_optionalChainsStates.top().actuallyHasOptionals |= ame->isOptional;
2482 case Node::Kind_DeleteExpression:
2483 node = AST::cast<DeleteExpression *>(node)->expression;
2493void Codegen::optionalChainFinalizer(
const Reference &expressionResult,
bool tailOfChain,
2494 bool isDeleteExpression)
2496 auto &chainState = m_optionalChainsStates.top();
2498 setExprResult(expressionResult);
2500 }
else if (!chainState.actuallyHasOptionals) {
2501 setExprResult(expressionResult);
2502 m_optionalChainsStates.pop();
2506 auto savedBaseSlot = -1;
2507 if (expressionResult.type == Reference::Member)
2508 savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
2509 expressionResult.loadInAccumulator();
2511 std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
2512 if (!isDeleteExpression)
2513 jumpToDone.emplace(bytecodeGenerator->jump());
2515 for (
auto &jump : chainState.jumpsToPatch)
2518 if (isDeleteExpression)
2519 bytecodeGenerator->addInstruction(Instruction::LoadTrue());
2521 bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
2523 if (jumpToDone.has_value())
2524 jumpToDone.value().link();
2526 auto ref = Reference::fromAccumulator(
this);
2527 if (expressionResult.type == Reference::Member) {
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540 ref.hasSavedCallBaseSlot =
true;
2541 ref.savedCallBaseSlot = savedBaseSlot;
2542 ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
2545 m_optionalChainsStates.pop();
2548bool Codegen::visit(FieldMemberExpression *ast)
2553 const bool isTailOfChain = traverseOptionalChain(ast);
2555 TailCallBlocker blockTailCalls(
this);
2557 if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
2558 if (id->name == QLatin1String(
"new")) {
2560 Q_ASSERT(ast->name == QLatin1String(
"target"));
2562 if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
2563 Reference r = referenceForName(QStringLiteral(
"new.target"),
false);
2564 r.isReadonly =
true;
2570 auto ref = Reference::fromStackSlot(
this, CallData::NewTarget);
2571 optionalChainFinalizer(ref, isTailOfChain);
2576 Reference base = expression(ast->base);
2580 if (base.isSuper()) {
2581 Instruction::LoadRuntimeString load;
2582 load.stringId = registerString(ast->name.toString());
2583 bytecodeGenerator->addInstruction(load);
2584 Reference property = Reference::fromAccumulator(
this).storeOnStack();
2586 optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
2590 auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
2591 ast->isOptional, &m_optionalChainsStates.top().jumpsToPatch);
2593 optionalChainFinalizer(ref, isTailOfChain);
2597void Codegen::endVisit(FieldMemberExpression *ast)
2599 m_seenOptionalChainNodes.remove(ast);
2602bool Codegen::visit(TaggedTemplate *ast)
2607 RegisterScope scope(
this);
2608 return handleTaggedTemplate(expression(ast->base), ast);
2611bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
2616 int functionObject = -1, thisObject = -1;
2617 switch (base.type) {
2618 case Reference::Member:
2619 base = base.asLValue();
2621 case Reference::Subscript:
2622 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2623 base.subscriptLoadedForCall =
true;
2625 case Reference::Name:
2627 case Reference::SuperProperty:
2628 thisObject = bytecodeGenerator->newRegister();
2629 functionObject = bytecodeGenerator->newRegister();
2632 base = base.storeOnStack();
2636 createTemplateObject(ast->templateLiteral);
2637 int templateObjectTemp = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
2638 Q_UNUSED(templateObjectTemp);
2639 auto calldata = pushTemplateArgs(ast->templateLiteral);
2643 Q_ASSERT(calldata.argv == templateObjectTemp + 1);
2646 handleCall(base, calldata, functionObject, thisObject);
2647 setExprResult(Reference::fromAccumulator(
this));
2651void Codegen::createTemplateObject(TemplateLiteral *t)
2655 for (TemplateLiteral *it = t; it; it = it->next) {
2656 obj.strings.append(registerString(it->value.toString()));
2657 obj.rawStrings.append(registerString(it->rawValue.toString()));
2660 int index = _module->templateObjects.size();
2661 _module->templateObjects.append(obj);
2663 Instruction::GetTemplateObject getTemplateObject;
2664 getTemplateObject.index = index;
2665 bytecodeGenerator->addInstruction(getTemplateObject);
2668bool Codegen::visit(FunctionExpression *ast)
2673 TailCallBlocker blockTailCalls(
this);
2675 RegisterScope scope(
this);
2677 int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
2680 loadClosure(function);
2681 setExprResult(Reference::fromAccumulator(
this));
2685Codegen::Reference Codegen::referenceForName(
const QString &name,
bool isLhs,
const SourceLocation &accessLocation)
2687 Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
2688 bool throwsReferenceError =
false;
2690 if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
2691 || resolved.type == Context::ResolvedName::Import) {
2692 if (resolved.isArgOrEval && isLhs)
2694 throwSyntaxError(SourceLocation(), QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
2696 if (resolved.declarationLocation.isValid() && accessLocation.isValid()
2697 && resolved.declarationLocation.begin() > accessLocation.end()) {
2698 Q_ASSERT(_interface);
2699 if (resolved.memberType == Context::FunctionDefinition) {
2700 _interface->reportFunctionUsedBeforeDeclaration(
2701 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2703 _interface->reportVarUsedBeforeDeclaration(
2704 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2706 if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
2707 throwsReferenceError =
true;
2710 if (resolved.isInjected && accessLocation.isValid()) {
2711 qCWarning(lcQmlInjectedParameter).nospace().noquote()
2712 << url().toString() <<
":" << accessLocation.startLine
2713 <<
":" << accessLocation.startColumn <<
" Parameter \"" << name
2714 <<
"\" is not declared."
2715 <<
" Injection of parameters into signal handlers is deprecated."
2716 <<
" Use JavaScript functions with formal parameters instead.";
2720 switch (resolved.type) {
2721 case Context::ResolvedName::Local:
2722 r = Reference::fromScopedLocal(
this, resolved.index, resolved.scope);
break;
2723 case Context::ResolvedName::Stack:
2724 r = Reference::fromStackSlot(
this, resolved.index,
true );
break;
2725 case Context::ResolvedName::Import:
2726 r = Reference::fromImport(
this, resolved.index);
break;
2727 default: Q_UNREACHABLE();
2729 if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
2730 r.isVolatile =
true;
2731 r.isArgOrEval = resolved.isArgOrEval;
2732 r.isReferenceToConst = resolved.isConst;
2733 r.requiresTDZCheck = resolved.requiresTDZCheck;
2735 r.sourceLocation = accessLocation;
2736 r.throwsReferenceError = throwsReferenceError;
2740 Reference r = Reference::fromName(
this, name);
2741 r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
2742 r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
2743 r.sourceLocation = accessLocation;
2744 if (!r.global && !r.qmlGlobal
2745 && _context->contextType == ContextType::ScriptImportedByQML
2746 && Codegen::isNameGlobal(name)) {
2756void Codegen::loadClosure(
int closureId)
2758 if (closureId >= 0) {
2759 Instruction::LoadClosure load;
2760 load.value = closureId;
2761 bytecodeGenerator->addInstruction(load);
2763 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
2767bool Codegen::visit(IdentifierExpression *ast)
2772 setExprResult(referenceForName(ast->name.toString(),
false, ast->firstSourceLocation()));
2776bool Codegen::visit(NestedExpression *ast)
2781 accept(ast->expression);
2785void Codegen::handleConstruct(
const Reference &base, ArgumentList *arguments)
2787 Reference constructor;
2788 if (base.isSuper()) {
2789 Instruction::LoadSuperConstructor super;
2790 bytecodeGenerator->addInstruction(super);
2791 constructor = Reference::fromAccumulator(
this).storeOnStack();
2793 constructor = base.storeOnStack();
2796 auto calldata = pushArgs(arguments);
2801 Reference::fromStackSlot(
this, CallData::NewTarget).loadInAccumulator();
2803 constructor.loadInAccumulator();
2805 if (calldata.hasSpread) {
2806 Instruction::ConstructWithSpread create;
2807 create.func = constructor.stackSlot();
2808 create.argc = calldata.argc;
2809 create.argv = calldata.argv;
2810 bytecodeGenerator->addInstruction(create);
2812 Instruction::Construct create;
2813 create.func = constructor.stackSlot();
2814 create.argc = calldata.argc;
2815 create.argv = calldata.argv;
2816 bytecodeGenerator->addInstruction(create);
2820 Reference::fromAccumulator(
this).storeOnStack(CallData::This);
2822 setExprResult(Reference::fromAccumulator(
this));
2825bool Codegen::visit(NewExpression *ast)
2830 RegisterScope scope(
this);
2831 TailCallBlocker blockTailCalls(
this);
2833 Reference base = expression(ast->expression);
2836 if (base.isSuper()) {
2837 throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2841 handleConstruct(base,
nullptr);
2845bool Codegen::visit(NewMemberExpression *ast)
2850 RegisterScope scope(
this);
2851 TailCallBlocker blockTailCalls(
this);
2853 Reference base = expression(ast->base);
2856 if (base.isSuper()) {
2857 throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2861 handleConstruct(base, ast->arguments);
2865bool Codegen::visit(NotExpression *ast)
2870 TailCallBlocker blockTailCalls(
this);
2871 setExprResult(unop(Not, expression(ast->expression)));
2875bool Codegen::visit(NullExpression *)
2881 bytecodeGenerator->jump().link(*currentExpr().iffalse());
2883 setExprResult(Reference::fromConst(
this, Encode::null()));
2888bool Codegen::visit(NumericLiteral *ast)
2893 setExprResult(Reference::fromConst(
this, QV4::Encode::smallestNumber(ast->value)));
2897bool Codegen::visit(ObjectPattern *ast)
2902 TailCallBlocker blockTailCalls(
this);
2904 RegisterScope scope(
this);
2906 QStringList members;
2910 auto push = [
this, &args, &argc](
const Reference &arg) {
2911 int temp = bytecodeGenerator->newRegister();
2914 (
void) arg.storeOnStack(temp);
2918 PatternPropertyList *it = ast->properties;
2919 for (; it; it = it->next) {
2920 PatternProperty *p = it->property;
2921 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2922 if (cname || p->type != PatternProperty::Literal)
2924 QString name = p->name->asString();
2925 uint arrayIndex = stringToArrayIndex(name);
2926 if (arrayIndex != UINT_MAX)
2928 if (members.contains(name))
2930 members.append(name);
2933 RegisterScope innerScope(
this);
2934 Reference value = expression(p->initializer, name);
2937 value.loadInAccumulator();
2939 push(Reference::fromAccumulator(
this));
2942 int classId = jsUnitGenerator->registerJSClass(members);
2945 for (; it; it = it->next) {
2946 PatternProperty *p = it->property;
2947 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2948 ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
2949 if (p->type == PatternProperty::Method)
2950 argType = ObjectLiteralArgument::Method;
2951 else if (p->type == PatternProperty::Getter)
2952 argType = ObjectLiteralArgument::Getter;
2953 else if (p->type == PatternProperty::Setter)
2954 argType = ObjectLiteralArgument::Setter;
2956 Reference::fromConst(
this, Encode(
int(argType))).loadInAccumulator();
2957 push(Reference::fromAccumulator(
this));
2960 RegisterScope innerScope(
this);
2961 Reference name = expression(cname->expression);
2964 name.loadInAccumulator();
2966 QString name = p->name->asString();
2968 uint arrayIndex = QV4::String::toArrayIndex(name);
2969 if (arrayIndex != UINT_MAX) {
2970 Reference::fromConst(
this, Encode(arrayIndex)).loadInAccumulator();
2974 Instruction::LoadRuntimeString instr;
2975 instr.stringId = registerString(name);
2976 bytecodeGenerator->addInstruction(instr);
2979 push(Reference::fromAccumulator(
this));
2981 RegisterScope innerScope(
this);
2982 if (p->type != PatternProperty::Literal) {
2984 FunctionExpression *f = p->initializer->asFunctionDefinition();
2986 int function = defineFunction(f->name.toString(), f, f->formals, f->body);
2989 Reference::fromConst(
this, Encode(function)).loadInAccumulator();
2991 Reference value = expression(p->initializer);
2994 value.loadInAccumulator();
2997 push(Reference::fromAccumulator(
this));
3000 Instruction::DefineObjectLiteral call;
3001 call.internalClassId = classId;
3003 call.args = Moth::StackSlot::createRegister(args);
3004 bytecodeGenerator->addInstruction(call);
3005 setExprResult(Reference::fromAccumulator(
this));
3009bool Codegen::visit(PostDecrementExpression *ast)
3014 Reference expr = expression(ast->base);
3017 if (!expr.isLValue()) {
3018 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3021 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3024 setExprResult(unop(PostDecrement, expr));
3029bool Codegen::visit(PostIncrementExpression *ast)
3034 Reference expr = expression(ast->base);
3037 if (!expr.isLValue()) {
3038 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3041 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3044 setExprResult(unop(PostIncrement, expr));
3048bool Codegen::visit(PreDecrementExpression *ast)
3052 Reference expr = expression(ast->expression);
3055 if (!expr.isLValue()) {
3056 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3060 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3062 setExprResult(unop(PreDecrement, expr));
3066bool Codegen::visit(PreIncrementExpression *ast)
3071 Reference expr = expression(ast->expression);
3074 if (!expr.isLValue()) {
3075 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3079 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3081 setExprResult(unop(PreIncrement, expr));
3085bool Codegen::visit(RegExpLiteral *ast)
3090 auto r = Reference::fromStackSlot(
this);
3091 r.isReadonly =
true;
3094 Instruction::MoveRegExp instr;
3095 instr.regExpId = jsUnitGenerator->registerRegExp(ast);
3096 instr.destReg = r.stackSlot();
3097 bytecodeGenerator->addInstruction(instr);
3101bool Codegen::visit(StringLiteral *ast)
3106 auto r = Reference::fromAccumulator(
this);
3107 r.isReadonly =
true;
3110 Instruction::LoadRuntimeString instr;
3111 instr.stringId = registerString(ast->value.toString());
3112 bytecodeGenerator->addInstruction(instr);
3116bool Codegen::visit(TemplateLiteral *ast)
3121 TailCallBlocker blockTailCalls(
this);
3123 Instruction::LoadRuntimeString instr;
3124 instr.stringId = registerString(ast->value.toString());
3125 bytecodeGenerator->addInstruction(instr);
3127 if (ast->expression) {
3128 RegisterScope scope(
this);
3129 int temp = bytecodeGenerator->newRegister();
3130 Instruction::StoreReg store;
3132 bytecodeGenerator->addInstruction(store);
3134 Reference expr = expression(ast->expression);
3139 int temp2 = bytecodeGenerator->newRegister();
3140 expr.storeOnStack(temp2);
3143 Instruction::Add instr;
3145 bytecodeGenerator->addInstruction(instr);
3147 expr.loadInAccumulator();
3150 Instruction::Add instr;
3152 bytecodeGenerator->addInstruction(instr);
3155 auto r = Reference::fromAccumulator(
this);
3156 r.isReadonly =
true;
3163bool Codegen::visit(ThisExpression *)
3168 for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
3169 if (parentContext->isArrowFunction) {
3170 Reference r = referenceForName(QStringLiteral(
"this"),
false);
3171 r.isReadonly =
true;
3175 if (parentContext->contextType != ContextType::Block)
3179 setExprResult(Reference::fromThis(
this));
3183bool Codegen::visit(TildeExpression *ast)
3188 TailCallBlocker blockTailCalls(
this);
3189 setExprResult(unop(Compl, expression(ast->expression)));
3193bool Codegen::visit(TrueLiteral *)
3198 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
3202bool Codegen::visit(TypeOfExpression *ast)
3207 RegisterScope scope(
this);
3208 TailCallBlocker blockTailCalls(
this);
3210 Reference expr = expression(ast->expression);
3214 if (expr.type == Reference::Name) {
3216 Instruction::TypeofName instr;
3217 instr.name = expr.nameAsIndex();
3218 bytecodeGenerator->addInstruction(instr);
3220 expr.loadInAccumulator();
3221 Instruction::TypeofValue instr;
3222 bytecodeGenerator->addInstruction(instr);
3224 setExprResult(Reference::fromAccumulator(
this));
3229bool Codegen::visit(UnaryMinusExpression *ast)
3234 TailCallBlocker blockTailCalls(
this);
3235 setExprResult(unop(UMinus, expression(ast->expression)));
3239bool Codegen::visit(UnaryPlusExpression *ast)
3244 TailCallBlocker blockTailCalls(
this);
3245 setExprResult(unop(UPlus, expression(ast->expression)));
3249bool Codegen::visit(VoidExpression *ast)
3254 RegisterScope scope(
this);
3255 TailCallBlocker blockTailCalls(
this);
3257 statement(ast->expression);
3258 setExprResult(Reference::fromConst(
this, Encode::undefined()));
3262bool Codegen::visit(FunctionDeclaration * ast)
3268 RegisterScope scope(
this);
3270 if (_functionContext->contextType == ContextType::Binding)
3271 referenceForName(ast->name.toString(),
true).loadInAccumulator();
3276bool Codegen::visit(YieldExpression *ast)
3278 if (inFormalParameterList) {
3279 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"yield is not allowed inside parameter lists"));
3283 auto innerMostCurentFunctionContext = _context;
3284 while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
3285 innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
3287 Q_ASSERT(innerMostCurentFunctionContext);
3289 if (!innerMostCurentFunctionContext->isGenerator) {
3290 throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
3294 RegisterScope scope(
this);
3295 TailCallBlocker blockTailCalls(
this);
3296 Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(
this, Encode::undefined());
3300 Reference acc = Reference::fromAccumulator(
this);
3302 if (ast->isYieldStar) {
3303 Reference iterator = Reference::fromStackSlot(
this);
3304 Reference lhsValue = Reference::fromConst(
this, Encode::undefined()).storeOnStack();
3306 expr.loadInAccumulator();
3307 Instruction::GetIterator getIterator;
3308 getIterator.iterator =
static_cast<
int>(AST::ForEachType::Of);
3309 bytecodeGenerator->addInstruction(getIterator);
3310 iterator.storeConsumeAccumulator();
3311 Instruction::LoadUndefined load;
3312 bytecodeGenerator->addInstruction(load);
3314 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3315 bytecodeGenerator->jump().link(in);
3317 BytecodeGenerator::Label loop = bytecodeGenerator->label();
3319 lhsValue.loadInAccumulator();
3320 Instruction::YieldStar yield;
3321 bytecodeGenerator->addInstruction(yield);
3325 Instruction::IteratorNextForYieldStar next;
3326 next.object = lhsValue.stackSlot();
3327 next.iterator = iterator.stackSlot();
3328 BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
3329 bytecodeGenerator->jumpNotUndefined().link(loop);
3331 lhsValue.loadInAccumulator();
3336 bytecodeGenerator->checkException();
3338 lhsValue.loadInAccumulator();
3343 expr.loadInAccumulator();
3344 Instruction::Yield yield;
3345 bytecodeGenerator->addInstruction(yield);
3346 Instruction::Resume resume;
3347 BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
3358 if (AST::cast<ReturnStatement *>(node))
3360 if (AST::cast<ThrowStatement *>(node))
3362 if (Program *p = AST::cast<Program *>(node))
3363 return endsWithReturn(module, p->statements);
3364 if (StatementList *sl = AST::cast<StatementList *>(node)) {
3367 return endsWithReturn(module, sl->statement);
3369 if (Block *b = AST::cast<Block *>(node)) {
3370 Context *blockContext = module->contextMap.value(node);
3371 if (blockContext->requiresExecutionContext)
3375 return endsWithReturn(module, b->statements);
3377 if (IfStatement *is = AST::cast<IfStatement *>(node))
3378 return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
3382int Codegen::defineFunction(
const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
3383 AST::StatementList *body)
3387 if (_context->functionIndex >= 0)
3389 return leaveContext();
3391 _context->name = name.isEmpty() ? currentExpr().result().name : name;
3392 _module->functions.append(_context);
3393 _context->functionIndex = _module->functions.size() - 1;
3395 Context *savedFunctionContext = _functionContext;
3396 _functionContext = _context;
3397 ControlFlow *savedControlFlow = controlFlow;
3398 controlFlow =
nullptr;
3400 if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
3401 _module->blocks.append(_context);
3402 _context->blockIndex = _module->blocks.size() - 1;
3404 if (_module->debugMode)
3405 _context->argumentsCanEscape =
true;
3413 _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
3414 && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
3416 BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
3417 BytecodeGenerator *savedBytecodeGenerator;
3418 savedBytecodeGenerator = bytecodeGenerator;
3419 bytecodeGenerator = &bytecode;
3420 bytecodeGenerator->setLocation(ast->firstSourceLocation());
3421 BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
3422 _returnLabel =
nullptr;
3424 bool savedFunctionEndsWithReturn = functionEndsWithReturn;
3425 functionEndsWithReturn = endsWithReturn(_module, body);
3428 bytecodeGenerator->newRegisterArray(
3429 sizeof(CallData) /
sizeof(StaticValue) - 1 + _context->arguments.size());
3431 bool _inFormalParameterList =
false;
3432 qSwap(_inFormalParameterList, inFormalParameterList);
3434 int returnAddress = -1;
3435 bool _requiresReturnValue = _context->requiresImplicitReturnValue();
3436 qSwap(requiresReturnValue, _requiresReturnValue);
3437 returnAddress = bytecodeGenerator->newRegister();
3438 qSwap(_returnAddress, returnAddress);
3441 if (!_context->parent && _context->requiresExecutionContext) {
3442 _module->blocks.append(_context);
3443 _context->blockIndex = _module->blocks.size() - 1;
3446 TailCallBlocker maybeBlockTailCalls(
this, _context->canHaveTailCalls());
3448 RegisterScope registerScope(
this);
3449 _context->emitBlockHeader(
this);
3452 QScopedValueRollback<
bool> inFormals(inFormalParameterList,
true);
3453 TailCallBlocker blockTailCalls(
this);
3457 PatternElement *e = formals->element;
3465 Reference arg = referenceForName(e->bindingIdentifier.toString(),
true);
3466 if (e->type == PatternElement::RestElement) {
3467 Q_ASSERT(!formals->next);
3468 Instruction::CreateRestParameter rest;
3469 rest.argIndex = argc;
3470 bytecodeGenerator->addInstruction(rest);
3471 arg.storeConsumeAccumulator();
3473 if (e->bindingTarget || e->initializer) {
3474 initializeAndDestructureBindingElement(e, arg);
3479 formals = formals->next;
3484 if (_context->isGenerator) {
3485 Instruction::Yield yield;
3486 bytecodeGenerator->addInstruction(yield);
3489 statementList(body);
3492 bytecodeGenerator->setLocation(ast->lastSourceLocation());
3493 _context->emitBlockFooter(
this);
3495 if (_returnLabel || !functionEndsWithReturn) {
3497 _returnLabel->link();
3499 if (_returnLabel || requiresReturnValue) {
3500 Instruction::LoadReg load;
3501 load.reg = Moth::StackSlot::createRegister(_returnAddress);
3502 bytecodeGenerator->addInstruction(load);
3504 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
3507 bytecodeGenerator->addInstruction(Instruction::Ret());
3510 Q_ASSERT(_context == _functionContext);
3511 bytecodeGenerator->finalize(_context);
3512 _context->registerCountInFunction = bytecodeGenerator->registerCount();
3513 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
3515 qDebug() <<
"=== Bytecode for" << _context->name <<
"strict mode" << _context->isStrict
3516 <<
"register count" << _context->registerCountInFunction <<
"implicit return" << requiresReturnValue;
3517 qDebug().noquote() << QV4::Moth::dumpBytecode(
3518 _context->code, _context->locals.size(), _context->arguments.size(),
3519 _context->line, _context->lineAndStatementNumberMapping);
3524 qSwap(_returnAddress, returnAddress);
3525 qSwap(requiresReturnValue, _requiresReturnValue);
3526 qSwap(_inFormalParameterList, inFormalParameterList);
3527 bytecodeGenerator = savedBytecodeGenerator;
3528 delete _returnLabel;
3529 _returnLabel = savedReturnLabel;
3530 controlFlow = savedControlFlow;
3531 functionEndsWithReturn = savedFunctionEndsWithReturn;
3532 _functionContext = savedFunctionContext;
3534 return leaveContext();
3537bool Codegen::visit(Block *ast)
3542 RegisterScope scope(
this);
3544 ControlFlowBlock controlFlow(
this, ast);
3545 statementList(ast->statements);
3549bool Codegen::visit(BreakStatement *ast)
3556 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3560 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
3561 if (!target.linkLabel.isValid()) {
3562 if (ast->label.isEmpty())
3563 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3565 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3569 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3574bool Codegen::visit(ContinueStatement *ast)
3580 RegisterScope scope(
this);
3583 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Continue outside of loop"));
3587 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
3588 if (!target.linkLabel.isValid()) {
3589 if (ast->label.isEmpty())
3590 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3592 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"continue outside of loop"));
3596 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3601bool Codegen::visit(DebuggerStatement *)
3607bool Codegen::visit(DoWhileStatement *ast)
3612 RegisterScope scope(
this);
3614 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3615 BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
3616 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3618 ControlFlowLoop flow(
this, &end, &cond);
3622 if (!AST::cast<FalseLiteral *>(ast->expression))
3623 bytecodeGenerator->addLoopStart(body);
3626 statement(ast->statement);
3627 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
3630 if (AST::cast<TrueLiteral *>(ast->expression)) {
3632 bytecodeGenerator->checkException();
3633 bytecodeGenerator->jump().link(body);
3634 }
else if (AST::cast<FalseLiteral *>(ast->expression)) {
3637 TailCallBlocker blockTailCalls(
this);
3638 bytecodeGenerator->checkException();
3639 condition(ast->expression, &body, &end,
false);
3647bool Codegen::visit(EmptyStatement *)
3652bool Codegen::visit(ExpressionStatement *ast)
3657 RegisterScope scope(
this);
3658 TailCallBlocker blockTailCalls(
this);
3660 if (requiresReturnValue) {
3661 Reference e = expression(ast->expression);
3664 (
void) e.storeOnStack(_returnAddress);
3666 statement(ast->expression);
3671bool Codegen::visit(ForEachStatement *ast)
3676 RegisterScope scope(
this);
3677 TailCallBlocker blockTailCalls(
this);
3679 Reference iterator = Reference::fromStackSlot(
this);
3680 Reference lhsValue = Reference::fromStackSlot(
this);
3685 RegisterScope innerScope(
this);
3686 ControlFlowBlock controlFlow(
this, ast);
3687 Reference expr = expression(ast->expression);
3691 expr.loadInAccumulator();
3692 Instruction::GetIterator iteratorObjInstr;
3693 iteratorObjInstr.iterator =
static_cast<
int>(ast->type);
3694 bytecodeGenerator->addInstruction(iteratorObjInstr);
3695 iterator.storeConsumeAccumulator();
3698 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3699 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3700 BytecodeGenerator::Label done;
3703 std::function<
void()> cleanup;
3704 if (ast->type == ForEachType::Of) {
3705 done = bytecodeGenerator->newLabel();
3706 cleanup = [iterator,
this, done]() {
3707 iterator.loadInAccumulator();
3708 Instruction::IteratorClose close;
3709 bytecodeGenerator->addInstruction(close);
3715 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
3716 bytecodeGenerator->addLoopStart(in);
3718 iterator.loadInAccumulator();
3719 Instruction::IteratorNext next;
3720 next.value = lhsValue.stackSlot();
3721 bytecodeGenerator->addJumpInstruction(next).link(done);
3725 RegisterScope innerScope(
this);
3726 ControlFlowBlock controlFlow(
this, ast);
3728 if (ExpressionNode *e = ast->lhs->expressionCast()) {
3729 if (AST::Pattern *p = e->patternCast()) {
3730 RegisterScope scope(
this);
3731 destructurePattern(p, lhsValue);
3733 Reference lhs = expression(e);
3736 if (!lhs.isLValue()) {
3737 throwReferenceError(e->firstSourceLocation(), QStringLiteral(
"Invalid left-hand side expression for 'in' expression"));
3740 lhs = lhs.asLValue();
3741 lhsValue.loadInAccumulator();
3742 lhs.storeConsumeAccumulator();
3744 }
else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
3745 initializeAndDestructureBindingElement(p, lhsValue,
true);
3752 blockTailCalls.unblock();
3753 statement(ast->statement);
3754 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3757 bytecodeGenerator->checkException();
3758 bytecodeGenerator->jump().link(in);
3770bool Codegen::visit(ForStatement *ast)
3775 RegisterScope scope(
this);
3776 TailCallBlocker blockTailCalls(
this);
3778 ControlFlowBlock controlFlow(
this, ast);
3780 if (ast->initialiser)
3781 statement(ast->initialiser);
3782 else if (ast->declarations)
3783 variableDeclarationList(ast->declarations);
3785 BytecodeGenerator::Label cond = bytecodeGenerator->label();
3786 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3787 BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
3788 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3790 ControlFlowLoop flow(
this, &end, &step);
3791 bytecodeGenerator->addLoopStart(cond);
3792 condition(ast->condition, &body, &end,
true);
3795 blockTailCalls.unblock();
3796 statement(ast->statement);
3797 blockTailCalls.reblock();
3798 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3801 if (_context->requiresExecutionContext) {
3802 Instruction::CloneBlockContext clone;
3803 bytecodeGenerator->addInstruction(clone);
3805 statement(ast->expression);
3806 bytecodeGenerator->checkException();
3807 bytecodeGenerator->jump().link(cond);
3814bool Codegen::visit(IfStatement *ast)
3819 RegisterScope scope(
this);
3820 TailCallBlocker blockTailCalls(
this);
3822 BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
3823 BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
3824 condition(ast->expression, &trueLabel, &falseLabel,
true);
3825 blockTailCalls.unblock();
3830 if (endsWithReturn(_module, ast)) {
3834 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
3846bool Codegen::visit(LabelledStatement *ast)
3851 RegisterScope scope(
this);
3854 ControlFlow *l = controlFlow;
3856 if (l->label() == ast->label) {
3857 QString error = QString(QStringLiteral(
"Label '%1' has already been declared")).arg(ast->label.toString());
3858 throwSyntaxError(ast->firstSourceLocation(), error);
3863 _labelledStatement = ast;
3865 if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
3866 AST::cast<AST::WhileStatement *>(ast->statement) ||
3867 AST::cast<AST::DoWhileStatement *>(ast->statement) ||
3868 AST::cast<AST::ForStatement *>(ast->statement) ||
3869 AST::cast<AST::ForEachStatement *>(ast->statement)) {
3870 statement(ast->statement);
3872 BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
3873 ControlFlowLoop flow(
this, &breakLabel);
3874 statement(ast->statement);
3881void Codegen::emitReturn(
const Reference &expr)
3883 ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
3884 if (target.linkLabel.isValid() && target.unwindLevel) {
3885 Q_ASSERT(_returnAddress >= 0);
3886 (
void) expr.storeOnStack(_returnAddress);
3887 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3889 expr.loadInAccumulator();
3890 bytecodeGenerator->addInstruction(Instruction::Ret());
3894bool Codegen::visit(ReturnStatement *ast)
3899 if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
3900 throwSyntaxError(ast->returnToken, QStringLiteral(
"Return statement outside of function"));
3904 if (ast->expression) {
3905 expr = expression(ast->expression);
3909 expr = Reference::fromConst(
this, Encode::undefined());
3917bool Codegen::visit(SwitchStatement *ast)
3922 if (requiresReturnValue)
3923 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
3925 RegisterScope scope(
this);
3926 TailCallBlocker blockTailCalls(
this);
3929 BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
3931 Reference lhs = expression(ast->expression);
3934 lhs = lhs.storeOnStack();
3936 ControlFlowBlock controlFlow(
this, ast->block);
3939 QHash<Node *, BytecodeGenerator::Label> blockMap;
3940 for (CaseClauses *it = ast->block->clauses; it; it = it->next)
3941 blockMap[it->clause] = bytecodeGenerator->newLabel();
3942 if (ast->block->defaultClause)
3943 blockMap[ast->block->defaultClause] = bytecodeGenerator->newLabel();
3944 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next)
3945 blockMap[it->clause] = bytecodeGenerator->newLabel();
3948 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3949 CaseClause *clause = it->clause;
3950 Reference rhs = expression(clause->expression);
3953 rhs.loadInAccumulator();
3954 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3957 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3958 CaseClause *clause = it->clause;
3959 Reference rhs = expression(clause->expression);
3962 rhs.loadInAccumulator();
3963 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3966 if (DefaultClause *defaultClause = ast->block->defaultClause)
3967 bytecodeGenerator->jump().link(blockMap.value(defaultClause));
3969 bytecodeGenerator->jump().link(switchEnd);
3971 ControlFlowLoop flow(
this, &switchEnd);
3973 insideSwitch =
true;
3974 blockTailCalls.unblock();
3975 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3976 CaseClause *clause = it->clause;
3977 blockMap[clause].link();
3979 statementList(clause->statements);
3982 if (ast->block->defaultClause) {
3983 DefaultClause *clause = ast->block->defaultClause;
3984 blockMap[clause].link();
3986 statementList(clause->statements);
3989 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3990 CaseClause *clause = it->clause;
3991 blockMap[clause].link();
3993 statementList(clause->statements);
3995 insideSwitch =
false;
4004bool Codegen::visit(ThrowStatement *ast)
4009 RegisterScope scope(
this);
4010 TailCallBlocker blockTailCalls(
this);
4012 Reference expr = expression(ast->expression);
4016 expr.loadInAccumulator();
4017 Instruction::ThrowException instr;
4018 bytecodeGenerator->addInstruction(instr);
4022void Codegen::handleTryCatch(TryStatement *ast)
4025 RegisterScope scope(
this);
4027 ControlFlowCatch catchFlow(
this, ast->catchExpression);
4028 RegisterScope scope(
this);
4029 TailCallBlocker blockTailCalls(
this);
4030 statement(ast->statement);
4034void Codegen::handleTryFinally(TryStatement *ast)
4036 RegisterScope scope(
this);
4037 const bool hasCatchBlock = ast->catchExpression;
4038 ControlFlowFinally finally(
this, ast->finallyExpression, hasCatchBlock);
4039 TailCallBlocker blockTailCalls(
this);
4041 if (ast->catchExpression) {
4042 handleTryCatch(ast);
4044 RegisterScope scope(
this);
4045 statement(ast->statement);
4049bool Codegen::visit(TryStatement *ast)
4054 RegisterScope scope(
this);
4056 if (ast->finallyExpression && ast->finallyExpression->statement) {
4057 handleTryFinally(ast);
4059 handleTryCatch(ast);
4065bool Codegen::visit(VariableStatement *ast)
4070 variableDeclarationList(ast->declarations);
4074bool Codegen::visit(WhileStatement *ast)
4079 if (AST::cast<FalseLiteral *>(ast->expression))
4082 RegisterScope scope(
this);
4084 BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
4085 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
4086 BytecodeGenerator::Label cond = bytecodeGenerator->label();
4087 ControlFlowLoop flow(
this, &end, &cond);
4088 bytecodeGenerator->addLoopStart(cond);
4090 bytecodeGenerator->checkException();
4092 if (!AST::cast<TrueLiteral *>(ast->expression)) {
4093 TailCallBlocker blockTailCalls(
this);
4094 condition(ast->expression, &start, &end,
true);
4098 statement(ast->statement);
4099 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->whileToken);
4100 bytecodeGenerator->jump().link(cond);
4106bool Codegen::visit(WithStatement *ast)
4111 RegisterScope scope(
this);
4112 TailCallBlocker blockTailCalls(
this);
4114 Reference src = expression(ast->expression);
4117 src = src.storeOnStack();
4118 src.loadInAccumulator();
4122 blockTailCalls.unblock();
4123 ControlFlowWith flow(
this);
4124 statement(ast->statement);
4131bool Codegen::visit(UiArrayBinding *)
4137bool Codegen::visit(UiObjectBinding *)
4143bool Codegen::visit(UiObjectDefinition *)
4149bool Codegen::visit(UiPublicMember *)
4155bool Codegen::visit(UiScriptBinding *)
4161bool Codegen::visit(UiSourceElement *)
4167bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(
const Reference &r,
const SourceLocation& loc)
4169 if (!_context->isStrict)
4171 bool isArgOrEval =
false;
4172 if (r.type == Reference::Name) {
4173 QString str = jsUnitGenerator->stringForIndex(r.nameAsIndex());
4174 if (str == QLatin1String(
"eval") || str == QLatin1String(
"arguments")) {
4177 }
else if (r.type == Reference::ScopedLocal || r.isRegister()) {
4178 isArgOrEval = r.isArgOrEval;
4181 throwSyntaxError(loc, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
4185void Codegen::throwError(ErrorType errorType,
const SourceLocation &loc,
const QString &detail)
4190 _errorType = errorType;
4191 _error.message = detail;
4195void Codegen::throwSyntaxError(
const SourceLocation &loc,
const QString &detail)
4197 throwError(SyntaxError, loc, detail);
4200void Codegen::throwReferenceError(
const SourceLocation &loc,
const QString &detail)
4202 throwError(ReferenceError, loc, detail);
4205QQmlJS::DiagnosticMessage Codegen::error()
const
4210QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
4211 bool generateUnitData)
4213 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
4214 new QV4::CompiledData::CompilationUnit(
4215 generateUnitData ? jsUnitGenerator->generateUnit() :
nullptr),
4216 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
4219QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
4220 bool debugMode,
const QString &url,
const QString &sourceCode,
4221 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
4224 QQmlJS::Lexer lexer(&ee);
4225 lexer.setCode(sourceCode, 1,
false);
4226 QQmlJS::Parser parser(&ee);
4228 const bool parsed = parser.parseModule();
4231 *diagnostics = parser.diagnosticMessages();
4234 return QQmlRefPointer<CompiledData::CompilationUnit>();
4236 QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
4241 diagnostics->clear();
4245 using namespace QV4::Compiler;
4246 Compiler::Module compilerModule(url, url, debugMode);
4247 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4248 compilerModule.sourceTimeStamp = sourceTimeStamp;
4249 JSUnitGenerator jsGenerator(&compilerModule);
4250 Codegen cg(&jsGenerator,
true);
4251 cg.generateFromModule(sourceCode, moduleNode, &compilerModule);
4252 if (cg.hasError()) {
4254 *diagnostics << cg.error();
4255 return QQmlRefPointer<CompiledData::CompilationUnit>();
4258 return cg.generateCompilationUnit();
4261const QV4::CompiledData::Unit *Codegen::generateNativeModuleUnitData(
4262 bool debugMode,
const QString &url,
const Value &value)
4264 using namespace QV4::Compiler;
4265 Compiler::Module compilerModule(url, url, debugMode);
4266 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4267 JSUnitGenerator jsGenerator(&compilerModule);
4268 Codegen cg(&jsGenerator,
true);
4269 cg.generateFromModule(value, &compilerModule);
4270 Q_ASSERT(!cg.hasError());
4271 return jsGenerator.generateUnit();
4276 VolatileMemoryLocations locs;
4291 bool visit(ArrayMemberExpression *)
override
4293 locs.setAllVolatile();
4297 bool visit(FieldMemberExpression *)
override
4299 locs.setAllVolatile();
4303 bool visit(PostIncrementExpression *e)
override
4305 collectIdentifiers(locs.specificLocations, e->base);
4309 bool visit(PostDecrementExpression *e)
override
4311 collectIdentifiers(locs.specificLocations, e->base);
4315 bool visit(PreIncrementExpression *e)
override
4317 collectIdentifiers(locs.specificLocations, e->expression);
4321 bool visit(PreDecrementExpression *e)
override
4323 collectIdentifiers(locs.specificLocations, e->expression);
4327 bool visit(BinaryExpression *e)
override
4330 case QSOperator::InplaceAnd:
4331 case QSOperator::InplaceSub:
4332 case QSOperator::InplaceDiv:
4333 case QSOperator::InplaceAdd:
4334 case QSOperator::InplaceLeftShift:
4335 case QSOperator::InplaceMod:
4336 case QSOperator::InplaceMul:
4337 case QSOperator::InplaceOr:
4338 case QSOperator::InplaceRightShift:
4339 case QSOperator::InplaceURightShift:
4340 case QSOperator::InplaceXor:
4341 collectIdentifiers(locs.specificLocations, e);
4355 void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
4356 class Collector:
public QQmlJS::AST::Visitor {
4358 QList<QStringView> &ids;
4359 VolatileMemoryLocationScanner *parent;
4362 Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
4363 QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
4366 bool visit(IdentifierExpression *ie) final {
4367 ids.append(ie->name);
4371 void throwRecursionDepthError() final
4373 parent->throwRecursionDepthError();
4376 Collector collector(ids,
this);
4377 node->accept(&collector);
4381Codegen::VolatileMemoryLocations
Codegen::scanVolatileMemoryLocations(AST::Node *ast)
4383 VolatileMemoryLocationScanner scanner(
this);
4384 return scanner.scan(ast);
4389 return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
4392bool Codegen::RValue::operator==(
const RValue &other)
const
4396 return other.isAccumulator();
4398 return other.isStackSlot() && theStackSlot == other.theStackSlot;
4400 return other.isConst() && constant == other.constant;
4406Codegen::RValue Codegen::RValue::storeOnStack()
const
4410 return RValue::fromStackSlot(codegen, Reference::fromAccumulator(codegen).storeOnStack().stackSlot());
4414 return RValue::fromStackSlot(codegen, Reference::storeConstOnStack(codegen, constant).stackSlot());
4420void Codegen::RValue::loadInAccumulator()
const
4427 return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
4429 return Reference::fromConst(codegen, constant).loadInAccumulator();
4436bool Codegen::Reference::operator==(
const Codegen::Reference &other)
const
4438 if (type != other.type)
4447 return property == other.property;
4449 return theStackSlot == other.theStackSlot;
4451 return index == other.index && scope == other.scope;
4453 return nameAsIndex() == other.nameAsIndex();
4455 return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
4457 return elementBase == other.elementBase && other.subscriptLoadedForCall
4458 ? (subscriptLoadedForCall && element == other.element)
4459 : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
4461 return index == other.index;
4463 return constant == other.constant;
4468Codegen::RValue Codegen::Reference::asRValue()
const
4474 return RValue::fromAccumulator(codegen);
4476 return RValue::fromStackSlot(codegen, stackSlot());
4478 return RValue::fromConst(codegen, constant);
4480 loadInAccumulator();
4481 return RValue::fromAccumulator(codegen);
4485Codegen::Reference Codegen::Reference::asLValue()
const
4492 codegen->throwSyntaxError(SourceLocation(), QStringLiteral(
"Super lvalues not implemented."));
4495 if (!propertyBase.isStackSlot()) {
4496 Reference r = *
this;
4497 r.propertyBase = propertyBase.storeOnStack();
4502 if (!elementSubscript.isStackSlot()) {
4503 Reference r = *
this;
4504 r.elementSubscript = elementSubscript.storeOnStack();
4513Codegen::Reference Codegen::Reference::storeConsumeAccumulator()
const
4519Codegen::Reference Codegen::Reference::baseObject()
const
4521 if (type == Reference::Member) {
4522 RValue rval = propertyBase;
4523 if (!rval.isValid())
4524 return Reference::fromConst(codegen, Encode::undefined());
4525 if (rval.isAccumulator())
4526 return Reference::fromAccumulator(codegen);
4527 if (rval.isStackSlot())
4528 return Reference::fromStackSlot(codegen, rval.stackSlot());
4530 return Reference::fromConst(codegen, rval.constantValue());
4532 }
else if (type == Reference::Subscript) {
4533 return Reference::fromStackSlot(codegen, elementBase.stackSlot());
4534 }
else if (type == Reference::SuperProperty) {
4535 return Reference::fromStackSlot(codegen, CallData::This);
4537 return Reference::fromConst(codegen, Encode::undefined());
4541Codegen::Reference Codegen::Reference::storeOnStack()
const
4542{
return doStoreOnStack(-1); }
4544void Codegen::Reference::storeOnStack(
int slotIndex)
const
4545{ doStoreOnStack(slotIndex); }
4547Codegen::Reference Codegen::Reference::doStoreOnStack(
int slotIndex)
const
4549 Q_ASSERT(isValid());
4551 if (isStackSlot() && slotIndex == -1 && !(stackSlotIsLocalOrArgument && isVolatile) && !requiresTDZCheck)
4554 if (isStackSlot() && !requiresTDZCheck) {
4555 Reference dest = Reference::fromStackSlot(codegen, slotIndex);
4556 Instruction::MoveReg move;
4557 move.srcReg = stackSlot();
4558 move.destReg = dest.stackSlot();
4559 codegen->bytecodeGenerator->addInstruction(move);
4563 Reference slot = Reference::fromStackSlot(codegen, slotIndex);
4565 Instruction::MoveConst move;
4566 move.constIndex = codegen->registerConstant(constant);
4567 move.destTemp = slot.stackSlot();
4568 codegen->bytecodeGenerator->addInstruction(move);
4570 loadInAccumulator();
4571 slot.storeConsumeAccumulator();
4576void Codegen::Reference::tdzCheck(
bool requiresCheck,
bool throwsReferenceError)
const {
4577 if (throwsReferenceError) {
4578 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4579 name + QStringLiteral(
" is not defined"));
4584 Instruction::DeadTemporalZoneCheck check;
4585 check.name = codegen->registerString(name);
4586 codegen->bytecodeGenerator->addInstruction(check);
4589void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot,
bool requiresCheck,
bool throwsReferenceError)
const {
4592 Instruction::LoadReg load;
4594 codegen->bytecodeGenerator->addInstruction(load);
4595 tdzCheck(
true, throwsReferenceError);
4598Codegen::Reference Codegen::Reference::storeRetainAccumulator()
const
4600 if (storeWipesAccumulator()) {
4602 auto tmp = Reference::fromStackSlot(codegen);
4603 tmp.storeAccumulator();
4613bool Codegen::Reference::storeWipesAccumulator()
const
4632void Codegen::Reference::storeAccumulator()
const
4634 if (throwsReferenceError) {
4635 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4636 name + QStringLiteral(
" is not defined"));
4640 if (isReferenceToConst) {
4642 codegen->generateThrowException(QStringLiteral(
"TypeError"));
4648 Q_UNREACHABLE_RETURN();
4650 Instruction::StoreSuperProperty store;
4651 store.property = property.stackSlot();
4652 codegen->bytecodeGenerator->addInstruction(store);
4655 Instruction::StoreReg store;
4656 store.reg = theStackSlot;
4657 codegen->bytecodeGenerator->addInstruction(store);
4662 Instruction::StoreLocal store;
4663 store.index = index;
4664 codegen->bytecodeGenerator->addInstruction(store);
4666 Instruction::StoreScopedLocal store;
4667 store.index = index;
4668 store.scope = scope;
4669 codegen->bytecodeGenerator->addInstruction(store);
4674 Context *c = codegen->currentContext();
4676 Instruction::StoreNameStrict store;
4677 store.name = nameAsIndex();
4678 codegen->bytecodeGenerator->addInstruction(store);
4680 Instruction::StoreNameSloppy store;
4681 store.name = nameAsIndex();
4682 codegen->bytecodeGenerator->addInstruction(store);
4686 if (codegen->useFastLookups) {
4687 Instruction::SetLookup store;
4688 store.base = propertyBase.stackSlot();
4689 store.index = codegen->registerSetterLookup(propertyNameIndex);
4690 codegen->bytecodeGenerator->addInstruction(store);
4692 Instruction::StoreProperty store;
4693 store.base = propertyBase.stackSlot();
4694 store.name = propertyNameIndex;
4695 codegen->bytecodeGenerator->addInstruction(store);
4699 Instruction::StoreElement store;
4700 store.base = elementBase;
4701 store.index = elementSubscript.stackSlot();
4702 codegen->bytecodeGenerator->addInstruction(store);
4714void Codegen::Reference::loadInAccumulator()
const
4720 Q_UNREACHABLE_RETURN();
4722 tdzCheckStackSlot(property, subscriptRequiresTDZCheck,
false);
4723 Instruction::LoadSuperProperty load;
4724 load.property = property.stackSlot();
4725 codegen->bytecodeGenerator->addInstruction(load);
4729QT_WARNING_DISABLE_GCC(
"-Wmaybe-uninitialized")
4730 if (constant == Encode::null()) {
4731 Instruction::LoadNull load;
4732 codegen->bytecodeGenerator->addInstruction(load);
4733 }
else if (constant == Encode(
true)) {
4734 Instruction::LoadTrue load;
4735 codegen->bytecodeGenerator->addInstruction(load);
4736 }
else if (constant == Encode(
false)) {
4737 Instruction::LoadFalse load;
4738 codegen->bytecodeGenerator->addInstruction(load);
4739 }
else if (constant == Encode::undefined()) {
4740 Instruction::LoadUndefined load;
4741 codegen->bytecodeGenerator->addInstruction(load);
4743 StaticValue p = StaticValue::fromReturnedValue(constant);
4745 double d = p.asDouble();
4746 int i = QJSNumberCoercion::toInteger(d);
4747 if (d == i && (d != 0 || !std::signbit(d))) {
4749 Instruction::LoadZero load;
4750 codegen->bytecodeGenerator->addInstruction(load);
4753 Instruction::LoadInt load;
4754 load.value = StaticValue::fromReturnedValue(constant).toInt32();
4755 codegen->bytecodeGenerator->addInstruction(load);
4759 Instruction::LoadConst load;
4760 load.index = codegen->registerConstant(constant);
4761 codegen->bytecodeGenerator->addInstruction(load);
4766 Instruction::LoadReg load;
4767 load.reg = stackSlot();
4768 codegen->bytecodeGenerator->addInstruction(load);
4769 tdzCheck(requiresTDZCheck, throwsReferenceError);
4773 Instruction::LoadLocal load;
4775 codegen->bytecodeGenerator->addInstruction(load);
4777 Instruction::LoadScopedLocal load;
4780 codegen->bytecodeGenerator->addInstruction(load);
4782 tdzCheck(requiresTDZCheck, throwsReferenceError);
4789 if (name == QStringLiteral(
"undefined")) {
4790 Reference::fromConst(codegen, Encode::undefined()).loadInAccumulator();
4792 }
else if (name == QStringLiteral(
"Infinity")) {
4793 Reference::fromConst(codegen, Encode(qInf())).loadInAccumulator();
4795 }
else if (name == QStringLiteral(
"Nan")) {
4796 Reference::fromConst(codegen, Encode(qQNaN())).loadInAccumulator();
4801 if (sourceLocation.isValid())
4802 codegen->bytecodeGenerator->setLocation(sourceLocation);
4806 Instruction::LoadQmlContextPropertyLookup load;
4807 load.index = codegen->registerQmlContextPropertyGetterLookup(
4808 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4809 codegen->bytecodeGenerator->addInstruction(load);
4811 Instruction::LoadGlobalLookup load;
4812 load.index = codegen->registerGlobalGetterLookup(
4813 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4814 codegen->bytecodeGenerator->addInstruction(load);
4817 Instruction::LoadName load;
4818 load.name = nameAsIndex();
4819 codegen->bytecodeGenerator->addInstruction(load);
4823 propertyBase.loadInAccumulator();
4824 tdzCheck(requiresTDZCheck, throwsReferenceError);
4826 if (sourceLocation.isValid())
4827 codegen->bytecodeGenerator->setLocation(sourceLocation);
4829 if (codegen->useFastLookups) {
4830 if (optionalChainJumpsToPatch && isOptional) {
4831 auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
4832 codegen->registerGetterLookup(
4833 propertyNameIndex, JSUnitGenerator::LookupForStorage));
4834 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4836 Instruction::GetLookup load;
4837 load.index = codegen->registerGetterLookup(
4838 propertyNameIndex, JSUnitGenerator::LookupForStorage);
4839 codegen->bytecodeGenerator->addInstruction(load);
4842 if (optionalChainJumpsToPatch && isOptional) {
4843 auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
4844 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4846 Instruction::LoadProperty load;
4847 load.name = propertyNameIndex;
4848 codegen->bytecodeGenerator->addInstruction(load);
4853 Instruction::LoadImport load;
4855 codegen->bytecodeGenerator->addInstruction(load);
4856 tdzCheck(requiresTDZCheck, throwsReferenceError);
4859 tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
4860 elementSubscript.loadInAccumulator();
4861 tdzCheck(subscriptRequiresTDZCheck,
false);
4862 Instruction::LoadElement load;
4863 load.base = elementBase;
4864 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[]