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: std::as_const(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();
402 Instruction::Increment inc = {};
403 bytecodeGenerator->addInstruction(inc);
405 return e.storeConsumeAccumulator();
407 return e.storeRetainAccumulator();
410 if (!exprAccept(nx) || requiresReturnValue) {
411 Reference e = expr.asLValue();
412 e.loadInAccumulator();
413 Instruction::UPlus uplus = {};
414 bytecodeGenerator->addInstruction(uplus);
415 Reference originalValue = Reference::fromStackSlot(
this).storeRetainAccumulator();
416 Instruction::Decrement dec = {};
417 bytecodeGenerator->addInstruction(dec);
418 e.storeConsumeAccumulator();
419 return originalValue;
426 Reference e = expr.asLValue();
427 e.loadInAccumulator();
429 Instruction::Decrement dec = {};
430 bytecodeGenerator->addInstruction(dec);
432 return e.storeConsumeAccumulator();
434 return e.storeRetainAccumulator();
441void Codegen::addCJump()
443 const Result &expression = currentExpr();
444 bytecodeGenerator->addCJumpInstruction(expression.trueBlockFollowsCondition(),
445 expression.iftrue(), expression.iffalse());
448void Codegen::statement(Statement *ast)
450 RegisterScope scope(
this);
452 bytecodeGenerator->incrementStatement();
453 bytecodeGenerator->setLocation(ast->firstSourceLocation());
455 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
456 qSwap(_volatileMemoryLocations, vLocs);
458 qSwap(_volatileMemoryLocations, vLocs);
461void Codegen::statement(ExpressionNode *ast)
466 RegisterScope scope(
this);
468 bytecodeGenerator->incrementStatement();
469 pushExpr(Result(nx));
470 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
471 qSwap(_volatileMemoryLocations, vLocs);
475 qSwap(_volatileMemoryLocations, vLocs);
476 Reference result = popResult();
480 if (result.loadTriggersSideEffect())
481 result.loadInAccumulator();
485void Codegen::condition(ExpressionNode *ast,
const BytecodeGenerator::Label *iftrue,
486 const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition)
494 pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition));
496 Result r = popExpr();
501 if (r.format() == ex) {
502 Q_ASSERT(iftrue == r.iftrue());
503 Q_ASSERT(iffalse == r.iffalse());
504 Q_ASSERT(r.result().isValid());
505 bytecodeGenerator->setLocation(ast->firstSourceLocation());
506 r.result().loadInAccumulator();
507 if (r.trueBlockFollowsCondition())
508 bytecodeGenerator->jumpFalse().link(*r.iffalse());
510 bytecodeGenerator->jumpTrue().link(*r.iftrue());
514void Codegen::program(Program *ast)
517 statementList(ast->statements);
529 for (StatementList *it = list; it; it = it->next) {
530 if (it->statement->kind == Statement::Kind_BreakStatement ||
531 it->statement->kind == Statement::Kind_ContinueStatement)
533 if (it->statement->kind == Statement::Kind_EmptyStatement ||
534 it->statement->kind == Statement::Kind_VariableDeclaration ||
535 it->statement->kind == Statement::Kind_FunctionDeclaration)
537 if (it->statement->kind == Statement::Kind_Block) {
538 CompletionState subState = completionState(
static_cast<Block *>(it->statement)->statements);
550 Node *completionStatement =
nullptr;
551 for (StatementList *it = list; it; it = it->next) {
552 if (it->statement->kind == Statement::Kind_BreakStatement ||
553 it->statement->kind == Statement::Kind_ContinueStatement)
554 return completionStatement;
555 if (it->statement->kind == Statement::Kind_ThrowStatement ||
556 it->statement->kind == Statement::Kind_ReturnStatement)
557 return it->statement;
558 if (it->statement->kind == Statement::Kind_EmptyStatement ||
559 it->statement->kind == Statement::Kind_VariableStatement ||
560 it->statement->kind == Statement::Kind_FunctionDeclaration)
562 if (it->statement->kind == Statement::Kind_Block) {
563 CompletionState state = completionState(
static_cast<Block *>(it->statement)->statements);
568 return it->statement;
573 completionStatement = it->statement;
575 return completionStatement;
578void Codegen::statementList(StatementList *ast)
583 bool _requiresReturnValue = requiresReturnValue;
586 if (!controlFlow || !controlFlow->hasLoop())
587 requiresReturnValue =
false;
589 Node *needsCompletion =
nullptr;
591 if (_requiresReturnValue && !requiresReturnValue)
592 needsCompletion = completionStatement(ast);
594 if (requiresReturnValue && !needsCompletion && !insideSwitch) {
596 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
599 bool _insideSwitch = insideSwitch;
600 insideSwitch =
false;
602 for (StatementList *it = ast; it; it = it->next) {
603 if (it->statement == needsCompletion)
604 requiresReturnValue =
true;
605 if (Statement *s = it->statement->statementCast())
608 statement(
static_cast<ExpressionNode *>(it->statement));
609 if (it->statement == needsCompletion)
610 requiresReturnValue =
false;
611 if (it->statement->kind == Statement::Kind_ThrowStatement
612 || it->statement->kind == Statement::Kind_BreakStatement
613 || it->statement->kind == Statement::Kind_ContinueStatement
614 || it->statement->kind == Statement::Kind_ReturnStatement) {
616 if (Visitor *visitor = _interface->unreachableVisitor())
617 Node::accept(it->next, visitor);
621 requiresReturnValue = _requiresReturnValue;
622 insideSwitch = _insideSwitch;
625void Codegen::variableDeclaration(PatternElement *ast)
627 TailCallBlocker blockTailCalls(
this);
628 RegisterScope scope(
this);
630 if (!ast->initializer) {
631 if (ast->isLexicallyScoped()) {
632 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
633 Reference varToStore = targetForPatternElement(ast);
634 varToStore.storeConsumeAccumulator();
638 initializeAndDestructureBindingElement(ast, Reference(),
true);
641void Codegen::variableDeclarationList(VariableDeclarationList *ast)
643 for (VariableDeclarationList *it = ast; it; it = it->next) {
644 variableDeclaration(it->declaration);
648Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
650 if (!p->bindingIdentifier.isNull())
651 return referenceForName(p->bindingIdentifier.toString(),
true, p->firstSourceLocation());
652 if (!p->bindingTarget || p->destructuringPattern())
653 return Codegen::Reference::fromStackSlot(
this);
654 Reference lhs = expression(p->bindingTarget);
657 if (!lhs.isLValue()) {
658 throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral(
"Binding target is not a reference."));
661 lhs = lhs.asLValue();
669Codegen::Reference Codegen::referenceForFormalParameter(
int argIndex)
671 if (_context->argumentsCanEscape)
672 return Reference::fromScopedLocal(
this, argIndex + _context->locals.size(), 0);
673 const int index = argIndex +
int(
sizeof(CallData) /
sizeof(StaticValue)) - 1;
674 return Reference::fromStackSlot(
this, index,
true);
677void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e,
const Reference &base,
bool isDefinition)
679 Q_ASSERT(e->type == AST::PatternElement::Binding || e->type == AST::PatternElement::RestElement);
680 RegisterScope scope(
this);
681 Reference baseRef = (base.isAccumulator()) ? base.storeOnStack() : base;
682 Reference varToStore = targetForPatternElement(e);
684 varToStore.isReferenceToConst =
false;
688 if (e->typeAnnotation) {
689 throwSyntaxError(e->firstSourceLocation(),
690 QLatin1String(
"Type annotations on default parameters are not supported."));
693 const auto loadValueForStore = [&](
const Reference &value) {
694 if (isDefinition || !varToStore.requiresTDZCheck) {
695 value.loadInAccumulator();
698 Reference stashed = value.storeOnStack();
699 varToStore.checkTDZBeforeAssignment();
700 stashed.loadInAccumulator();
703 if (e->initializer) {
704 if (!baseRef.isValid()) {
706 Reference expr = expression(e->initializer);
709 loadValueForStore(expr);
710 varToStore.storeConsumeAccumulator();
711 }
else if (baseRef == varToStore) {
712 baseRef.loadInAccumulator();
713 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
714 Reference expr = expression(e->initializer);
719 loadValueForStore(expr);
720 varToStore.storeConsumeAccumulator();
723 baseRef.loadInAccumulator();
724 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
725 Reference expr = expression(e->initializer);
730 expr.loadInAccumulator();
732 loadValueForStore(Reference::fromAccumulator(
this));
733 varToStore.storeConsumeAccumulator();
735 }
else if (baseRef != varToStore && baseRef.isValid()) {
736 loadValueForStore(baseRef);
737 varToStore.storeConsumeAccumulator();
739 Pattern *p = e->destructuringPattern();
743 if (!varToStore.isStackSlot())
744 varToStore = varToStore.storeOnStack();
745 if (PatternElementList *l = e->elementList()) {
746 destructureElementList(varToStore, l, isDefinition);
747 }
else if (PatternPropertyList *p = e->propertyList()) {
748 destructurePropertyList(varToStore, p, isDefinition);
749 }
else if (e->bindingTarget) {
751 varToStore.loadInAccumulator();
752 Instruction::ToObject toObject;
753 bytecodeGenerator->addInstruction(toObject);
758Codegen::Reference Codegen::referenceForPropertyName(
const Codegen::Reference &object, AST::PropertyName *name)
760 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
763 Reference computedName = expression(cname->expression);
766 computedName = computedName.storeOnStack();
767 property = Reference::fromSubscript(object, computedName).asLValue();
769 QString propertyName = name->asString();
770 property = Reference::fromMember(object, propertyName);
775void Codegen::destructurePropertyList(
const Codegen::Reference &object, PatternPropertyList *bindingList,
bool isDefinition)
777 RegisterScope scope(
this);
779 object.loadInAccumulator();
780 Instruction::ThrowOnNullOrUndefined t;
781 bytecodeGenerator->addInstruction(t);
783 for (PatternPropertyList *it = bindingList; it; it = it->next) {
784 PatternProperty *p = it->property;
785 RegisterScope scope(
this);
786 Reference property = referenceForPropertyName(object, p->name);
789 initializeAndDestructureBindingElement(p, property, isDefinition);
795void Codegen::destructureElementList(
const Codegen::Reference &array, PatternElementList *bindingList,
bool isDefinition)
797 RegisterScope scope(
this);
799 Reference iterator = Reference::fromStackSlot(
this);
800 QVarLengthArray<Reference, 32> iteratorValues;
803 array.loadInAccumulator();
804 Instruction::GetIterator iteratorObjInstr;
805 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
806 bytecodeGenerator->addInstruction(iteratorObjInstr);
807 iterator.storeConsumeAccumulator();
809 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
810 Reference needsClose = Reference::storeConstOnStack(
this, Encode(
false));
812 for (PatternElementList *p = bindingList; p; p = p->next) {
813 PatternElement *e = p->element;
814 for (Elision *elision = p->elision; elision; elision = elision->next) {
815 iterator.loadInAccumulator();
816 Instruction::IteratorNext next;
817 if (!ignored.isValid())
818 ignored = Reference::fromStackSlot(
this);
819 next.value = ignored.stackSlot();
820 bytecodeGenerator->addJumpInstruction(next).link(done);
826 if (e->type != PatternElement::RestElement) {
827 iterator.loadInAccumulator();
828 Instruction::IteratorNext next;
829 iteratorValues.push_back(Reference::fromStackSlot(
this));
830 next.value = iteratorValues.back().stackSlot();
831 bytecodeGenerator->addJumpInstruction(next).link(done);
839 Reference::fromConst(
this, Encode(
true)).storeOnStack(needsClose.stackSlot());
842 bytecodeGenerator->checkException();
845 ControlFlowUnwindCleanup flow(
this, [&]() {
846 BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
847 needsClose.loadInAccumulator();
848 bytecodeGenerator->jumpFalse().link(skipClose);
849 iterator.loadInAccumulator();
850 Instruction::IteratorClose close;
851 bytecodeGenerator->addInstruction(close);
855 auto it = iteratorValues.constBegin();
856 for (PatternElementList *p = bindingList; p; p = p->next) {
857 PatternElement *e = p->element;
862 if (e->type == PatternElement::RestElement) {
863 Q_ASSERT(it == iteratorValues.constEnd());
866 Reference::fromConst(
this, Encode(
false)).storeOnStack(needsClose.stackSlot());
868 iterator.loadInAccumulator();
869 bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
870 initializeAndDestructureBindingElement(
871 e, Reference::fromAccumulator(
this), isDefinition);
873 Q_ASSERT(it != iteratorValues.constEnd());
874 initializeAndDestructureBindingElement(e, *it++, isDefinition);
883void Codegen::destructurePattern(Pattern *p,
const Reference &rhs)
885 RegisterScope scope(
this);
886 if (
auto *o = AST::cast<ObjectPattern *>(p))
887 destructurePropertyList(rhs, o->properties);
888 else if (
auto *a = AST::cast<ArrayPattern *>(p))
889 destructureElementList(rhs, a->elements);
895bool Codegen::visit(ArgumentList *)
897 Q_UNREACHABLE_RETURN(
false);
900bool Codegen::visit(CaseBlock *)
902 Q_UNREACHABLE_RETURN(
false);
905bool Codegen::visit(CaseClause *)
907 Q_UNREACHABLE_RETURN(
false);
910bool Codegen::visit(CaseClauses *)
912 Q_UNREACHABLE_RETURN(
false);
915bool Codegen::visit(Catch *)
917 Q_UNREACHABLE_RETURN(
false);
920bool Codegen::visit(DefaultClause *)
922 Q_UNREACHABLE_RETURN(
false);
925bool Codegen::visit(Elision *)
927 Q_UNREACHABLE_RETURN(
false);
930bool Codegen::visit(Finally *)
932 Q_UNREACHABLE_RETURN(
false);
935bool Codegen::visit(FormalParameterList *)
937 Q_UNREACHABLE_RETURN(
false);
940bool Codegen::visit(Program *)
942 Q_UNREACHABLE_RETURN(
false);
945bool Codegen::visit(PatternElement *)
947 Q_UNREACHABLE_RETURN(
false);
950bool Codegen::visit(PatternElementList *)
952 Q_UNREACHABLE_RETURN(
false);
955bool Codegen::visit(PatternProperty *)
957 Q_UNREACHABLE_RETURN(
false);
960bool Codegen::visit(PatternPropertyList *)
962 Q_UNREACHABLE_RETURN(
false);
965bool Codegen::visit(ExportDeclaration *ast)
967 if (!ast->exportDefault)
970 TailCallBlocker blockTailCalls(
this);
971 Reference exportedValue;
973 if (
auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
975 visit(
static_cast<FunctionExpression*>(fdecl));
976 exportedValue = popResult();
977 }
else if (
auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
979 visit(
static_cast<ClassExpression*>(classDecl));
980 exportedValue = popResult();
981 }
else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
982 exportedValue = expression(expr);
987 exportedValue.loadInAccumulator();
989 const int defaultExportIndex = _context->locals.indexOf(_context->localNameForDefaultExport);
990 Q_ASSERT(defaultExportIndex != -1);
991 Reference defaultExportSlot = Reference::fromScopedLocal(
this, defaultExportIndex, 0);
992 defaultExportSlot.storeConsumeAccumulator();
997bool Codegen::visit(TypeAnnotation *ast)
999 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Type annotations are not supported (yet)."));
1003bool Codegen::visit(StatementList *)
1005 Q_UNREACHABLE_RETURN(
false);
1008bool Codegen::visit(UiArrayMemberList *)
1010 Q_UNREACHABLE_RETURN(
false);
1013bool Codegen::visit(UiImport *)
1015 Q_UNREACHABLE_RETURN(
false);
1018bool Codegen::visit(UiHeaderItemList *)
1020 Q_UNREACHABLE_RETURN(
false);
1023bool Codegen::visit(UiPragmaValueList *)
1025 Q_UNREACHABLE_RETURN(
false);
1028bool Codegen::visit(UiPragma *)
1030 Q_UNREACHABLE_RETURN(
false);
1033bool Codegen::visit(UiObjectInitializer *)
1035 Q_UNREACHABLE_RETURN(
false);
1038bool Codegen::visit(UiObjectMemberList *)
1040 Q_UNREACHABLE_RETURN(
false);
1043bool Codegen::visit(UiParameterList *)
1045 Q_UNREACHABLE_RETURN(
false);
1048bool Codegen::visit(UiProgram *)
1050 Q_UNREACHABLE_RETURN(
false);
1053bool Codegen::visit(UiQualifiedId *)
1055 Q_UNREACHABLE_RETURN(
false);
1058bool Codegen::visit(VariableDeclarationList *)
1060 Q_UNREACHABLE_RETURN(
false);
1063bool Codegen::visit(ClassExpression *ast)
1065 TailCallBlocker blockTailCalls(
this);
1067 Compiler::Class jsClass;
1068 jsClass.nameIndex = registerString(ast->name.toString());
1070 ClassElementList *constructor =
nullptr;
1071 int nComputedNames = 0;
1072 int nStaticComputedNames = 0;
1074 RegisterScope scope(
this);
1075 ControlFlowBlock controlFlow(
this, ast);
1077 for (
auto *member = ast->elements; member; member = member->next) {
1078 PatternProperty *p = member->property;
1079 FunctionExpression *f = p->initializer->asFunctionDefinition();
1081 AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
1084 if (member->isStatic)
1085 ++nStaticComputedNames;
1087 QString name = p->name->asString();
1088 uint nameIndex = cname ? UINT_MAX : registerString(name);
1089 Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
1090 if (p->type == PatternProperty::Getter)
1091 type = Compiler::Class::Method::Getter;
1092 else if (p->type == PatternProperty::Setter)
1093 type = Compiler::Class::Method::Setter;
1094 Compiler::Class::Method m{ nameIndex, type,
static_cast<uint>(defineFunction(name, f, f->formals, f->body)) };
1096 if (member->isStatic) {
1097 if (name == QStringLiteral(
"prototype")) {
1098 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a static method named 'prototype'."));
1101 jsClass.staticMethods << m;
1103 if (name == QStringLiteral(
"constructor")) {
1105 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a multiple constructors in a class."));
1108 if (m.type != Compiler::Class::Method::Regular) {
1109 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a getter or setter named 'constructor'."));
1112 constructor = member;
1113 jsClass.constructorIndex = m.functionIndex;
1117 jsClass.methods << m;
1121 int classIndex = _module->classes.size();
1122 _module->classes.append(jsClass);
1124 Reference heritage = Reference::fromStackSlot(
this);
1125 if (ast->heritage) {
1126 bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
1127 Reference r = expression(ast->heritage);
1130 r.storeOnStack(heritage.stackSlot());
1132 Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1133 heritage.storeConsumeAccumulator();
1136 int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
1137 int currentStaticName = computedNames;
1138 int currentNonStaticName = computedNames + nStaticComputedNames;
1140 for (
auto *member = ast->elements; member; member = member->next) {
1141 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
1144 RegisterScope scope(
this);
1145 bytecodeGenerator->setLocation(cname->firstSourceLocation());
1146 Reference computedName = expression(cname->expression);
1149 computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
1152 Instruction::CreateClass createClass;
1153 createClass.classIndex = classIndex;
1154 createClass.heritage = heritage.stackSlot();
1155 createClass.computedNames = computedNames;
1157 bytecodeGenerator->addInstruction(createClass);
1159 if (!ast->name.isEmpty()) {
1160 Reference ctor = referenceForName(ast->name.toString(),
true);
1161 ctor.isReferenceToConst =
false;
1162 (
void) ctor.storeRetainAccumulator();
1165 setExprResult(Reference::fromAccumulator(
this));
1169bool Codegen::visit(ClassDeclaration *ast)
1171 TailCallBlocker blockTailCalls(
this);
1172 Reference outerVar = referenceForName(ast->name.toString(),
true);
1173 visit(
static_cast<ClassExpression *>(ast));
1174 (
void) outerVar.storeRetainAccumulator();
1178bool Codegen::visit(CommaExpression *ast)
1183 TailCallBlocker blockTailCalls(
this);
1184 statement(ast->left);
1185 blockTailCalls.unblock();
1186 clearExprResultName();
1191bool Codegen::visit(ArrayPattern *ast)
1196 TailCallBlocker blockTailCalls(
this);
1198 PatternElementList *it = ast->elements;
1202 RegisterScope scope(
this);
1205 auto push = [
this, &argc, &args](AST::ExpressionNode *arg) {
1206 int temp = bytecodeGenerator->newRegister();
1210 auto c = Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue());
1211 (
void) c.storeOnStack(temp);
1213 RegisterScope scope(
this);
1214 Reference r = expression(arg);
1217 (
void) r.storeOnStack(temp);
1222 for (; it; it = it->next) {
1223 PatternElement *e = it->element;
1224 if (e && e->type == PatternElement::SpreadElement)
1226 for (Elision *elision = it->elision; elision; elision = elision->next)
1232 push(e->initializer);
1238 Q_ASSERT(argc == 0);
1242 Instruction::DefineArray call;
1244 call.args = Moth::StackSlot::createRegister(args);
1245 bytecodeGenerator->addInstruction(call);
1249 setExprResult(Reference::fromAccumulator(
this));
1252 Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
1254 RegisterScope scope(
this);
1255 Reference array = Reference::fromStackSlot(
this);
1256 array.storeConsumeAccumulator();
1257 Reference index = Reference::storeConstOnStack(
this, Encode(argc));
1259 auto pushAccumulator = [&]() {
1260 Reference slot = Reference::fromSubscript(array, index);
1261 slot.storeConsumeAccumulator();
1263 index.loadInAccumulator();
1264 Instruction::Increment inc = {};
1265 bytecodeGenerator->addInstruction(inc);
1266 index.storeConsumeAccumulator();
1270 for (Elision *elision = it->elision; elision; elision = elision->next) {
1271 Reference::fromConst(
1272 this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1282 if (it->element->type == PatternElement::SpreadElement) {
1283 RegisterScope scope(
this);
1285 Reference iterator = Reference::fromStackSlot(
this);
1286 Reference lhsValue = Reference::fromStackSlot(
this);
1291 RegisterScope innerScope(
this);
1292 Reference expr = expression(it->element->initializer);
1296 expr.loadInAccumulator();
1297 Instruction::GetIterator iteratorObjInstr;
1298 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
1299 bytecodeGenerator->addInstruction(iteratorObjInstr);
1300 iterator.storeConsumeAccumulator();
1303 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
1304 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
1305 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
1308 auto cleanup = [
this, iterator, done]() {
1309 iterator.loadInAccumulator();
1310 Instruction::IteratorClose close;
1311 bytecodeGenerator->addInstruction(close);
1314 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
1317 bytecodeGenerator->addLoopStart(in);
1318 iterator.loadInAccumulator();
1319 Instruction::IteratorNext next;
1320 next.value = lhsValue.stackSlot();
1321 bytecodeGenerator->addJumpInstruction(next).link(done);
1323 lhsValue.loadInAccumulator();
1326 bytecodeGenerator->checkException();
1327 bytecodeGenerator->jump().link(in);
1331 RegisterScope innerScope(
this);
1332 Reference expr = expression(it->element->initializer);
1336 expr.loadInAccumulator();
1343 array.loadInAccumulator();
1344 setExprResult(Reference::fromAccumulator(
this));
1349bool Codegen::visit(ArrayMemberExpression *ast)
1354 const bool isTailOfChain = traverseOptionalChain(ast);
1356 TailCallBlocker blockTailCalls(
this);
1357 Reference base = expression(ast->base);
1361 auto writeSkip = [&]() {
1362 base.loadInAccumulator();
1363 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
1364 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
1365 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
1368 if (base.isSuper()) {
1369 auto e = expression(ast->expression);
1372 Reference index = e.storeOnStack();
1373 optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
1376 base = base.storeOnStack();
1379 if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
1380 QString s = str->value.toString();
1381 uint arrayIndex = stringToArrayIndex(s);
1382 if (arrayIndex == UINT_MAX) {
1383 auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
1385 &m_optionalChainsStates->top().jumpsToPatch);
1387 optionalChainFinalizer(ref, isTailOfChain);
1391 if (ast->isOptional)
1394 Reference index = Reference::fromConst(
this, QV4::Encode(arrayIndex));
1395 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1400 if (ast->isOptional)
1403 Reference index = expression(ast->expression);
1408 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1414 switch ((QSOperator::Op) op) {
1415 case QSOperator::InplaceAnd:
return QSOperator::BitAnd;
1416 case QSOperator::InplaceSub:
return QSOperator::Sub;
1417 case QSOperator::InplaceDiv:
return QSOperator::Div;
1418 case QSOperator::InplaceAdd:
return QSOperator::Add;
1419 case QSOperator::InplaceLeftShift:
return QSOperator::LShift;
1420 case QSOperator::InplaceMod:
return QSOperator::Mod;
1421 case QSOperator::InplaceExp:
return QSOperator::Exp;
1422 case QSOperator::InplaceMul:
return QSOperator::Mul;
1423 case QSOperator::InplaceOr:
return QSOperator::BitOr;
1424 case QSOperator::InplaceRightShift:
return QSOperator::RShift;
1425 case QSOperator::InplaceURightShift:
return QSOperator::URShift;
1426 case QSOperator::InplaceXor:
return QSOperator::BitXor;
1427 default:
return QSOperator::Invalid;
1431bool Codegen::visit(BinaryExpression *ast)
1436 TailCallBlocker blockTailCalls(
this);
1438 if (ast->op == QSOperator::And) {
1439 if (exprAccept(cx)) {
1440 auto iftrue = bytecodeGenerator->newLabel();
1441 condition(ast->left, &iftrue, currentExpr().iffalse(),
true);
1443 blockTailCalls.unblock();
1444 const Result &expr = currentExpr();
1445 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1447 auto iftrue = bytecodeGenerator->newLabel();
1448 auto endif = bytecodeGenerator->newLabel();
1450 Reference left = expression(ast->left);
1453 left.loadInAccumulator();
1455 bytecodeGenerator->setLocation(ast->operatorToken);
1456 bytecodeGenerator->jumpFalse().link(endif);
1459 blockTailCalls.unblock();
1460 Reference right = expression(ast->right);
1463 right.loadInAccumulator();
1467 setExprResult(Reference::fromAccumulator(
this));
1470 }
else if (ast->op == QSOperator::Or) {
1471 if (exprAccept(cx)) {
1472 auto iffalse = bytecodeGenerator->newLabel();
1473 condition(ast->left, currentExpr().iftrue(), &iffalse,
false);
1475 const Result &expr = currentExpr();
1476 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1478 auto iffalse = bytecodeGenerator->newLabel();
1479 auto endif = bytecodeGenerator->newLabel();
1481 Reference left = expression(ast->left);
1484 left.loadInAccumulator();
1486 bytecodeGenerator->setLocation(ast->operatorToken);
1487 bytecodeGenerator->jumpTrue().link(endif);
1490 blockTailCalls.unblock();
1491 Reference right = expression(ast->right);
1494 right.loadInAccumulator();
1498 setExprResult(Reference::fromAccumulator(
this));
1501 }
else if (ast->op == QSOperator::Coalesce) {
1503 Reference left = expression(ast->left);
1507 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
1509 Instruction::CmpEqNull cmp;
1511 left = left.storeOnStack();
1512 left.loadInAccumulator();
1513 bytecodeGenerator->addInstruction(cmp);
1515 bytecodeGenerator->jumpTrue().link(iftrue);
1517 blockTailCalls.unblock();
1519 left.loadInAccumulator();
1520 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
1523 Reference right = expression(ast->right);
1529 right.loadInAccumulator();
1531 setExprResult(Reference::fromAccumulator(
this));
1534 }
else if (ast->op == QSOperator::Assign) {
1535 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1536 if (AST::Pattern *p = ast->left->patternCast()) {
1537 RegisterScope scope(
this);
1538 Reference right = expression(ast->right);
1541 right = right.storeOnStack();
1542 destructurePattern(p, right);
1543 if (!exprAccept(nx)) {
1544 right.loadInAccumulator();
1545 setExprResult(Reference::fromAccumulator(
this));
1549 Reference left = expression(ast->left);
1553 if (!left.isLValue()) {
1554 throwReferenceError(ast->operatorToken, QStringLiteral(
"left-hand side of assignment operator is not an lvalue"));
1557 left = left.asLValue();
1558 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1560 blockTailCalls.unblock();
1561 Reference r = expression(ast->right);
1564 if (left.requiresTDZCheck) {
1565 r = r.storeOnStack();
1566 left.checkTDZBeforeAssignment();
1568 r.loadInAccumulator();
1570 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1572 setExprResult(left.storeConsumeAccumulator());
1574 setExprResult(left.storeRetainAccumulator());
1578 Reference left = expression(ast->left);
1583 case QSOperator::Or:
1584 case QSOperator::And:
1585 case QSOperator::Assign:
1589 case QSOperator::InplaceAnd:
1590 case QSOperator::InplaceSub:
1591 case QSOperator::InplaceDiv:
1592 case QSOperator::InplaceAdd:
1593 case QSOperator::InplaceLeftShift:
1594 case QSOperator::InplaceMod:
1595 case QSOperator::InplaceExp:
1596 case QSOperator::InplaceMul:
1597 case QSOperator::InplaceOr:
1598 case QSOperator::InplaceRightShift:
1599 case QSOperator::InplaceURightShift:
1600 case QSOperator::InplaceXor: {
1601 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1604 if (!left.isLValue()) {
1605 throwSyntaxError(ast->operatorToken, QStringLiteral(
"left-hand side of inplace operator is not an lvalue"));
1608 left = left.asLValue();
1610 Reference tempLeft = left.storeOnStack();
1611 Reference right = expression(ast->right);
1616 binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
1617 setExprResult(left.storeRetainAccumulator());
1622 case QSOperator::BitAnd:
1623 case QSOperator::BitOr:
1624 case QSOperator::BitXor:
1625 if (left.isConstant()) {
1626 Reference right = expression(ast->right);
1629 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), right, left));
1633 case QSOperator::In:
1634 case QSOperator::InstanceOf:
1635 case QSOperator::As:
1636 case QSOperator::Equal:
1637 case QSOperator::NotEqual:
1638 case QSOperator::Ge:
1639 case QSOperator::Gt:
1640 case QSOperator::Le:
1641 case QSOperator::Lt:
1642 case QSOperator::StrictEqual:
1643 case QSOperator::StrictNotEqual:
1644 case QSOperator::Add:
1645 case QSOperator::Div:
1646 case QSOperator::Exp:
1647 case QSOperator::Mod:
1648 case QSOperator::Mul:
1649 case QSOperator::Sub:
1650 case QSOperator::LShift:
1651 case QSOperator::RShift:
1652 case QSOperator::URShift: {
1654 if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
1656 right = exprResult();
1658 left = left.storeOnStack();
1659 right = expression(ast->right);
1664 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), left, right));
1673Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
1676 auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
1677 bytecodeGenerator->setLocation(loc);
1679 case QSOperator::Add: {
1680 left = left.storeOnStack();
1681 right.loadInAccumulator();
1682 Instruction::Add add;
1683 add.lhs = left.stackSlot();
1684 bytecodeGenerator->addInstruction(add);
1687 case QSOperator::Sub: {
1688 if (right.isConstant() && right.constant == Encode(
int(1))) {
1689 left.loadInAccumulator();
1690 Instruction::Decrement dec = {};
1691 bytecodeGenerator->addInstruction(dec);
1693 left = left.storeOnStack();
1694 right.loadInAccumulator();
1695 Instruction::Sub sub;
1696 sub.lhs = left.stackSlot();
1697 bytecodeGenerator->addInstruction(sub);
1701 case QSOperator::Exp: {
1702 left = left.storeOnStack();
1703 right.loadInAccumulator();
1704 Instruction::Exp exp;
1705 exp.lhs = left.stackSlot();
1706 bytecodeGenerator->addInstruction(exp);
1709 case QSOperator::Mul: {
1710 left = left.storeOnStack();
1711 right.loadInAccumulator();
1712 Instruction::Mul mul;
1713 mul.lhs = left.stackSlot();
1714 bytecodeGenerator->addInstruction(mul);
1717 case QSOperator::Div: {
1718 left = left.storeOnStack();
1719 right.loadInAccumulator();
1720 Instruction::Div div;
1721 div.lhs = left.stackSlot();
1722 bytecodeGenerator->addInstruction(div);
1725 case QSOperator::Mod: {
1726 left = left.storeOnStack();
1727 right.loadInAccumulator();
1728 Instruction::Mod mod;
1729 mod.lhs = left.stackSlot();
1730 bytecodeGenerator->addInstruction(mod);
1733 case QSOperator::BitAnd:
1734 if (right.isConstant()) {
1735 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1736 if (left.isConstant()) {
1737 int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
1738 return Reference::fromConst(
this, Encode(result));
1740 left.loadInAccumulator();
1741 Instruction::BitAndConst bitAnd;
1742 bitAnd.rhs = rightAsInt;
1743 bytecodeGenerator->addInstruction(bitAnd);
1745 right.loadInAccumulator();
1746 Instruction::BitAnd bitAnd;
1747 bitAnd.lhs = left.stackSlot();
1748 bytecodeGenerator->addInstruction(bitAnd);
1751 case QSOperator::BitOr:
1752 if (right.isConstant()) {
1753 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1754 if (left.isConstant()) {
1755 int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
1756 return Reference::fromConst(
this, Encode(result));
1758 left.loadInAccumulator();
1759 Instruction::BitOrConst bitOr;
1760 bitOr.rhs = rightAsInt;
1761 bytecodeGenerator->addInstruction(bitOr);
1763 right.loadInAccumulator();
1764 Instruction::BitOr bitOr;
1765 bitOr.lhs = left.stackSlot();
1766 bytecodeGenerator->addInstruction(bitOr);
1769 case QSOperator::BitXor:
1770 if (right.isConstant()) {
1771 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1772 if (left.isConstant()) {
1773 int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
1774 return Reference::fromConst(
this, Encode(result));
1776 left.loadInAccumulator();
1777 Instruction::BitXorConst bitXor;
1778 bitXor.rhs = rightAsInt;
1779 bytecodeGenerator->addInstruction(bitXor);
1781 right.loadInAccumulator();
1782 Instruction::BitXor bitXor;
1783 bitXor.lhs = left.stackSlot();
1784 bytecodeGenerator->addInstruction(bitXor);
1787 case QSOperator::URShift:
1788 if (right.isConstant()) {
1789 left.loadInAccumulator();
1790 Instruction::UShrConst ushr;
1791 ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1792 bytecodeGenerator->addInstruction(ushr);
1794 right.loadInAccumulator();
1795 Instruction::UShr ushr;
1796 ushr.lhs = left.stackSlot();
1797 bytecodeGenerator->addInstruction(ushr);
1800 case QSOperator::RShift:
1801 if (right.isConstant()) {
1802 left.loadInAccumulator();
1803 Instruction::ShrConst shr;
1804 shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1805 bytecodeGenerator->addInstruction(shr);
1807 right.loadInAccumulator();
1808 Instruction::Shr shr;
1809 shr.lhs = left.stackSlot();
1810 bytecodeGenerator->addInstruction(shr);
1813 case QSOperator::LShift:
1814 if (right.isConstant()) {
1815 left.loadInAccumulator();
1816 Instruction::ShlConst shl;
1817 shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1818 bytecodeGenerator->addInstruction(shl);
1820 right.loadInAccumulator();
1821 Instruction::Shl shl;
1822 shl.lhs = left.stackSlot();
1823 bytecodeGenerator->addInstruction(shl);
1826 case QSOperator::InstanceOf: {
1827 Instruction::CmpInstanceOf binop;
1828 left = left.storeOnStack();
1829 right.loadInAccumulator();
1830 binop.lhs = left.stackSlot();
1831 bytecodeGenerator->addInstruction(binop);
1834 case QSOperator::As: {
1836 left = left.storeOnStack();
1837 right.loadInAccumulator();
1838 as.lhs = left.stackSlot();
1839 bytecodeGenerator->addInstruction(as);
1842 case QSOperator::In: {
1843 Instruction::CmpIn binop;
1844 left = left.storeOnStack();
1845 right.loadInAccumulator();
1846 binop.lhs = left.stackSlot();
1847 bytecodeGenerator->addInstruction(binop);
1850 case QSOperator::StrictEqual: {
1852 return jumpBinop(oper, left, right);
1854 Instruction::CmpStrictEqual cmp;
1855 left = left.storeOnStack();
1856 right.loadInAccumulator();
1857 cmp.lhs = left.stackSlot();
1858 bytecodeGenerator->addInstruction(cmp);
1861 case QSOperator::StrictNotEqual: {
1863 return jumpBinop(oper, left, right);
1865 Instruction::CmpStrictNotEqual cmp;
1866 left = left.storeOnStack();
1867 right.loadInAccumulator();
1868 cmp.lhs = left.stackSlot();
1869 bytecodeGenerator->addInstruction(cmp);
1872 case QSOperator::Equal: {
1874 return jumpBinop(oper, left, right);
1876 Instruction::CmpEq cmp;
1877 left = left.storeOnStack();
1878 right.loadInAccumulator();
1879 cmp.lhs = left.stackSlot();
1880 bytecodeGenerator->addInstruction(cmp);
1883 case QSOperator::NotEqual: {
1885 return jumpBinop(oper, left, right);
1887 Instruction::CmpNe cmp;
1888 left = left.storeOnStack();
1889 right.loadInAccumulator();
1890 cmp.lhs = left.stackSlot();
1891 bytecodeGenerator->addInstruction(cmp);
1894 case QSOperator::Gt: {
1896 return jumpBinop(oper, left, right);
1898 Instruction::CmpGt cmp;
1899 left = left.storeOnStack();
1900 right.loadInAccumulator();
1901 cmp.lhs = left.stackSlot();
1902 bytecodeGenerator->addInstruction(cmp);
1905 case QSOperator::Ge: {
1907 return jumpBinop(oper, left, right);
1909 Instruction::CmpGe cmp;
1910 left = left.storeOnStack();
1911 right.loadInAccumulator();
1912 cmp.lhs = left.stackSlot();
1913 bytecodeGenerator->addInstruction(cmp);
1916 case QSOperator::Lt: {
1918 return jumpBinop(oper, left, right);
1920 Instruction::CmpLt cmp;
1921 left = left.storeOnStack();
1922 right.loadInAccumulator();
1923 cmp.lhs = left.stackSlot();
1924 bytecodeGenerator->addInstruction(cmp);
1927 case QSOperator::Le:
1929 return jumpBinop(oper, left, right);
1931 Instruction::CmpLe cmp;
1932 left = left.storeOnStack();
1933 right.loadInAccumulator();
1934 cmp.lhs = left.stackSlot();
1935 bytecodeGenerator->addInstruction(cmp);
1941 return Reference::fromAccumulator(
this);
1944Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
1947 if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
1949 if (left.isConstant() && !right.isConstant())
1952 if (right.isConstant()) {
1953 StaticValue c = StaticValue::fromReturnedValue(right.constant);
1954 if (c.isNull() || c.isUndefined()) {
1955 left.loadInAccumulator();
1956 if (oper == QSOperator::Equal) {
1957 Instruction::CmpEqNull cmp;
1958 bytecodeGenerator->addInstruction(cmp);
1961 }
else if (oper == QSOperator::NotEqual) {
1962 Instruction::CmpNeNull cmp;
1963 bytecodeGenerator->addInstruction(cmp);
1967 }
else if (c.isInt32()) {
1968 left.loadInAccumulator();
1969 if (oper == QSOperator::Equal) {
1970 Instruction::CmpEqInt cmp;
1971 cmp.lhs = c.int_32();
1972 bytecodeGenerator->addInstruction(cmp);
1975 }
else if (oper == QSOperator::NotEqual) {
1976 Instruction::CmpNeInt cmp;
1977 cmp.lhs = c.int_32();
1978 bytecodeGenerator->addInstruction(cmp);
1987 left = left.storeOnStack();
1988 right.loadInAccumulator();
1991 case QSOperator::StrictEqual: {
1992 Instruction::CmpStrictEqual cmp;
1993 cmp.lhs = left.stackSlot();
1994 bytecodeGenerator->addInstruction(cmp);
1998 case QSOperator::StrictNotEqual: {
1999 Instruction::CmpStrictNotEqual cmp;
2000 cmp.lhs = left.stackSlot();
2001 bytecodeGenerator->addInstruction(cmp);
2005 case QSOperator::Equal: {
2006 Instruction::CmpEq cmp;
2007 cmp.lhs = left.stackSlot();
2008 bytecodeGenerator->addInstruction(cmp);
2012 case QSOperator::NotEqual: {
2013 Instruction::CmpNe cmp;
2014 cmp.lhs = left.stackSlot();
2015 bytecodeGenerator->addInstruction(cmp);
2019 case QSOperator::Gt: {
2020 Instruction::CmpGt cmp;
2021 cmp.lhs = left.stackSlot();
2022 bytecodeGenerator->addInstruction(cmp);
2026 case QSOperator::Ge: {
2027 Instruction::CmpGe cmp;
2028 cmp.lhs = left.stackSlot();
2029 bytecodeGenerator->addInstruction(cmp);
2033 case QSOperator::Lt: {
2034 Instruction::CmpLt cmp;
2035 cmp.lhs = left.stackSlot();
2036 bytecodeGenerator->addInstruction(cmp);
2040 case QSOperator::Le: {
2041 Instruction::CmpLe cmp;
2042 cmp.lhs = left.stackSlot();
2043 bytecodeGenerator->addInstruction(cmp);
2053Codegen::Reference Codegen::loadSubscriptForCall(
const Codegen::Reference &base)
2057 base.elementSubscript.loadInAccumulator();
2058 Codegen::Instruction::LoadElement load;
2059 load.base = base.elementBase;
2060 bytecodeGenerator->addInstruction(load);
2061 return Reference::fromAccumulator(
this);
2064bool Codegen::visit(CallExpression *ast)
2069 const bool isTailOfChain = traverseOptionalChain(ast);
2071 RegisterScope scope(
this);
2072 TailCallBlocker blockTailCalls(
this);
2074 Reference expr = expression(ast->base);
2075 Reference base = expr;
2079 switch (base.type) {
2080 case Reference::Member:
2081 base = base.asLValue();
2083 case Reference::Subscript:
2084 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2085 base.subscriptLoadedForCall =
true;
2087 case Reference::Name:
2089 case Reference::Super:
2090 handleConstruct(base, ast->arguments);
2092 case Reference::SuperProperty:
2095 base = base.storeOnStack();
2099 if (expr.hasSavedCallBaseSlot) {
2101 base.hasSavedCallBaseSlot =
true;
2102 base.savedCallBaseSlot = expr.savedCallBaseSlot;
2103 base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
2106 int thisObject = bytecodeGenerator->newRegister();
2107 int functionObject = bytecodeGenerator->newRegister();
2109 if (ast->isOptional || m_optionalChainsStates->top().actuallyHasOptionals) {
2110 base.loadInAccumulator();
2111 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2112 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2113 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2116 auto calldata = pushArgs(ast->arguments);
2120 blockTailCalls.unblock();
2121 if (calldata.hasSpread || _tailCallsAreAllowed) {
2122 Reference baseObject = base.baseObject();
2123 if (!baseObject.isStackSlot()) {
2124 baseObject.storeOnStack(thisObject);
2125 baseObject = Reference::fromStackSlot(
this, thisObject);
2128 const int func = [&]() {
2129 if (base.type == Reference::Subscript)
2130 return base.element;
2132 if (!base.isStackSlot()) {
2133 base.storeOnStack(functionObject);
2134 base = Reference::fromStackSlot(
this, functionObject);
2137 return base.stackSlot();
2140 if (calldata.hasSpread) {
2141 Instruction::CallWithSpread call;
2143 call.thisObject = baseObject.stackSlot();
2144 call.argc = calldata.argc;
2145 call.argv = calldata.argv;
2146 bytecodeGenerator->addInstruction(call);
2148 Instruction::TailCall call;
2150 call.thisObject = baseObject.stackSlot();
2151 call.argc = calldata.argc;
2152 call.argv = calldata.argv;
2153 bytecodeGenerator->addInstruction(call);
2156 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2160 handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
2161 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2165void Codegen::endVisit(CallExpression *ast)
2167 m_seenOptionalChainNodes.remove(ast);
2170void Codegen::handleCall(Reference &base, Arguments calldata,
int slotForFunction,
int slotForThisObject,
bool optional)
2172 if (base.sourceLocation.isValid())
2173 bytecodeGenerator->setLocation(base.sourceLocation);
2176 if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
2177 if (useFastLookups) {
2178 Instruction::CallPropertyLookup call;
2179 if (base.hasSavedCallBaseSlot) {
2180 call.base = base.savedCallBaseSlot;
2181 call.lookupIndex = registerGetterLookup(
2182 base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
2184 call.base = base.propertyBase.stackSlot();
2185 call.lookupIndex = registerGetterLookup(
2186 base.propertyNameIndex, JSUnitGenerator::LookupForCall);
2188 call.argc = calldata.argc;
2189 call.argv = calldata.argv;
2190 bytecodeGenerator->addInstruction(call);
2192 Instruction::CallProperty call;
2193 if (base.hasSavedCallBaseSlot) {
2194 call.base = base.savedCallBaseSlot;
2195 call.name = base.savedCallPropertyNameIndex;
2197 call.base = base.propertyBase.stackSlot();
2198 call.name = base.propertyNameIndex;
2200 call.argc = calldata.argc;
2201 call.argv = calldata.argv;
2202 bytecodeGenerator->addInstruction(call);
2204 }
else if (base.type == Reference::Subscript) {
2205 Instruction::CallWithReceiver call;
2206 call.thisObject = base.elementBase.stackSlot();
2207 call.name = base.element;
2208 call.argc = calldata.argc;
2209 call.argv = calldata.argv;
2210 bytecodeGenerator->addInstruction(call);
2211 }
else if (base.type == Reference::Name) {
2212 if (base.name == QStringLiteral(
"eval") && !optional) {
2213 Instruction::CallPossiblyDirectEval call;
2214 call.argc = calldata.argc;
2215 call.argv = calldata.argv;
2216 bytecodeGenerator->addInstruction(call);
2217 }
else if (useFastLookups && base.global) {
2218 if (base.qmlGlobal) {
2219 Instruction::CallQmlContextPropertyLookup call;
2220 call.index = registerQmlContextPropertyGetterLookup(
2221 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2222 call.argc = calldata.argc;
2223 call.argv = calldata.argv;
2224 bytecodeGenerator->addInstruction(call);
2226 Instruction::CallGlobalLookup call;
2227 call.index = registerGlobalGetterLookup(
2228 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2229 call.argc = calldata.argc;
2230 call.argv = calldata.argv;
2231 bytecodeGenerator->addInstruction(call);
2234 Instruction::CallName call;
2235 call.name = base.nameAsIndex();
2236 call.argc = calldata.argc;
2237 call.argv = calldata.argv;
2238 bytecodeGenerator->addInstruction(call);
2240 }
else if (base.type == Reference::SuperProperty) {
2241 Reference receiver = base.baseObject();
2242 if (!base.isStackSlot()) {
2243 base.storeOnStack(slotForFunction);
2244 base = Reference::fromStackSlot(
this, slotForFunction);
2246 if (!receiver.isStackSlot()) {
2247 receiver.storeOnStack(slotForThisObject);
2248 receiver = Reference::fromStackSlot(
this, slotForThisObject);
2250 Instruction::CallWithReceiver call;
2251 call.name = base.stackSlot();
2252 call.thisObject = receiver.stackSlot();
2253 call.argc = calldata.argc;
2254 call.argv = calldata.argv;
2255 bytecodeGenerator->addInstruction(call);
2257 Q_ASSERT(base.isStackSlot());
2258 Instruction::CallValue call;
2259 call.name = base.stackSlot();
2260 call.argc = calldata.argc;
2261 call.argv = calldata.argv;
2262 bytecodeGenerator->addInstruction(call);
2266Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
2268 bool hasSpread =
false;
2270 for (ArgumentList *it = args; it; it = it->next) {
2271 if (it->spreadToken.isValid()) {
2279 return { 0, 0,
false };
2281 int calldata = bytecodeGenerator->newRegisterArray(argc);
2284 for (ArgumentList *it = args; it; it = it->next) {
2285 if (it->spreadToken.isValid()) {
2286 Reference::fromConst(
2288 StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
2291 RegisterScope scope(
this);
2292 Reference e = expression(it->expression);
2295 if (!argc && !it->next && !hasSpread) {
2297 if (e.isStackSlot()) {
2299 return { 1, e.stackSlot(), hasSpread };
2302 (
void) e.storeOnStack(calldata + argc);
2306 return { argc, calldata, hasSpread };
2309Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
2312 for (TemplateLiteral *it = args; it; it = it->next)
2316 return { 0, 0,
false };
2318 int calldata = bytecodeGenerator->newRegisterArray(argc);
2321 for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
2322 RegisterScope scope(
this);
2323 Reference e = expression(it->expression);
2326 (
void) e.storeOnStack(calldata + argc);
2330 return { argc, calldata,
false };
2333bool Codegen::visit(ConditionalExpression *ast)
2338 RegisterScope scope(
this);
2339 TailCallBlocker blockTailCalls(
this);
2341 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
2342 BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
2343 condition(ast->expression, &iftrue, &iffalse,
true);
2345 blockTailCalls.unblock();
2348 Reference ok = expression(ast->ok);
2351 ok.loadInAccumulator();
2352 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
2355 Reference ko = expression(ast->ko);
2360 ko.loadInAccumulator();
2363 setExprResult(Reference::fromAccumulator(
this));
2368bool Codegen::visit(DeleteExpression *ast)
2373 const bool isTailOfChain = traverseOptionalChain(ast);
2375 RegisterScope scope(
this);
2376 TailCallBlocker blockTailCalls(
this);
2377 Reference expr = expression(ast->expression);
2381 const bool chainActuallyHasOptionals = m_optionalChainsStates->top().actuallyHasOptionals;
2382 if (chainActuallyHasOptionals)
2383 Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
2385 switch (expr.type) {
2386 case Reference::SuperProperty:
2389 case Reference::StackSlot:
2390 if (!expr.stackSlotIsLocalOrArgument)
2393 case Reference::ScopedLocal:
2395 if (_context->isStrict) {
2396 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2399 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2401 case Reference::Name: {
2402 if (_context->isStrict) {
2403 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2406 Instruction::DeleteName del;
2407 del.name = expr.nameAsIndex();
2408 bytecodeGenerator->addInstruction(del);
2409 setExprResult(Reference::fromAccumulator(
this));
2412 case Reference::Member: {
2414 expr = expr.asLValue();
2416 if (chainActuallyHasOptionals) {
2417 expr.loadInAccumulator();
2418 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2419 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2420 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2423 Instruction::LoadRuntimeString instr;
2424 instr.stringId = expr.propertyNameIndex;
2425 bytecodeGenerator->addInstruction(instr);
2426 Reference index = Reference::fromStackSlot(
this);
2427 index.storeConsumeAccumulator();
2428 Instruction::DeleteProperty del;
2429 del.base = expr.propertyBase.stackSlot();
2430 del.index = index.stackSlot();
2431 bytecodeGenerator->addInstruction(del);
2432 auto ref = Reference::fromAccumulator(
this);
2434 optionalChainFinalizer(ref, isTailOfChain,
true);
2437 case Reference::Subscript: {
2439 expr = expr.asLValue();
2441 if (chainActuallyHasOptionals) {
2442 expr.loadInAccumulator();
2443 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2444 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2445 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2448 Instruction::DeleteProperty del;
2449 del.base = expr.elementBase;
2450 del.index = expr.elementSubscript.stackSlot();
2451 bytecodeGenerator->addInstruction(del);
2452 auto ref = Reference::fromAccumulator(
this);
2454 optionalChainFinalizer(ref, isTailOfChain,
true);
2461 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
2465void Codegen::endVisit(DeleteExpression *ast) {
2466 m_seenOptionalChainNodes.remove(ast);
2469bool Codegen::visit(FalseLiteral *)
2474 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2478bool Codegen::visit(SuperLiteral *)
2483 setExprResult(Reference::fromSuper(
this));
2487bool Codegen::traverseOptionalChain(Node *node)
2489 if (m_seenOptionalChainNodes.contains(node))
2492 const auto isOptionalChainableNode = [](
const Node *node) {
2493 return node->kind == Node::Kind_FieldMemberExpression ||
2494 node->kind == Node::Kind_CallExpression ||
2495 node->kind == Node::Kind_ArrayMemberExpression ||
2496 node->kind == Node::Kind_DeleteExpression;
2498 m_optionalChainsStates->emplace();
2499 while (isOptionalChainableNode(node)) {
2500 m_seenOptionalChainNodes.insert(node);
2502 switch (node->kind) {
2503 case Node::Kind_FieldMemberExpression: {
2504 auto *fme = AST::cast<FieldMemberExpression *>(node);
2505 m_optionalChainsStates->top().actuallyHasOptionals |= fme->isOptional;
2509 case Node::Kind_CallExpression: {
2510 auto *ce = AST::cast<CallExpression *>(node);
2511 m_optionalChainsStates->top().actuallyHasOptionals |= ce->isOptional;
2515 case Node::Kind_ArrayMemberExpression: {
2516 auto *ame = AST::cast<ArrayMemberExpression *>(node);
2517 m_optionalChainsStates->top().actuallyHasOptionals |= ame->isOptional;
2521 case Node::Kind_DeleteExpression:
2522 node = AST::cast<DeleteExpression *>(node)->expression;
2532void Codegen::optionalChainFinalizer(
const Reference &expressionResult,
bool tailOfChain,
2533 bool isDeleteExpression)
2535 auto &chainState = m_optionalChainsStates->top();
2537 setExprResult(expressionResult);
2539 }
else if (!chainState.actuallyHasOptionals) {
2540 setExprResult(expressionResult);
2541 m_optionalChainsStates->pop();
2545 auto savedBaseSlot = -1;
2546 if (expressionResult.type == Reference::Member)
2547 savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
2548 expressionResult.loadInAccumulator();
2550 std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
2551 if (!isDeleteExpression)
2552 jumpToDone.emplace(bytecodeGenerator->jump());
2554 for (
auto &jump : chainState.jumpsToPatch)
2557 if (isDeleteExpression)
2558 bytecodeGenerator->addInstruction(Instruction::LoadTrue());
2560 bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
2562 if (jumpToDone.has_value())
2563 jumpToDone.value().link();
2565 auto ref = Reference::fromAccumulator(
this);
2566 if (expressionResult.type == Reference::Member) {
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579 ref.hasSavedCallBaseSlot =
true;
2580 ref.savedCallBaseSlot = savedBaseSlot;
2581 ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
2584 m_optionalChainsStates->pop();
2587bool Codegen::visit(FieldMemberExpression *ast)
2592 const bool isTailOfChain = traverseOptionalChain(ast);
2594 TailCallBlocker blockTailCalls(
this);
2596 if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
2597 if (id->name == QLatin1String(
"new")) {
2599 Q_ASSERT(ast->name == QLatin1String(
"target"));
2601 if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
2602 Reference r = referenceForName(QStringLiteral(
"new.target"),
false);
2603 r.isReadonly =
true;
2609 auto ref = Reference::fromStackSlot(
this, CallData::NewTarget);
2610 optionalChainFinalizer(ref, isTailOfChain);
2615 Reference base = expression(ast->base);
2619 if (base.isSuper()) {
2620 Instruction::LoadRuntimeString load;
2621 load.stringId = registerString(ast->name.toString());
2622 bytecodeGenerator->addInstruction(load);
2623 Reference property = Reference::fromAccumulator(
this).storeOnStack();
2625 optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
2629 auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
2630 ast->isOptional, &m_optionalChainsStates->top().jumpsToPatch);
2632 optionalChainFinalizer(ref, isTailOfChain);
2636void Codegen::endVisit(FieldMemberExpression *ast)
2638 m_seenOptionalChainNodes.remove(ast);
2641bool Codegen::visit(TaggedTemplate *ast)
2646 RegisterScope scope(
this);
2647 auto base = expression(ast->base);
2650 return handleTaggedTemplate(std::move(base), ast);
2653bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
2658 int functionObject = -1, thisObject = -1;
2659 switch (base.type) {
2660 case Reference::Member:
2661 base = base.asLValue();
2663 case Reference::Subscript:
2664 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2665 base.subscriptLoadedForCall =
true;
2667 case Reference::Name:
2669 case Reference::SuperProperty:
2670 thisObject = bytecodeGenerator->newRegister();
2671 functionObject = bytecodeGenerator->newRegister();
2674 base = base.storeOnStack();
2678 createTemplateObject(ast->templateLiteral);
2679 int templateObjectTemp = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
2680 Q_UNUSED(templateObjectTemp);
2681 auto calldata = pushTemplateArgs(ast->templateLiteral);
2685 Q_ASSERT(calldata.argv == templateObjectTemp + 1);
2688 handleCall(base, calldata, functionObject, thisObject);
2689 setExprResult(Reference::fromAccumulator(
this));
2693void Codegen::createTemplateObject(TemplateLiteral *t)
2697 for (TemplateLiteral *it = t; it; it = it->next) {
2698 obj.strings.append(registerString(it->value.toString()));
2699 obj.rawStrings.append(registerString(it->rawValue.toString()));
2702 int index = _module->templateObjects.size();
2703 _module->templateObjects.append(obj);
2705 Instruction::GetTemplateObject getTemplateObject;
2706 getTemplateObject.index = index;
2707 bytecodeGenerator->addInstruction(getTemplateObject);
2710bool Codegen::visit(FunctionExpression *ast)
2715 TailCallBlocker blockTailCalls(
this);
2717 RegisterScope scope(
this);
2719 int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
2722 loadClosure(function);
2723 setExprResult(Reference::fromAccumulator(
this));
2727Codegen::Reference Codegen::referenceForName(
const QString &name,
bool isLhs,
const SourceLocation &accessLocation)
2729 Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
2730 bool throwsReferenceError =
false;
2732 if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
2733 || resolved.type == Context::ResolvedName::Import) {
2734 if (resolved.isArgOrEval && isLhs)
2736 throwSyntaxError(SourceLocation(), QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
2738 if (resolved.declarationLocation.isValid() && accessLocation.isValid()
2739 && resolved.declarationLocation.begin() > accessLocation.end()) {
2740 Q_ASSERT(_interface);
2741 if (resolved.memberType == Context::FunctionDefinition) {
2742 _interface->reportFunctionUsedBeforeDeclaration(
2743 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2745 _interface->reportVarUsedBeforeDeclaration(
2746 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2748 if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
2749 throwsReferenceError =
true;
2752 if (resolved.isInjected && accessLocation.isValid()) {
2753 qCWarning(lcQmlInjectedParameter).nospace().noquote()
2754 << url().toString() <<
":" << accessLocation.startLine
2755 <<
":" << accessLocation.startColumn <<
" Parameter \"" << name
2756 <<
"\" is not declared."
2757 <<
" Injection of parameters into signal handlers is deprecated."
2758 <<
" Use JavaScript functions with formal parameters instead.";
2762 switch (resolved.type) {
2763 case Context::ResolvedName::Local:
2764 r = Reference::fromScopedLocal(
this, resolved.index, resolved.scope);
break;
2765 case Context::ResolvedName::Stack:
2766 r = Reference::fromStackSlot(
this, resolved.index,
true );
break;
2767 case Context::ResolvedName::Import:
2768 r = Reference::fromImport(
this, resolved.index);
break;
2769 default: Q_UNREACHABLE();
2771 if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
2772 r.isVolatile =
true;
2773 r.isArgOrEval = resolved.isArgOrEval;
2774 r.isReferenceToConst = resolved.isConst;
2775 r.requiresTDZCheck = resolved.requiresTDZCheck;
2777 r.sourceLocation = accessLocation;
2778 r.throwsReferenceError = throwsReferenceError;
2782 Reference r = Reference::fromName(
this, name);
2783 r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
2784 r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
2785 r.sourceLocation = accessLocation;
2786 if (!r.global && !r.qmlGlobal
2787 && _context->contextType == ContextType::ScriptImportedByQML
2788 && Codegen::isNameGlobal(name)) {
2798void Codegen::loadClosure(
int closureId)
2800 if (closureId >= 0) {
2801 Instruction::LoadClosure load;
2802 load.value = closureId;
2803 bytecodeGenerator->addInstruction(load);
2805 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
2809bool Codegen::visit(IdentifierExpression *ast)
2814 setExprResult(referenceForName(ast->name.toString(),
false, ast->firstSourceLocation()));
2818bool Codegen::visit(NestedExpression *ast)
2823 accept(ast->expression);
2827void Codegen::handleConstruct(
const Reference &base, ArgumentList *arguments)
2829 Reference constructor;
2830 if (base.isSuper()) {
2831 Instruction::LoadSuperConstructor super;
2832 bytecodeGenerator->addInstruction(super);
2833 constructor = Reference::fromAccumulator(
this).storeOnStack();
2835 constructor = base.storeOnStack();
2838 auto calldata = pushArgs(arguments);
2843 Reference::fromStackSlot(
this, CallData::NewTarget).loadInAccumulator();
2845 constructor.loadInAccumulator();
2847 if (calldata.hasSpread) {
2848 Instruction::ConstructWithSpread create;
2849 create.func = constructor.stackSlot();
2850 create.argc = calldata.argc;
2851 create.argv = calldata.argv;
2852 bytecodeGenerator->addInstruction(create);
2854 Instruction::Construct create;
2855 create.func = constructor.stackSlot();
2856 create.argc = calldata.argc;
2857 create.argv = calldata.argv;
2858 bytecodeGenerator->addInstruction(create);
2862 Reference::fromAccumulator(
this).storeOnStack(CallData::This);
2864 setExprResult(Reference::fromAccumulator(
this));
2867bool Codegen::visit(NewExpression *ast)
2872 RegisterScope scope(
this);
2873 TailCallBlocker blockTailCalls(
this);
2875 Reference base = expression(ast->expression);
2878 if (base.isSuper()) {
2879 throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2883 handleConstruct(base,
nullptr);
2887bool Codegen::visit(NewMemberExpression *ast)
2892 RegisterScope scope(
this);
2893 TailCallBlocker blockTailCalls(
this);
2895 Reference base = expression(ast->base);
2898 if (base.isSuper()) {
2899 throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2903 handleConstruct(base, ast->arguments);
2907bool Codegen::visit(NotExpression *ast)
2912 TailCallBlocker blockTailCalls(
this);
2913 auto e = expression(ast->expression);
2916 setExprResult(unop(Not, e));
2920bool Codegen::visit(NullExpression *)
2926 bytecodeGenerator->jump().link(*currentExpr().iffalse());
2928 setExprResult(Reference::fromConst(
this, Encode::null()));
2933bool Codegen::visit(NumericLiteral *ast)
2938 setExprResult(Reference::fromConst(
this, QV4::Encode::smallestNumber(ast->value)));
2942bool Codegen::visit(ObjectPattern *ast)
2947 TailCallBlocker blockTailCalls(
this);
2949 RegisterScope scope(
this);
2951 QStringList members;
2955 auto push = [
this, &args, &argc](
const Reference &arg) {
2956 int temp = bytecodeGenerator->newRegister();
2959 (
void) arg.storeOnStack(temp);
2963 PatternPropertyList *it = ast->properties;
2964 for (; it; it = it->next) {
2965 PatternProperty *p = it->property;
2966 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2967 if (cname || p->type != PatternProperty::Literal)
2969 QString name = p->name->asString();
2970 uint arrayIndex = stringToArrayIndex(name);
2971 if (arrayIndex != UINT_MAX)
2973 if (members.contains(name))
2975 members.append(name);
2978 RegisterScope innerScope(
this);
2979 Reference value = expression(p->initializer, name);
2982 value.loadInAccumulator();
2984 push(Reference::fromAccumulator(
this));
2987 int classId = jsUnitGenerator->registerJSClass(members);
2990 for (; it; it = it->next) {
2991 PatternProperty *p = it->property;
2992 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2993 ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
2994 if (p->type == PatternProperty::Method)
2995 argType = ObjectLiteralArgument::Method;
2996 else if (p->type == PatternProperty::Getter)
2997 argType = ObjectLiteralArgument::Getter;
2998 else if (p->type == PatternProperty::Setter)
2999 argType = ObjectLiteralArgument::Setter;
3001 Reference::fromConst(
this, Encode(
int(argType))).loadInAccumulator();
3002 push(Reference::fromAccumulator(
this));
3005 RegisterScope innerScope(
this);
3006 Reference name = expression(cname->expression);
3009 name.loadInAccumulator();
3011 QString name = p->name->asString();
3013 uint arrayIndex = QV4::String::toArrayIndex(name);
3014 if (arrayIndex != UINT_MAX) {
3015 Reference::fromConst(
this, Encode(arrayIndex)).loadInAccumulator();
3019 Instruction::LoadRuntimeString instr;
3020 instr.stringId = registerString(name);
3021 bytecodeGenerator->addInstruction(instr);
3024 push(Reference::fromAccumulator(
this));
3026 RegisterScope innerScope(
this);
3027 if (p->type != PatternProperty::Literal) {
3029 FunctionExpression *f = p->initializer->asFunctionDefinition();
3031 int function = defineFunction(f->name.toString(), f, f->formals, f->body);
3034 Reference::fromConst(
this, Encode(function)).loadInAccumulator();
3036 Reference value = expression(p->initializer);
3039 value.loadInAccumulator();
3042 push(Reference::fromAccumulator(
this));
3045 Instruction::DefineObjectLiteral call;
3046 call.internalClassId = classId;
3048 call.args = Moth::StackSlot::createRegister(args);
3049 bytecodeGenerator->addInstruction(call);
3050 setExprResult(Reference::fromAccumulator(
this));
3054bool Codegen::visit(PostDecrementExpression *ast)
3059 Reference expr = expression(ast->base);
3062 if (!expr.isLValue()) {
3063 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3066 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3069 setExprResult(unop(PostDecrement, expr));
3074bool Codegen::visit(PostIncrementExpression *ast)
3079 Reference expr = expression(ast->base);
3082 if (!expr.isLValue()) {
3083 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3086 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3089 setExprResult(unop(PostIncrement, expr));
3093bool Codegen::visit(PreDecrementExpression *ast)
3097 Reference expr = expression(ast->expression);
3100 if (!expr.isLValue()) {
3101 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix -- operator applied to value that is not a reference."));
3105 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3107 setExprResult(unop(PreDecrement, expr));
3111bool Codegen::visit(PreIncrementExpression *ast)
3116 Reference expr = expression(ast->expression);
3119 if (!expr.isLValue()) {
3120 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3124 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3126 setExprResult(unop(PreIncrement, expr));
3130bool Codegen::visit(RegExpLiteral *ast)
3135 auto r = Reference::fromStackSlot(
this);
3136 r.isReadonly =
true;
3139 Instruction::MoveRegExp instr;
3140 instr.regExpId = jsUnitGenerator->registerRegExp(ast);
3141 instr.destReg = r.stackSlot();
3142 bytecodeGenerator->addInstruction(instr);
3146bool Codegen::visit(StringLiteral *ast)
3151 auto r = Reference::fromAccumulator(
this);
3152 r.isReadonly =
true;
3155 Instruction::LoadRuntimeString instr;
3156 instr.stringId = registerString(ast->value.toString());
3157 bytecodeGenerator->addInstruction(instr);
3161bool Codegen::visit(TemplateLiteral *ast)
3166 TailCallBlocker blockTailCalls(
this);
3168 Instruction::LoadRuntimeString instr;
3169 instr.stringId = registerString(ast->value.toString());
3170 bytecodeGenerator->addInstruction(instr);
3172 if (ast->expression) {
3173 RegisterScope scope(
this);
3174 int temp = bytecodeGenerator->newRegister();
3175 Instruction::StoreReg store;
3177 bytecodeGenerator->addInstruction(store);
3179 Reference expr = expression(ast->expression);
3184 int temp2 = bytecodeGenerator->newRegister();
3185 expr.storeOnStack(temp2);
3188 Instruction::Add instr;
3190 bytecodeGenerator->addInstruction(instr);
3192 expr.loadInAccumulator();
3195 Instruction::Add instr;
3197 bytecodeGenerator->addInstruction(instr);
3200 auto r = Reference::fromAccumulator(
this);
3201 r.isReadonly =
true;
3208bool Codegen::visit(ThisExpression *)
3213 for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
3214 if (parentContext->isArrowFunction) {
3215 Reference r = referenceForName(QStringLiteral(
"this"),
false);
3216 r.isReadonly =
true;
3220 if (parentContext->contextType != ContextType::Block)
3224 setExprResult(Reference::fromThis(
this));
3228bool Codegen::visit(TildeExpression *ast)
3233 TailCallBlocker blockTailCalls(
this);
3234 auto e = expression(ast->expression);
3238 setExprResult(unop(Compl, e));
3242bool Codegen::visit(TrueLiteral *)
3247 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
3251bool Codegen::visit(TypeOfExpression *ast)
3256 RegisterScope scope(
this);
3257 TailCallBlocker blockTailCalls(
this);
3259 Reference expr = expression(ast->expression);
3263 if (expr.type == Reference::Name) {
3265 Instruction::TypeofName instr;
3266 instr.name = expr.nameAsIndex();
3267 bytecodeGenerator->addInstruction(instr);
3269 expr.loadInAccumulator();
3270 Instruction::TypeofValue instr;
3271 bytecodeGenerator->addInstruction(instr);
3273 setExprResult(Reference::fromAccumulator(
this));
3278bool Codegen::visit(UnaryMinusExpression *ast)
3283 TailCallBlocker blockTailCalls(
this);
3284 auto e = expression(ast->expression);
3288 setExprResult(unop(UMinus, e));
3292bool Codegen::visit(UnaryPlusExpression *ast)
3297 TailCallBlocker blockTailCalls(
this);
3298 auto e = expression(ast->expression);
3302 setExprResult(unop(UPlus, e));
3306bool Codegen::visit(VoidExpression *ast)
3311 RegisterScope scope(
this);
3312 TailCallBlocker blockTailCalls(
this);
3314 statement(ast->expression);
3315 setExprResult(Reference::fromConst(
this, Encode::undefined()));
3319bool Codegen::visit(FunctionDeclaration * ast)
3325 RegisterScope scope(
this);
3327 if (_functionContext->contextType == ContextType::Binding)
3328 referenceForName(ast->name.toString(),
true).loadInAccumulator();
3333bool Codegen::visit(YieldExpression *ast)
3335 if (inFormalParameterList) {
3336 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"yield is not allowed inside parameter lists"));
3340 auto innerMostCurentFunctionContext = _context;
3341 while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
3342 innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
3344 Q_ASSERT(innerMostCurentFunctionContext);
3346 if (!innerMostCurentFunctionContext->isGenerator) {
3347 throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
3351 RegisterScope scope(
this);
3352 TailCallBlocker blockTailCalls(
this);
3353 Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(
this, Encode::undefined());
3357 Reference acc = Reference::fromAccumulator(
this);
3359 if (ast->isYieldStar) {
3360 Reference iterator = Reference::fromStackSlot(
this);
3361 Reference lhsValue = Reference::fromConst(
this, Encode::undefined()).storeOnStack();
3363 expr.loadInAccumulator();
3364 Instruction::GetIterator getIterator;
3365 getIterator.iterator =
static_cast<
int>(AST::ForEachType::Of);
3366 bytecodeGenerator->addInstruction(getIterator);
3367 iterator.storeConsumeAccumulator();
3368 Instruction::LoadUndefined load;
3369 bytecodeGenerator->addInstruction(load);
3371 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3372 bytecodeGenerator->jump().link(in);
3374 BytecodeGenerator::Label loop = bytecodeGenerator->label();
3376 lhsValue.loadInAccumulator();
3377 Instruction::YieldStar yield;
3378 bytecodeGenerator->addInstruction(yield);
3382 Instruction::IteratorNextForYieldStar next;
3383 next.object = lhsValue.stackSlot();
3384 next.iterator = iterator.stackSlot();
3385 BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
3386 bytecodeGenerator->jumpNotUndefined().link(loop);
3388 lhsValue.loadInAccumulator();
3393 bytecodeGenerator->checkException();
3395 lhsValue.loadInAccumulator();
3400 expr.loadInAccumulator();
3401 Instruction::Yield yield;
3402 bytecodeGenerator->addInstruction(yield);
3403 Instruction::Resume resume;
3404 BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
3415 if (AST::cast<ReturnStatement *>(node))
3417 if (AST::cast<ThrowStatement *>(node))
3419 if (Program *p = AST::cast<Program *>(node))
3420 return endsWithReturn(module, p->statements);
3421 if (StatementList *sl = AST::cast<StatementList *>(node)) {
3424 return endsWithReturn(module, sl->statement);
3426 if (Block *b = AST::cast<Block *>(node)) {
3427 Context *blockContext = module->contextMap.value(node);
3428 if (blockContext->requiresExecutionContext)
3432 return endsWithReturn(module, b->statements);
3434 if (IfStatement *is = AST::cast<IfStatement *>(node))
3435 return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
3439int Codegen::defineFunction(
const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
3440 AST::StatementList *body)
3444 if (_context->functionIndex >= 0)
3446 return leaveContext();
3448 _context->name = name.isEmpty() ? currentExpr().result().name : name;
3449 _module->functions.append(_context);
3450 _context->functionIndex = _module->functions.size() - 1;
3452 Context *savedFunctionContext = _functionContext;
3453 _functionContext = _context;
3454 ControlFlow *savedControlFlow = controlFlow;
3455 controlFlow =
nullptr;
3457 if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
3458 _module->blocks.append(_context);
3459 _context->blockIndex = _module->blocks.size() - 1;
3461 if (_module->debugMode)
3462 _context->argumentsCanEscape =
true;
3470 _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
3471 && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
3473 BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
3474 BytecodeGenerator *savedBytecodeGenerator;
3475 savedBytecodeGenerator = bytecodeGenerator;
3476 bytecodeGenerator = &bytecode;
3477 bytecodeGenerator->setLocation(ast->firstSourceLocation());
3478 BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
3479 _returnLabel =
nullptr;
3481 OptionalChainStates optionalChainStates;
3482 OptionalChainStates *savedOptionalChainStates = m_optionalChainsStates;
3483 m_optionalChainsStates = &optionalChainStates;
3485 bool savedFunctionEndsWithReturn = functionEndsWithReturn;
3486 functionEndsWithReturn = endsWithReturn(_module, body);
3489 bytecodeGenerator->newRegisterArray(
3490 sizeof(CallData) /
sizeof(StaticValue) - 1 + _context->arguments.size());
3492 bool _inFormalParameterList =
false;
3493 qSwap(_inFormalParameterList, inFormalParameterList);
3495 int returnAddress = -1;
3496 bool _requiresReturnValue = _context->requiresImplicitReturnValue();
3497 qSwap(requiresReturnValue, _requiresReturnValue);
3498 returnAddress = bytecodeGenerator->newRegister();
3499 qSwap(_returnAddress, returnAddress);
3502 if (!_context->parent && _context->requiresExecutionContext) {
3503 _module->blocks.append(_context);
3504 _context->blockIndex = _module->blocks.size() - 1;
3507 TailCallBlocker maybeBlockTailCalls(
this, _context->canHaveTailCalls());
3509 RegisterScope registerScope(
this);
3510 _context->emitBlockHeader(
this);
3513 QScopedValueRollback<
bool> inFormals(inFormalParameterList,
true);
3514 TailCallBlocker blockTailCalls(
this);
3518 PatternElement *e = formals->element;
3526 if (e->type == PatternElement::RestElement) {
3527 Q_ASSERT(!formals->next);
3528 Reference arg = referenceForName(e->bindingIdentifier.toString(),
true);
3529 Instruction::CreateRestParameter rest;
3530 rest.argIndex = argc;
3531 bytecodeGenerator->addInstruction(rest);
3532 arg.storeConsumeAccumulator();
3535 const auto memberIt = _context->members.constFind(e->bindingIdentifier.toString());
3536 const bool promoted = memberIt != _context->members.constEnd()
3537 && memberIt->isFormalParameterTDZPromotion;
3538 if (e->bindingTarget || e->initializer || promoted) {
3539 Reference arg = referenceForFormalParameter(argc);
3540 initializeAndDestructureBindingElement(e, arg,
true);
3545 formals = formals->next;
3550 if (_context->isGenerator) {
3551 Instruction::Yield yield;
3552 bytecodeGenerator->addInstruction(yield);
3555 statementList(body);
3558 bytecodeGenerator->setError(
true);
3560 bytecodeGenerator->setLocation(ast->lastSourceLocation());
3561 _context->emitBlockFooter(
this);
3563 if (_returnLabel || !functionEndsWithReturn) {
3565 _returnLabel->link();
3567 if (_returnLabel || requiresReturnValue) {
3568 Instruction::LoadReg load;
3569 load.reg = Moth::StackSlot::createRegister(_returnAddress);
3570 bytecodeGenerator->addInstruction(load);
3572 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
3575 bytecodeGenerator->addInstruction(Instruction::Ret());
3578 Q_ASSERT(_context == _functionContext);
3579 bytecodeGenerator->finalize(_context);
3580 _context->registerCountInFunction = bytecodeGenerator->registerCount();
3581 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
3583 qDebug() <<
"=== Bytecode for" << _context->name <<
"strict mode" << _context->isStrict
3584 <<
"register count" << _context->registerCountInFunction <<
"implicit return" << requiresReturnValue;
3585 qDebug().noquote() << QV4::Moth::dumpBytecode(
3586 _context->code, _context->locals.size(), _context->arguments.size(),
3587 _context->line, _context->lineAndStatementNumberMapping);
3592 qSwap(_returnAddress, returnAddress);
3593 qSwap(requiresReturnValue, _requiresReturnValue);
3594 qSwap(_inFormalParameterList, inFormalParameterList);
3595 m_optionalChainsStates = savedOptionalChainStates;
3596 bytecodeGenerator = savedBytecodeGenerator;
3597 delete _returnLabel;
3598 _returnLabel = savedReturnLabel;
3599 controlFlow = savedControlFlow;
3600 functionEndsWithReturn = savedFunctionEndsWithReturn;
3601 _functionContext = savedFunctionContext;
3603 return leaveContext();
3606bool Codegen::visit(Block *ast)
3611 RegisterScope scope(
this);
3613 ControlFlowBlock controlFlow(
this, ast);
3614 statementList(ast->statements);
3618bool Codegen::visit(BreakStatement *ast)
3625 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3629 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
3630 if (!target.linkLabel.isValid()) {
3631 if (ast->label.isEmpty())
3632 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3634 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3638 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3643bool Codegen::visit(ContinueStatement *ast)
3649 RegisterScope scope(
this);
3652 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Continue outside of loop"));
3656 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
3657 if (!target.linkLabel.isValid()) {
3658 if (ast->label.isEmpty())
3659 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3661 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"continue outside of loop"));
3665 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3670bool Codegen::visit(DebuggerStatement *)
3676bool Codegen::visit(DoWhileStatement *ast)
3681 RegisterScope scope(
this);
3683 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3684 BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
3685 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3687 ControlFlowLoop flow(
this, &end, &cond);
3691 if (!AST::cast<FalseLiteral *>(ast->expression))
3692 bytecodeGenerator->addLoopStart(body);
3695 statement(ast->statement);
3696 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
3699 if (AST::cast<TrueLiteral *>(ast->expression)) {
3701 bytecodeGenerator->checkException();
3702 bytecodeGenerator->jump().link(body);
3703 }
else if (AST::cast<FalseLiteral *>(ast->expression)) {
3706 TailCallBlocker blockTailCalls(
this);
3707 bytecodeGenerator->checkException();
3708 condition(ast->expression, &body, &end,
false);
3716bool Codegen::visit(EmptyStatement *)
3721bool Codegen::visit(ExpressionStatement *ast)
3726 RegisterScope scope(
this);
3727 TailCallBlocker blockTailCalls(
this);
3729 if (requiresReturnValue) {
3730 Reference e = expression(ast->expression);
3733 (
void) e.storeOnStack(_returnAddress);
3735 statement(ast->expression);
3740bool Codegen::visit(ForEachStatement *ast)
3745 RegisterScope scope(
this);
3746 TailCallBlocker blockTailCalls(
this);
3748 Reference iterator = Reference::fromStackSlot(
this);
3749 Reference lhsValue = Reference::fromStackSlot(
this);
3754 RegisterScope innerScope(
this);
3755 ControlFlowBlock controlFlow(
this, ast);
3756 Reference expr = expression(ast->expression);
3760 expr.loadInAccumulator();
3761 Instruction::GetIterator iteratorObjInstr;
3762 iteratorObjInstr.iterator =
static_cast<
int>(ast->type);
3763 bytecodeGenerator->addInstruction(iteratorObjInstr);
3764 iterator.storeConsumeAccumulator();
3767 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3768 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3769 BytecodeGenerator::Label done;
3772 std::function<
void()> cleanup;
3773 if (ast->type == ForEachType::Of) {
3774 done = bytecodeGenerator->newLabel();
3775 cleanup = [iterator,
this, done]() {
3776 iterator.loadInAccumulator();
3777 Instruction::IteratorClose close;
3778 bytecodeGenerator->addInstruction(close);
3784 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
3785 bytecodeGenerator->addLoopStart(in);
3787 iterator.loadInAccumulator();
3788 Instruction::IteratorNext next;
3789 next.value = lhsValue.stackSlot();
3790 bytecodeGenerator->addJumpInstruction(next).link(done);
3794 RegisterScope innerScope(
this);
3795 ControlFlowBlock controlFlow(
this, ast);
3797 if (ExpressionNode *e = ast->lhs->expressionCast()) {
3798 if (AST::Pattern *p = e->patternCast()) {
3799 RegisterScope scope(
this);
3800 destructurePattern(p, lhsValue);
3802 Reference lhs = expression(e);
3805 if (!lhs.isLValue()) {
3806 throwReferenceError(e->firstSourceLocation(), QStringLiteral(
"Invalid left-hand side expression for 'in' expression"));
3809 lhs = lhs.asLValue();
3810 lhsValue.loadInAccumulator();
3811 lhs.storeConsumeAccumulator();
3813 }
else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
3814 initializeAndDestructureBindingElement(p, lhsValue,
true);
3821 blockTailCalls.unblock();
3822 statement(ast->statement);
3823 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3826 bytecodeGenerator->checkException();
3827 bytecodeGenerator->jump().link(in);
3839bool Codegen::visit(ForStatement *ast)
3844 RegisterScope scope(
this);
3845 TailCallBlocker blockTailCalls(
this);
3847 ControlFlowBlock controlFlow(
this, ast);
3849 if (ast->initialiser)
3850 statement(ast->initialiser);
3851 else if (ast->declarations)
3852 variableDeclarationList(ast->declarations);
3854 BytecodeGenerator::Label cond = bytecodeGenerator->label();
3855 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3856 BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
3857 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3859 ControlFlowLoop flow(
this, &end, &step);
3860 bytecodeGenerator->addLoopStart(cond);
3861 condition(ast->condition, &body, &end,
true);
3864 blockTailCalls.unblock();
3865 statement(ast->statement);
3866 blockTailCalls.reblock();
3867 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3870 if (_context->requiresExecutionContext) {
3871 Instruction::CloneBlockContext clone;
3872 bytecodeGenerator->addInstruction(clone);
3874 statement(ast->expression);
3875 bytecodeGenerator->checkException();
3876 bytecodeGenerator->jump().link(cond);
3883bool Codegen::visit(IfStatement *ast)
3888 RegisterScope scope(
this);
3889 TailCallBlocker blockTailCalls(
this);
3891 BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
3892 BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
3893 condition(ast->expression, &trueLabel, &falseLabel,
true);
3894 blockTailCalls.unblock();
3899 if (endsWithReturn(_module, ast)) {
3903 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
3915bool Codegen::visit(LabelledStatement *ast)
3920 RegisterScope scope(
this);
3923 ControlFlow *l = controlFlow;
3925 if (l->label() == ast->label) {
3926 QString error = QString(QStringLiteral(
"Label '%1' has already been declared")).arg(ast->label.toString());
3927 throwSyntaxError(ast->firstSourceLocation(), error);
3932 _labelledStatement = ast;
3934 if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
3935 AST::cast<AST::WhileStatement *>(ast->statement) ||
3936 AST::cast<AST::DoWhileStatement *>(ast->statement) ||
3937 AST::cast<AST::ForStatement *>(ast->statement) ||
3938 AST::cast<AST::ForEachStatement *>(ast->statement)) {
3939 statement(ast->statement);
3941 BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
3942 ControlFlowLoop flow(
this, &breakLabel);
3943 statement(ast->statement);
3950void Codegen::emitReturn(
const Reference &expr)
3952 ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
3953 if (target.linkLabel.isValid() && target.unwindLevel) {
3954 Q_ASSERT(_returnAddress >= 0);
3955 (
void) expr.storeOnStack(_returnAddress);
3956 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3958 expr.loadInAccumulator();
3959 bytecodeGenerator->addInstruction(Instruction::Ret());
3963bool Codegen::visit(ReturnStatement *ast)
3968 if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
3969 throwSyntaxError(ast->returnToken, QStringLiteral(
"Return statement outside of function"));
3973 if (ast->expression) {
3974 expr = expression(ast->expression);
3978 expr = Reference::fromConst(
this, Encode::undefined());
3986bool Codegen::visit(SwitchStatement *ast)
3991 if (requiresReturnValue)
3992 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
3994 RegisterScope scope(
this);
3995 TailCallBlocker blockTailCalls(
this);
3998 BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
4000 Reference lhs = expression(ast->expression);
4003 lhs = lhs.storeOnStack();
4005 ControlFlowBlock controlFlow(
this, ast->block);
4008 QHash<Node *, BytecodeGenerator::Label> blockMap;
4009 for (CaseClauses *it = ast->block->clauses; it; it = it->next)
4010 blockMap[it->clause] = bytecodeGenerator->newLabel();
4011 if (ast->block->defaultClause)
4012 blockMap[ast->block->defaultClause] = bytecodeGenerator->newLabel();
4013 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next)
4014 blockMap[it->clause] = bytecodeGenerator->newLabel();
4017 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
4018 CaseClause *clause = it->clause;
4019 Reference rhs = expression(clause->expression);
4022 rhs.loadInAccumulator();
4023 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
4026 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
4027 CaseClause *clause = it->clause;
4028 Reference rhs = expression(clause->expression);
4031 rhs.loadInAccumulator();
4032 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
4035 if (DefaultClause *defaultClause = ast->block->defaultClause)
4036 bytecodeGenerator->jump().link(blockMap.value(defaultClause));
4038 bytecodeGenerator->jump().link(switchEnd);
4040 ControlFlowLoop flow(
this, &switchEnd);
4042 insideSwitch =
true;
4043 blockTailCalls.unblock();
4044 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
4045 CaseClause *clause = it->clause;
4046 blockMap[clause].link();
4048 statementList(clause->statements);
4051 if (ast->block->defaultClause) {
4052 DefaultClause *clause = ast->block->defaultClause;
4053 blockMap[clause].link();
4055 statementList(clause->statements);
4058 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
4059 CaseClause *clause = it->clause;
4060 blockMap[clause].link();
4062 statementList(clause->statements);
4064 insideSwitch =
false;
4073bool Codegen::visit(ThrowStatement *ast)
4078 RegisterScope scope(
this);
4079 TailCallBlocker blockTailCalls(
this);
4081 Reference expr = expression(ast->expression);
4085 expr.loadInAccumulator();
4086 Instruction::ThrowException instr;
4087 bytecodeGenerator->addInstruction(instr);
4091void Codegen::handleTryCatch(TryStatement *ast)
4094 RegisterScope scope(
this);
4096 ControlFlowCatch catchFlow(
this, ast->catchExpression);
4097 RegisterScope scope(
this);
4098 TailCallBlocker blockTailCalls(
this);
4099 statement(ast->statement);
4103void Codegen::handleTryFinally(TryStatement *ast)
4105 RegisterScope scope(
this);
4106 const bool hasCatchBlock = ast->catchExpression;
4107 ControlFlowFinally finally(
this, ast->finallyExpression, hasCatchBlock);
4108 TailCallBlocker blockTailCalls(
this);
4110 if (ast->catchExpression) {
4111 handleTryCatch(ast);
4113 RegisterScope scope(
this);
4114 statement(ast->statement);
4118bool Codegen::visit(TryStatement *ast)
4123 RegisterScope scope(
this);
4125 if (ast->finallyExpression && ast->finallyExpression->statement) {
4126 handleTryFinally(ast);
4128 handleTryCatch(ast);
4134bool Codegen::visit(VariableStatement *ast)
4139 variableDeclarationList(ast->declarations);
4143bool Codegen::visit(WhileStatement *ast)
4148 if (AST::cast<FalseLiteral *>(ast->expression))
4151 RegisterScope scope(
this);
4153 BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
4154 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
4155 BytecodeGenerator::Label cond = bytecodeGenerator->label();
4156 ControlFlowLoop flow(
this, &end, &cond);
4157 bytecodeGenerator->addLoopStart(cond);
4159 bytecodeGenerator->checkException();
4161 if (!AST::cast<TrueLiteral *>(ast->expression)) {
4162 TailCallBlocker blockTailCalls(
this);
4163 condition(ast->expression, &start, &end,
true);
4167 statement(ast->statement);
4168 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->whileToken);
4169 bytecodeGenerator->jump().link(cond);
4175bool Codegen::visit(WithStatement *ast)
4180 RegisterScope scope(
this);
4181 TailCallBlocker blockTailCalls(
this);
4183 Reference src = expression(ast->expression);
4186 src = src.storeOnStack();
4187 src.loadInAccumulator();
4191 blockTailCalls.unblock();
4192 ControlFlowWith flow(
this);
4193 statement(ast->statement);
4200bool Codegen::visit(UiArrayBinding *)
4206bool Codegen::visit(UiObjectBinding *)
4212bool Codegen::visit(UiObjectDefinition *)
4218bool Codegen::visit(UiPublicMember *)
4224bool Codegen::visit(UiScriptBinding *)
4230bool Codegen::visit(UiSourceElement *)
4236bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(
const Reference &r,
const SourceLocation& loc)
4238 if (!_context->isStrict)
4240 bool isArgOrEval =
false;
4241 if (r.type == Reference::Name) {
4242 QString str = jsUnitGenerator->stringForIndex(r.nameAsIndex());
4243 if (str == QLatin1String(
"eval") || str == QLatin1String(
"arguments")) {
4246 }
else if (r.type == Reference::ScopedLocal || r.isRegister()) {
4247 isArgOrEval = r.isArgOrEval;
4250 throwSyntaxError(loc, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
4254void Codegen::throwError(ErrorType errorType,
const SourceLocation &loc,
const QString &detail)
4259 _errorType = errorType;
4260 _error.message = detail;
4264void Codegen::throwSyntaxError(
const SourceLocation &loc,
const QString &detail)
4266 throwError(SyntaxError, loc, detail);
4269void Codegen::throwReferenceError(
const SourceLocation &loc,
const QString &detail)
4271 throwError(ReferenceError, loc, detail);
4274QQmlJS::DiagnosticMessage Codegen::error()
const
4279QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
4280 bool generateUnitData)
4282 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
4283 new QV4::CompiledData::CompilationUnit(
4284 generateUnitData ? jsUnitGenerator->generateUnit() :
nullptr),
4285 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
4288QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
4289 bool debugMode,
const QString &url,
const QString &sourceCode,
4290 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
4293 QQmlJS::Lexer lexer(&ee);
4294 lexer.setCode(sourceCode, 1,
false);
4295 QQmlJS::Parser parser(&ee);
4297 const bool parsed = parser.parseModule();
4300 *diagnostics = parser.diagnosticMessages();
4303 return QQmlRefPointer<CompiledData::CompilationUnit>();
4305 QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
4310 diagnostics->clear();
4314 using namespace QV4::Compiler;
4315 Compiler::Module compilerModule(url, url, debugMode);
4316 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4317 compilerModule.sourceTimeStamp = sourceTimeStamp;
4318 JSUnitGenerator jsGenerator(&compilerModule);
4319 Codegen cg(&jsGenerator,
true);
4320 cg.generateFromModule(sourceCode, moduleNode, &compilerModule);
4321 if (cg.hasError()) {
4323 *diagnostics << cg.error();
4324 return QQmlRefPointer<CompiledData::CompilationUnit>();
4327 return cg.generateCompilationUnit();
4330const QV4::CompiledData::Unit *Codegen::generateNativeModuleUnitData(
4331 bool debugMode,
const QString &url,
const Value &value)
4333 using namespace QV4::Compiler;
4334 Compiler::Module compilerModule(url, url, debugMode);
4335 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4336 JSUnitGenerator jsGenerator(&compilerModule);
4337 Codegen cg(&jsGenerator,
true);
4338 cg.generateFromModule(value, &compilerModule);
4339 Q_ASSERT(!cg.hasError());
4340 return jsGenerator.generateUnit();
4345 VolatileMemoryLocations locs;
4360 bool visit(ArrayMemberExpression *)
override
4362 locs.setAllVolatile();
4366 bool visit(FieldMemberExpression *)
override
4368 locs.setAllVolatile();
4372 bool visit(PostIncrementExpression *e)
override
4374 collectIdentifiers(locs.specificLocations, e->base);
4378 bool visit(PostDecrementExpression *e)
override
4380 collectIdentifiers(locs.specificLocations, e->base);
4384 bool visit(PreIncrementExpression *e)
override
4386 collectIdentifiers(locs.specificLocations, e->expression);
4390 bool visit(PreDecrementExpression *e)
override
4392 collectIdentifiers(locs.specificLocations, e->expression);
4396 bool visit(BinaryExpression *e)
override
4399 case QSOperator::InplaceAnd:
4400 case QSOperator::InplaceSub:
4401 case QSOperator::InplaceDiv:
4402 case QSOperator::InplaceAdd:
4403 case QSOperator::InplaceLeftShift:
4404 case QSOperator::InplaceMod:
4405 case QSOperator::InplaceMul:
4406 case QSOperator::InplaceOr:
4407 case QSOperator::InplaceRightShift:
4408 case QSOperator::InplaceURightShift:
4409 case QSOperator::InplaceXor:
4410 collectIdentifiers(locs.specificLocations, e);
4424 void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
4425 class Collector:
public QQmlJS::AST::Visitor {
4427 QList<QStringView> &ids;
4428 VolatileMemoryLocationScanner *parent;
4431 Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
4432 QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
4435 bool visit(IdentifierExpression *ie) final {
4436 ids.append(ie->name);
4440 void throwRecursionDepthError() final
4442 parent->throwRecursionDepthError();
4445 Collector collector(ids,
this);
4446 node->accept(&collector);
4450Codegen::VolatileMemoryLocations
Codegen::scanVolatileMemoryLocations(AST::Node *ast)
4452 VolatileMemoryLocationScanner scanner(
this);
4453 return scanner.scan(ast);
4458 return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
4461bool Codegen::RValue::operator==(
const RValue &other)
const
4465 return other.isAccumulator();
4467 return other.isStackSlot() && theStackSlot == other.theStackSlot;
4469 return other.isConst() && constant == other.constant;
4475Codegen::RValue Codegen::RValue::storeOnStack()
const
4479 return RValue::fromStackSlot(codegen, Reference::fromAccumulator(codegen).storeOnStack().stackSlot());
4483 return RValue::fromStackSlot(codegen, Reference::storeConstOnStack(codegen, constant).stackSlot());
4489void Codegen::RValue::loadInAccumulator()
const
4496 return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
4498 return Reference::fromConst(codegen, constant).loadInAccumulator();
4505bool Codegen::Reference::operator==(
const Codegen::Reference &other)
const
4507 if (type != other.type)
4516 return property == other.property;
4518 return theStackSlot == other.theStackSlot;
4520 return index == other.index && scope == other.scope;
4522 return nameAsIndex() == other.nameAsIndex();
4524 return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
4526 return elementBase == other.elementBase && other.subscriptLoadedForCall
4527 ? (subscriptLoadedForCall && element == other.element)
4528 : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
4530 return index == other.index;
4532 return constant == other.constant;
4537Codegen::RValue Codegen::Reference::asRValue()
const
4543 return RValue::fromAccumulator(codegen);
4545 return RValue::fromStackSlot(codegen, stackSlot());
4547 return RValue::fromConst(codegen, constant);
4549 loadInAccumulator();
4550 return RValue::fromAccumulator(codegen);
4554Codegen::Reference Codegen::Reference::asLValue()
const
4561 codegen->throwSyntaxError(SourceLocation(), QStringLiteral(
"Super lvalues not implemented."));
4564 if (!propertyBase.isStackSlot()) {
4565 Reference r = *
this;
4566 r.propertyBase = propertyBase.storeOnStack();
4571 if (!elementSubscript.isStackSlot()) {
4572 Reference r = *
this;
4573 r.elementSubscript = elementSubscript.storeOnStack();
4582Codegen::Reference Codegen::Reference::storeConsumeAccumulator()
const
4588Codegen::Reference Codegen::Reference::baseObject()
const
4590 if (type == Reference::Member) {
4591 RValue rval = propertyBase;
4592 if (!rval.isValid())
4593 return Reference::fromConst(codegen, Encode::undefined());
4594 if (rval.isAccumulator())
4595 return Reference::fromAccumulator(codegen);
4596 if (rval.isStackSlot())
4597 return Reference::fromStackSlot(codegen, rval.stackSlot());
4599 return Reference::fromConst(codegen, rval.constantValue());
4601 }
else if (type == Reference::Subscript) {
4602 return Reference::fromStackSlot(codegen, elementBase.stackSlot());
4603 }
else if (type == Reference::SuperProperty) {
4604 return Reference::fromStackSlot(codegen, CallData::This);
4606 return Reference::fromConst(codegen, Encode::undefined());
4610Codegen::Reference Codegen::Reference::storeOnStack()
const
4611{
return doStoreOnStack(-1); }
4613void Codegen::Reference::storeOnStack(
int slotIndex)
const
4614{ doStoreOnStack(slotIndex); }
4616Codegen::Reference Codegen::Reference::doStoreOnStack(
int slotIndex)
const
4618 Q_ASSERT(isValid());
4620 if (isStackSlot() && slotIndex == -1 && !(stackSlotIsLocalOrArgument && isVolatile) && !requiresTDZCheck)
4623 if (isStackSlot() && !requiresTDZCheck) {
4624 Reference dest = Reference::fromStackSlot(codegen, slotIndex);
4625 Instruction::MoveReg move;
4626 move.srcReg = stackSlot();
4627 move.destReg = dest.stackSlot();
4628 codegen->bytecodeGenerator->addInstruction(move);
4632 Reference slot = Reference::fromStackSlot(codegen, slotIndex);
4634 Instruction::MoveConst move;
4635 move.constIndex = codegen->registerConstant(constant);
4636 move.destTemp = slot.stackSlot();
4637 codegen->bytecodeGenerator->addInstruction(move);
4639 loadInAccumulator();
4640 slot.storeConsumeAccumulator();
4645void Codegen::Reference::tdzCheck(
bool requiresCheck,
bool throwsReferenceError)
const {
4646 if (throwsReferenceError) {
4647 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4648 name + QStringLiteral(
" is not defined"));
4653 Instruction::DeadTemporalZoneCheck check;
4654 check.name = codegen->registerString(name);
4655 codegen->bytecodeGenerator->addInstruction(check);
4658void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot,
bool requiresCheck,
bool throwsReferenceError)
const {
4661 Instruction::LoadReg load;
4663 codegen->bytecodeGenerator->addInstruction(load);
4664 tdzCheck(
true, throwsReferenceError);
4670void Codegen::Reference::checkTDZBeforeAssignment()
const
4672 if (!requiresTDZCheck)
4675 if (type != StackSlot && type != ScopedLocal)
4678 loadInAccumulator();
4681Codegen::Reference Codegen::Reference::storeRetainAccumulator()
const
4683 if (storeWipesAccumulator()) {
4685 auto tmp = Reference::fromStackSlot(codegen);
4686 tmp.storeAccumulator();
4687 tmp.isReadonly = isReadonly;
4697bool Codegen::Reference::storeWipesAccumulator()
const
4716void Codegen::Reference::storeAccumulator()
const
4718 if (throwsReferenceError) {
4719 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4720 name + QStringLiteral(
" is not defined"));
4724 if (isReferenceToConst) {
4726 codegen->generateThrowException(QStringLiteral(
"TypeError"));
4732 Q_UNREACHABLE_RETURN();
4734 Instruction::StoreSuperProperty store;
4735 store.property = property.stackSlot();
4736 codegen->bytecodeGenerator->addInstruction(store);
4739 Instruction::StoreReg store;
4740 store.reg = theStackSlot;
4741 codegen->bytecodeGenerator->addInstruction(store);
4746 Instruction::StoreLocal store;
4747 store.index = index;
4748 codegen->bytecodeGenerator->addInstruction(store);
4750 Instruction::StoreScopedLocal store;
4751 store.index = index;
4752 store.scope = scope;
4753 codegen->bytecodeGenerator->addInstruction(store);
4758 Context *c = codegen->currentContext();
4760 Instruction::StoreNameStrict store;
4761 store.name = nameAsIndex();
4762 codegen->bytecodeGenerator->addInstruction(store);
4764 Instruction::StoreNameSloppy store;
4765 store.name = nameAsIndex();
4766 codegen->bytecodeGenerator->addInstruction(store);
4770 if (codegen->useFastLookups) {
4771 Instruction::SetLookup store;
4772 store.base = propertyBase.stackSlot();
4773 store.index = codegen->registerSetterLookup(propertyNameIndex);
4774 codegen->bytecodeGenerator->addInstruction(store);
4776 Instruction::StoreProperty store;
4777 store.base = propertyBase.stackSlot();
4778 store.name = propertyNameIndex;
4779 codegen->bytecodeGenerator->addInstruction(store);
4783 Instruction::StoreElement store;
4784 store.base = elementBase;
4785 store.index = elementSubscript.stackSlot();
4786 codegen->bytecodeGenerator->addInstruction(store);
4798void Codegen::Reference::loadInAccumulator()
const
4804 Q_UNREACHABLE_RETURN();
4806 tdzCheckStackSlot(property, subscriptRequiresTDZCheck,
false);
4807 Instruction::LoadSuperProperty load;
4808 load.property = property.stackSlot();
4809 codegen->bytecodeGenerator->addInstruction(load);
4813QT_WARNING_DISABLE_GCC(
"-Wmaybe-uninitialized")
4814 if (constant == Encode::null()) {
4815 Instruction::LoadNull load;
4816 codegen->bytecodeGenerator->addInstruction(load);
4817 }
else if (constant == Encode(
true)) {
4818 Instruction::LoadTrue load;
4819 codegen->bytecodeGenerator->addInstruction(load);
4820 }
else if (constant == Encode(
false)) {
4821 Instruction::LoadFalse load;
4822 codegen->bytecodeGenerator->addInstruction(load);
4823 }
else if (constant == Encode::undefined()) {
4824 Instruction::LoadUndefined load;
4825 codegen->bytecodeGenerator->addInstruction(load);
4827 StaticValue p = StaticValue::fromReturnedValue(constant);
4829 double d = p.asDouble();
4830 int i = QJSNumberCoercion::toInteger(d);
4831 if (d == i && (d != 0 || !std::signbit(d))) {
4833 Instruction::LoadZero load;
4834 codegen->bytecodeGenerator->addInstruction(load);
4837 Instruction::LoadInt load;
4838 load.value = StaticValue::fromReturnedValue(constant).toInt32();
4839 codegen->bytecodeGenerator->addInstruction(load);
4843 Instruction::LoadConst load;
4844 load.index = codegen->registerConstant(constant);
4845 codegen->bytecodeGenerator->addInstruction(load);
4850 Instruction::LoadReg load;
4851 load.reg = stackSlot();
4852 codegen->bytecodeGenerator->addInstruction(load);
4853 tdzCheck(requiresTDZCheck, throwsReferenceError);
4857 Instruction::LoadLocal load;
4859 codegen->bytecodeGenerator->addInstruction(load);
4861 Instruction::LoadScopedLocal load;
4864 codegen->bytecodeGenerator->addInstruction(load);
4866 tdzCheck(requiresTDZCheck, throwsReferenceError);
4873 if (name == QStringLiteral(
"undefined")) {
4874 Reference::fromConst(codegen, Encode::undefined()).loadInAccumulator();
4876 }
else if (name == QStringLiteral(
"Infinity")) {
4877 Reference::fromConst(codegen, Encode(qInf())).loadInAccumulator();
4879 }
else if (name == QStringLiteral(
"Nan")) {
4880 Reference::fromConst(codegen, Encode(qQNaN())).loadInAccumulator();
4885 if (sourceLocation.isValid())
4886 codegen->bytecodeGenerator->setLocation(sourceLocation);
4890 Instruction::LoadQmlContextPropertyLookup load;
4891 load.index = codegen->registerQmlContextPropertyGetterLookup(
4892 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4893 codegen->bytecodeGenerator->addInstruction(load);
4895 Instruction::LoadGlobalLookup load;
4896 load.index = codegen->registerGlobalGetterLookup(
4897 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4898 codegen->bytecodeGenerator->addInstruction(load);
4901 Instruction::LoadName load;
4902 load.name = nameAsIndex();
4903 codegen->bytecodeGenerator->addInstruction(load);
4907 propertyBase.loadInAccumulator();
4908 tdzCheck(requiresTDZCheck, throwsReferenceError);
4910 if (sourceLocation.isValid())
4911 codegen->bytecodeGenerator->setLocation(sourceLocation);
4913 if (codegen->useFastLookups) {
4914 if (optionalChainJumpsToPatch && isOptional) {
4915 auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
4916 codegen->registerGetterLookup(
4917 propertyNameIndex, JSUnitGenerator::LookupForStorage));
4918 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4920 Instruction::GetLookup load;
4921 load.index = codegen->registerGetterLookup(
4922 propertyNameIndex, JSUnitGenerator::LookupForStorage);
4923 codegen->bytecodeGenerator->addInstruction(load);
4926 if (optionalChainJumpsToPatch && isOptional) {
4927 auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
4928 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4930 Instruction::LoadProperty load;
4931 load.name = propertyNameIndex;
4932 codegen->bytecodeGenerator->addInstruction(load);
4937 Instruction::LoadImport load;
4939 codegen->bytecodeGenerator->addInstruction(load);
4940 tdzCheck(requiresTDZCheck, throwsReferenceError);
4943 tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
4944 elementSubscript.loadInAccumulator();
4945 tdzCheck(subscriptRequiresTDZCheck,
false);
4946 Instruction::LoadElement load;
4947 load.base = elementBase;
4948 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[]