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();
665void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e,
const Reference &base,
bool isDefinition)
667 Q_ASSERT(e->type == AST::PatternElement::Binding || e->type == AST::PatternElement::RestElement);
668 RegisterScope scope(
this);
669 Reference baseRef = (base.isAccumulator()) ? base.storeOnStack() : base;
670 Reference varToStore = targetForPatternElement(e);
672 varToStore.isReferenceToConst =
false;
676 if (e->typeAnnotation) {
677 throwSyntaxError(e->firstSourceLocation(),
678 QLatin1String(
"Type annotations on default parameters are not supported."));
681 if (e->initializer) {
682 if (!baseRef.isValid()) {
684 Reference expr = expression(e->initializer);
687 expr.loadInAccumulator();
688 varToStore.storeConsumeAccumulator();
689 }
else if (baseRef == varToStore) {
690 baseRef.loadInAccumulator();
691 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
692 Reference expr = expression(e->initializer);
697 expr.loadInAccumulator();
698 varToStore.storeConsumeAccumulator();
701 baseRef.loadInAccumulator();
702 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
703 Reference expr = expression(e->initializer);
708 expr.loadInAccumulator();
710 varToStore.storeConsumeAccumulator();
712 }
else if (baseRef != varToStore && baseRef.isValid()) {
713 baseRef.loadInAccumulator();
714 varToStore.storeConsumeAccumulator();
716 Pattern *p = e->destructuringPattern();
720 if (!varToStore.isStackSlot())
721 varToStore = varToStore.storeOnStack();
722 if (PatternElementList *l = e->elementList()) {
723 destructureElementList(varToStore, l, isDefinition);
724 }
else if (PatternPropertyList *p = e->propertyList()) {
725 destructurePropertyList(varToStore, p, isDefinition);
726 }
else if (e->bindingTarget) {
728 varToStore.loadInAccumulator();
729 Instruction::ToObject toObject;
730 bytecodeGenerator->addInstruction(toObject);
735Codegen::Reference Codegen::referenceForPropertyName(
const Codegen::Reference &object, AST::PropertyName *name)
737 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
740 Reference computedName = expression(cname->expression);
743 computedName = computedName.storeOnStack();
744 property = Reference::fromSubscript(object, computedName).asLValue();
746 QString propertyName = name->asString();
747 property = Reference::fromMember(object, propertyName);
752void Codegen::destructurePropertyList(
const Codegen::Reference &object, PatternPropertyList *bindingList,
bool isDefinition)
754 RegisterScope scope(
this);
756 object.loadInAccumulator();
757 Instruction::ThrowOnNullOrUndefined t;
758 bytecodeGenerator->addInstruction(t);
760 for (PatternPropertyList *it = bindingList; it; it = it->next) {
761 PatternProperty *p = it->property;
762 RegisterScope scope(
this);
763 Reference property = referenceForPropertyName(object, p->name);
766 initializeAndDestructureBindingElement(p, property, isDefinition);
772void Codegen::destructureElementList(
const Codegen::Reference &array, PatternElementList *bindingList,
bool isDefinition)
774 RegisterScope scope(
this);
776 Reference iterator = Reference::fromStackSlot(
this);
777 QVarLengthArray<Reference> iteratorValues;
780 array.loadInAccumulator();
781 Instruction::GetIterator iteratorObjInstr;
782 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
783 bytecodeGenerator->addInstruction(iteratorObjInstr);
784 iterator.storeConsumeAccumulator();
786 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
787 Reference needsClose = Reference::storeConstOnStack(
this, Encode(
false));
789 for (PatternElementList *p = bindingList; p; p = p->next) {
790 PatternElement *e = p->element;
791 for (Elision *elision = p->elision; elision; elision = elision->next) {
792 iterator.loadInAccumulator();
793 Instruction::IteratorNext next;
794 if (!ignored.isValid())
795 ignored = Reference::fromStackSlot(
this);
796 next.value = ignored.stackSlot();
797 bytecodeGenerator->addJumpInstruction(next).link(done);
803 if (e->type != PatternElement::RestElement) {
804 iterator.loadInAccumulator();
805 Instruction::IteratorNext next;
806 iteratorValues.push_back(Reference::fromStackSlot(
this));
807 next.value = iteratorValues.back().stackSlot();
808 bytecodeGenerator->addJumpInstruction(next).link(done);
816 Reference::fromConst(
this, Encode(
true)).storeOnStack(needsClose.stackSlot());
819 bytecodeGenerator->checkException();
822 ControlFlowUnwindCleanup flow(
this, [&]() {
823 BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
824 needsClose.loadInAccumulator();
825 bytecodeGenerator->jumpFalse().link(skipClose);
826 iterator.loadInAccumulator();
827 Instruction::IteratorClose close;
828 bytecodeGenerator->addInstruction(close);
832 auto it = iteratorValues.constBegin();
833 for (PatternElementList *p = bindingList; p; p = p->next) {
834 PatternElement *e = p->element;
839 if (e->type == PatternElement::RestElement) {
840 Q_ASSERT(it == iteratorValues.constEnd());
843 Reference::fromConst(
this, Encode(
false)).storeOnStack(needsClose.stackSlot());
845 iterator.loadInAccumulator();
846 bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
847 initializeAndDestructureBindingElement(
848 e, Reference::fromAccumulator(
this), isDefinition);
850 Q_ASSERT(it != iteratorValues.constEnd());
851 initializeAndDestructureBindingElement(e, *it++, isDefinition);
860void Codegen::destructurePattern(Pattern *p,
const Reference &rhs)
862 RegisterScope scope(
this);
863 if (
auto *o = AST::cast<ObjectPattern *>(p))
864 destructurePropertyList(rhs, o->properties);
865 else if (
auto *a = AST::cast<ArrayPattern *>(p))
866 destructureElementList(rhs, a->elements);
872bool Codegen::visit(ArgumentList *)
874 Q_UNREACHABLE_RETURN(
false);
877bool Codegen::visit(CaseBlock *)
879 Q_UNREACHABLE_RETURN(
false);
882bool Codegen::visit(CaseClause *)
884 Q_UNREACHABLE_RETURN(
false);
887bool Codegen::visit(CaseClauses *)
889 Q_UNREACHABLE_RETURN(
false);
892bool Codegen::visit(Catch *)
894 Q_UNREACHABLE_RETURN(
false);
897bool Codegen::visit(DefaultClause *)
899 Q_UNREACHABLE_RETURN(
false);
902bool Codegen::visit(Elision *)
904 Q_UNREACHABLE_RETURN(
false);
907bool Codegen::visit(Finally *)
909 Q_UNREACHABLE_RETURN(
false);
912bool Codegen::visit(FormalParameterList *)
914 Q_UNREACHABLE_RETURN(
false);
917bool Codegen::visit(Program *)
919 Q_UNREACHABLE_RETURN(
false);
922bool Codegen::visit(PatternElement *)
924 Q_UNREACHABLE_RETURN(
false);
927bool Codegen::visit(PatternElementList *)
929 Q_UNREACHABLE_RETURN(
false);
932bool Codegen::visit(PatternProperty *)
934 Q_UNREACHABLE_RETURN(
false);
937bool Codegen::visit(PatternPropertyList *)
939 Q_UNREACHABLE_RETURN(
false);
942bool Codegen::visit(ExportDeclaration *ast)
944 if (!ast->exportDefault)
947 TailCallBlocker blockTailCalls(
this);
948 Reference exportedValue;
950 if (
auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
952 visit(
static_cast<FunctionExpression*>(fdecl));
953 exportedValue = popResult();
954 }
else if (
auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
956 visit(
static_cast<ClassExpression*>(classDecl));
957 exportedValue = popResult();
958 }
else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
959 exportedValue = expression(expr);
964 exportedValue.loadInAccumulator();
966 const int defaultExportIndex = _context->locals.indexOf(_context->localNameForDefaultExport);
967 Q_ASSERT(defaultExportIndex != -1);
968 Reference defaultExportSlot = Reference::fromScopedLocal(
this, defaultExportIndex, 0);
969 defaultExportSlot.storeConsumeAccumulator();
974bool Codegen::visit(TypeAnnotation *ast)
976 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Type annotations are not supported (yet)."));
980bool Codegen::visit(StatementList *)
982 Q_UNREACHABLE_RETURN(
false);
985bool Codegen::visit(UiArrayMemberList *)
987 Q_UNREACHABLE_RETURN(
false);
990bool Codegen::visit(UiImport *)
992 Q_UNREACHABLE_RETURN(
false);
995bool Codegen::visit(UiHeaderItemList *)
997 Q_UNREACHABLE_RETURN(
false);
1000bool Codegen::visit(UiPragmaValueList *)
1002 Q_UNREACHABLE_RETURN(
false);
1005bool Codegen::visit(UiPragma *)
1007 Q_UNREACHABLE_RETURN(
false);
1010bool Codegen::visit(UiObjectInitializer *)
1012 Q_UNREACHABLE_RETURN(
false);
1015bool Codegen::visit(UiObjectMemberList *)
1017 Q_UNREACHABLE_RETURN(
false);
1020bool Codegen::visit(UiParameterList *)
1022 Q_UNREACHABLE_RETURN(
false);
1025bool Codegen::visit(UiProgram *)
1027 Q_UNREACHABLE_RETURN(
false);
1030bool Codegen::visit(UiQualifiedId *)
1032 Q_UNREACHABLE_RETURN(
false);
1035bool Codegen::visit(VariableDeclarationList *)
1037 Q_UNREACHABLE_RETURN(
false);
1040bool Codegen::visit(ClassExpression *ast)
1042 TailCallBlocker blockTailCalls(
this);
1044 Compiler::Class jsClass;
1045 jsClass.nameIndex = registerString(ast->name.toString());
1047 ClassElementList *constructor =
nullptr;
1048 int nComputedNames = 0;
1049 int nStaticComputedNames = 0;
1051 RegisterScope scope(
this);
1052 ControlFlowBlock controlFlow(
this, ast);
1054 for (
auto *member = ast->elements; member; member = member->next) {
1055 PatternProperty *p = member->property;
1056 FunctionExpression *f = p->initializer->asFunctionDefinition();
1058 AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
1061 if (member->isStatic)
1062 ++nStaticComputedNames;
1064 QString name = p->name->asString();
1065 uint nameIndex = cname ? UINT_MAX : registerString(name);
1066 Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
1067 if (p->type == PatternProperty::Getter)
1068 type = Compiler::Class::Method::Getter;
1069 else if (p->type == PatternProperty::Setter)
1070 type = Compiler::Class::Method::Setter;
1071 Compiler::Class::Method m{ nameIndex, type,
static_cast<uint>(defineFunction(name, f, f->formals, f->body)) };
1073 if (member->isStatic) {
1074 if (name == QStringLiteral(
"prototype")) {
1075 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a static method named 'prototype'."));
1078 jsClass.staticMethods << m;
1080 if (name == QStringLiteral(
"constructor")) {
1082 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a multiple constructors in a class."));
1085 if (m.type != Compiler::Class::Method::Regular) {
1086 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a getter or setter named 'constructor'."));
1089 constructor = member;
1090 jsClass.constructorIndex = m.functionIndex;
1094 jsClass.methods << m;
1098 int classIndex = _module->classes.size();
1099 _module->classes.append(jsClass);
1101 Reference heritage = Reference::fromStackSlot(
this);
1102 if (ast->heritage) {
1103 bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
1104 Reference r = expression(ast->heritage);
1107 r.storeOnStack(heritage.stackSlot());
1109 Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1110 heritage.storeConsumeAccumulator();
1113 int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
1114 int currentStaticName = computedNames;
1115 int currentNonStaticName = computedNames + nStaticComputedNames;
1117 for (
auto *member = ast->elements; member; member = member->next) {
1118 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
1121 RegisterScope scope(
this);
1122 bytecodeGenerator->setLocation(cname->firstSourceLocation());
1123 Reference computedName = expression(cname->expression);
1126 computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
1129 Instruction::CreateClass createClass;
1130 createClass.classIndex = classIndex;
1131 createClass.heritage = heritage.stackSlot();
1132 createClass.computedNames = computedNames;
1134 bytecodeGenerator->addInstruction(createClass);
1136 if (!ast->name.isEmpty()) {
1137 Reference ctor = referenceForName(ast->name.toString(),
true);
1138 ctor.isReferenceToConst =
false;
1139 (
void) ctor.storeRetainAccumulator();
1142 setExprResult(Reference::fromAccumulator(
this));
1146bool Codegen::visit(ClassDeclaration *ast)
1148 TailCallBlocker blockTailCalls(
this);
1149 Reference outerVar = referenceForName(ast->name.toString(),
true);
1150 visit(
static_cast<ClassExpression *>(ast));
1151 (
void) outerVar.storeRetainAccumulator();
1155bool Codegen::visit(CommaExpression *ast)
1160 TailCallBlocker blockTailCalls(
this);
1161 statement(ast->left);
1162 blockTailCalls.unblock();
1163 clearExprResultName();
1168bool Codegen::visit(ArrayPattern *ast)
1173 TailCallBlocker blockTailCalls(
this);
1175 PatternElementList *it = ast->elements;
1179 RegisterScope scope(
this);
1182 auto push = [
this, &argc, &args](AST::ExpressionNode *arg) {
1183 int temp = bytecodeGenerator->newRegister();
1187 auto c = Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue());
1188 (
void) c.storeOnStack(temp);
1190 RegisterScope scope(
this);
1191 Reference r = expression(arg);
1194 (
void) r.storeOnStack(temp);
1199 for (; it; it = it->next) {
1200 PatternElement *e = it->element;
1201 if (e && e->type == PatternElement::SpreadElement)
1203 for (Elision *elision = it->elision; elision; elision = elision->next)
1209 push(e->initializer);
1215 Q_ASSERT(argc == 0);
1219 Instruction::DefineArray call;
1221 call.args = Moth::StackSlot::createRegister(args);
1222 bytecodeGenerator->addInstruction(call);
1226 setExprResult(Reference::fromAccumulator(
this));
1229 Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
1231 RegisterScope scope(
this);
1232 Reference array = Reference::fromStackSlot(
this);
1233 array.storeConsumeAccumulator();
1234 Reference index = Reference::storeConstOnStack(
this, Encode(argc));
1236 auto pushAccumulator = [&]() {
1237 Reference slot = Reference::fromSubscript(array, index);
1238 slot.storeConsumeAccumulator();
1240 index.loadInAccumulator();
1241 Instruction::Increment inc = {};
1242 bytecodeGenerator->addInstruction(inc);
1243 index.storeConsumeAccumulator();
1247 for (Elision *elision = it->elision; elision; elision = elision->next) {
1248 Reference::fromConst(
1249 this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1259 if (it->element->type == PatternElement::SpreadElement) {
1260 RegisterScope scope(
this);
1262 Reference iterator = Reference::fromStackSlot(
this);
1263 Reference lhsValue = Reference::fromStackSlot(
this);
1268 RegisterScope innerScope(
this);
1269 Reference expr = expression(it->element->initializer);
1273 expr.loadInAccumulator();
1274 Instruction::GetIterator iteratorObjInstr;
1275 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
1276 bytecodeGenerator->addInstruction(iteratorObjInstr);
1277 iterator.storeConsumeAccumulator();
1280 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
1281 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
1282 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
1285 auto cleanup = [
this, iterator, done]() {
1286 iterator.loadInAccumulator();
1287 Instruction::IteratorClose close;
1288 bytecodeGenerator->addInstruction(close);
1291 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
1294 bytecodeGenerator->addLoopStart(in);
1295 iterator.loadInAccumulator();
1296 Instruction::IteratorNext next;
1297 next.value = lhsValue.stackSlot();
1298 bytecodeGenerator->addJumpInstruction(next).link(done);
1300 lhsValue.loadInAccumulator();
1303 bytecodeGenerator->checkException();
1304 bytecodeGenerator->jump().link(in);
1308 RegisterScope innerScope(
this);
1309 Reference expr = expression(it->element->initializer);
1313 expr.loadInAccumulator();
1320 array.loadInAccumulator();
1321 setExprResult(Reference::fromAccumulator(
this));
1326bool Codegen::visit(ArrayMemberExpression *ast)
1331 const bool isTailOfChain = traverseOptionalChain(ast);
1333 TailCallBlocker blockTailCalls(
this);
1334 Reference base = expression(ast->base);
1338 auto writeSkip = [&]() {
1339 base.loadInAccumulator();
1340 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
1341 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
1342 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
1345 if (base.isSuper()) {
1346 auto e = expression(ast->expression);
1349 Reference index = e.storeOnStack();
1350 optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
1353 base = base.storeOnStack();
1356 if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
1357 QString s = str->value.toString();
1358 uint arrayIndex = stringToArrayIndex(s);
1359 if (arrayIndex == UINT_MAX) {
1360 auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
1362 &m_optionalChainsStates->top().jumpsToPatch);
1364 optionalChainFinalizer(ref, isTailOfChain);
1368 if (ast->isOptional)
1371 Reference index = Reference::fromConst(
this, QV4::Encode(arrayIndex));
1372 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1377 if (ast->isOptional)
1380 Reference index = expression(ast->expression);
1385 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1391 switch ((QSOperator::Op) op) {
1392 case QSOperator::InplaceAnd:
return QSOperator::BitAnd;
1393 case QSOperator::InplaceSub:
return QSOperator::Sub;
1394 case QSOperator::InplaceDiv:
return QSOperator::Div;
1395 case QSOperator::InplaceAdd:
return QSOperator::Add;
1396 case QSOperator::InplaceLeftShift:
return QSOperator::LShift;
1397 case QSOperator::InplaceMod:
return QSOperator::Mod;
1398 case QSOperator::InplaceExp:
return QSOperator::Exp;
1399 case QSOperator::InplaceMul:
return QSOperator::Mul;
1400 case QSOperator::InplaceOr:
return QSOperator::BitOr;
1401 case QSOperator::InplaceRightShift:
return QSOperator::RShift;
1402 case QSOperator::InplaceURightShift:
return QSOperator::URShift;
1403 case QSOperator::InplaceXor:
return QSOperator::BitXor;
1404 default:
return QSOperator::Invalid;
1408bool Codegen::visit(BinaryExpression *ast)
1413 TailCallBlocker blockTailCalls(
this);
1415 if (ast->op == QSOperator::And) {
1416 if (exprAccept(cx)) {
1417 auto iftrue = bytecodeGenerator->newLabel();
1418 condition(ast->left, &iftrue, currentExpr().iffalse(),
true);
1420 blockTailCalls.unblock();
1421 const Result &expr = currentExpr();
1422 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1424 auto iftrue = bytecodeGenerator->newLabel();
1425 auto endif = bytecodeGenerator->newLabel();
1427 Reference left = expression(ast->left);
1430 left.loadInAccumulator();
1432 bytecodeGenerator->setLocation(ast->operatorToken);
1433 bytecodeGenerator->jumpFalse().link(endif);
1436 blockTailCalls.unblock();
1437 Reference right = expression(ast->right);
1440 right.loadInAccumulator();
1444 setExprResult(Reference::fromAccumulator(
this));
1447 }
else if (ast->op == QSOperator::Or) {
1448 if (exprAccept(cx)) {
1449 auto iffalse = bytecodeGenerator->newLabel();
1450 condition(ast->left, currentExpr().iftrue(), &iffalse,
false);
1452 const Result &expr = currentExpr();
1453 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1455 auto iffalse = bytecodeGenerator->newLabel();
1456 auto endif = bytecodeGenerator->newLabel();
1458 Reference left = expression(ast->left);
1461 left.loadInAccumulator();
1463 bytecodeGenerator->setLocation(ast->operatorToken);
1464 bytecodeGenerator->jumpTrue().link(endif);
1467 blockTailCalls.unblock();
1468 Reference right = expression(ast->right);
1471 right.loadInAccumulator();
1475 setExprResult(Reference::fromAccumulator(
this));
1478 }
else if (ast->op == QSOperator::Coalesce) {
1480 Reference left = expression(ast->left);
1484 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
1486 Instruction::CmpEqNull cmp;
1488 left = left.storeOnStack();
1489 left.loadInAccumulator();
1490 bytecodeGenerator->addInstruction(cmp);
1492 bytecodeGenerator->jumpTrue().link(iftrue);
1494 blockTailCalls.unblock();
1496 left.loadInAccumulator();
1497 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
1500 Reference right = expression(ast->right);
1506 right.loadInAccumulator();
1508 setExprResult(Reference::fromAccumulator(
this));
1511 }
else if (ast->op == QSOperator::Assign) {
1512 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1513 if (AST::Pattern *p = ast->left->patternCast()) {
1514 RegisterScope scope(
this);
1515 Reference right = expression(ast->right);
1518 right = right.storeOnStack();
1519 destructurePattern(p, right);
1520 if (!exprAccept(nx)) {
1521 right.loadInAccumulator();
1522 setExprResult(Reference::fromAccumulator(
this));
1526 Reference left = expression(ast->left);
1530 if (!left.isLValue()) {
1531 throwReferenceError(ast->operatorToken, QStringLiteral(
"left-hand side of assignment operator is not an lvalue"));
1534 left = left.asLValue();
1535 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1537 blockTailCalls.unblock();
1538 Reference r = expression(ast->right);
1541 r.loadInAccumulator();
1543 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1545 setExprResult(left.storeConsumeAccumulator());
1547 setExprResult(left.storeRetainAccumulator());
1551 Reference left = expression(ast->left);
1556 case QSOperator::Or:
1557 case QSOperator::And:
1558 case QSOperator::Assign:
1562 case QSOperator::InplaceAnd:
1563 case QSOperator::InplaceSub:
1564 case QSOperator::InplaceDiv:
1565 case QSOperator::InplaceAdd:
1566 case QSOperator::InplaceLeftShift:
1567 case QSOperator::InplaceMod:
1568 case QSOperator::InplaceExp:
1569 case QSOperator::InplaceMul:
1570 case QSOperator::InplaceOr:
1571 case QSOperator::InplaceRightShift:
1572 case QSOperator::InplaceURightShift:
1573 case QSOperator::InplaceXor: {
1574 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1577 if (!left.isLValue()) {
1578 throwSyntaxError(ast->operatorToken, QStringLiteral(
"left-hand side of inplace operator is not an lvalue"));
1581 left = left.asLValue();
1583 Reference tempLeft = left.storeOnStack();
1584 Reference right = expression(ast->right);
1589 binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
1590 setExprResult(left.storeRetainAccumulator());
1595 case QSOperator::BitAnd:
1596 case QSOperator::BitOr:
1597 case QSOperator::BitXor:
1598 if (left.isConstant()) {
1599 Reference right = expression(ast->right);
1602 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), right, left));
1606 case QSOperator::In:
1607 case QSOperator::InstanceOf:
1608 case QSOperator::As:
1609 case QSOperator::Equal:
1610 case QSOperator::NotEqual:
1611 case QSOperator::Ge:
1612 case QSOperator::Gt:
1613 case QSOperator::Le:
1614 case QSOperator::Lt:
1615 case QSOperator::StrictEqual:
1616 case QSOperator::StrictNotEqual:
1617 case QSOperator::Add:
1618 case QSOperator::Div:
1619 case QSOperator::Exp:
1620 case QSOperator::Mod:
1621 case QSOperator::Mul:
1622 case QSOperator::Sub:
1623 case QSOperator::LShift:
1624 case QSOperator::RShift:
1625 case QSOperator::URShift: {
1627 if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
1629 right = exprResult();
1631 left = left.storeOnStack();
1632 right = expression(ast->right);
1637 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), left, right));
1646Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
1649 auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
1650 bytecodeGenerator->setLocation(loc);
1652 case QSOperator::Add: {
1653 left = left.storeOnStack();
1654 right.loadInAccumulator();
1655 Instruction::Add add;
1656 add.lhs = left.stackSlot();
1657 bytecodeGenerator->addInstruction(add);
1660 case QSOperator::Sub: {
1661 if (right.isConstant() && right.constant == Encode(
int(1))) {
1662 left.loadInAccumulator();
1663 Instruction::Decrement dec = {};
1664 bytecodeGenerator->addInstruction(dec);
1666 left = left.storeOnStack();
1667 right.loadInAccumulator();
1668 Instruction::Sub sub;
1669 sub.lhs = left.stackSlot();
1670 bytecodeGenerator->addInstruction(sub);
1674 case QSOperator::Exp: {
1675 left = left.storeOnStack();
1676 right.loadInAccumulator();
1677 Instruction::Exp exp;
1678 exp.lhs = left.stackSlot();
1679 bytecodeGenerator->addInstruction(exp);
1682 case QSOperator::Mul: {
1683 left = left.storeOnStack();
1684 right.loadInAccumulator();
1685 Instruction::Mul mul;
1686 mul.lhs = left.stackSlot();
1687 bytecodeGenerator->addInstruction(mul);
1690 case QSOperator::Div: {
1691 left = left.storeOnStack();
1692 right.loadInAccumulator();
1693 Instruction::Div div;
1694 div.lhs = left.stackSlot();
1695 bytecodeGenerator->addInstruction(div);
1698 case QSOperator::Mod: {
1699 left = left.storeOnStack();
1700 right.loadInAccumulator();
1701 Instruction::Mod mod;
1702 mod.lhs = left.stackSlot();
1703 bytecodeGenerator->addInstruction(mod);
1706 case QSOperator::BitAnd:
1707 if (right.isConstant()) {
1708 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1709 if (left.isConstant()) {
1710 int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
1711 return Reference::fromConst(
this, Encode(result));
1713 left.loadInAccumulator();
1714 Instruction::BitAndConst bitAnd;
1715 bitAnd.rhs = rightAsInt;
1716 bytecodeGenerator->addInstruction(bitAnd);
1718 right.loadInAccumulator();
1719 Instruction::BitAnd bitAnd;
1720 bitAnd.lhs = left.stackSlot();
1721 bytecodeGenerator->addInstruction(bitAnd);
1724 case QSOperator::BitOr:
1725 if (right.isConstant()) {
1726 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1727 if (left.isConstant()) {
1728 int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
1729 return Reference::fromConst(
this, Encode(result));
1731 left.loadInAccumulator();
1732 Instruction::BitOrConst bitOr;
1733 bitOr.rhs = rightAsInt;
1734 bytecodeGenerator->addInstruction(bitOr);
1736 right.loadInAccumulator();
1737 Instruction::BitOr bitOr;
1738 bitOr.lhs = left.stackSlot();
1739 bytecodeGenerator->addInstruction(bitOr);
1742 case QSOperator::BitXor:
1743 if (right.isConstant()) {
1744 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1745 if (left.isConstant()) {
1746 int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
1747 return Reference::fromConst(
this, Encode(result));
1749 left.loadInAccumulator();
1750 Instruction::BitXorConst bitXor;
1751 bitXor.rhs = rightAsInt;
1752 bytecodeGenerator->addInstruction(bitXor);
1754 right.loadInAccumulator();
1755 Instruction::BitXor bitXor;
1756 bitXor.lhs = left.stackSlot();
1757 bytecodeGenerator->addInstruction(bitXor);
1760 case QSOperator::URShift:
1761 if (right.isConstant()) {
1762 left.loadInAccumulator();
1763 Instruction::UShrConst ushr;
1764 ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1765 bytecodeGenerator->addInstruction(ushr);
1767 right.loadInAccumulator();
1768 Instruction::UShr ushr;
1769 ushr.lhs = left.stackSlot();
1770 bytecodeGenerator->addInstruction(ushr);
1773 case QSOperator::RShift:
1774 if (right.isConstant()) {
1775 left.loadInAccumulator();
1776 Instruction::ShrConst shr;
1777 shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1778 bytecodeGenerator->addInstruction(shr);
1780 right.loadInAccumulator();
1781 Instruction::Shr shr;
1782 shr.lhs = left.stackSlot();
1783 bytecodeGenerator->addInstruction(shr);
1786 case QSOperator::LShift:
1787 if (right.isConstant()) {
1788 left.loadInAccumulator();
1789 Instruction::ShlConst shl;
1790 shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1791 bytecodeGenerator->addInstruction(shl);
1793 right.loadInAccumulator();
1794 Instruction::Shl shl;
1795 shl.lhs = left.stackSlot();
1796 bytecodeGenerator->addInstruction(shl);
1799 case QSOperator::InstanceOf: {
1800 Instruction::CmpInstanceOf binop;
1801 left = left.storeOnStack();
1802 right.loadInAccumulator();
1803 binop.lhs = left.stackSlot();
1804 bytecodeGenerator->addInstruction(binop);
1807 case QSOperator::As: {
1809 left = left.storeOnStack();
1810 right.loadInAccumulator();
1811 as.lhs = left.stackSlot();
1812 bytecodeGenerator->addInstruction(as);
1815 case QSOperator::In: {
1816 Instruction::CmpIn binop;
1817 left = left.storeOnStack();
1818 right.loadInAccumulator();
1819 binop.lhs = left.stackSlot();
1820 bytecodeGenerator->addInstruction(binop);
1823 case QSOperator::StrictEqual: {
1825 return jumpBinop(oper, left, right);
1827 Instruction::CmpStrictEqual cmp;
1828 left = left.storeOnStack();
1829 right.loadInAccumulator();
1830 cmp.lhs = left.stackSlot();
1831 bytecodeGenerator->addInstruction(cmp);
1834 case QSOperator::StrictNotEqual: {
1836 return jumpBinop(oper, left, right);
1838 Instruction::CmpStrictNotEqual cmp;
1839 left = left.storeOnStack();
1840 right.loadInAccumulator();
1841 cmp.lhs = left.stackSlot();
1842 bytecodeGenerator->addInstruction(cmp);
1845 case QSOperator::Equal: {
1847 return jumpBinop(oper, left, right);
1849 Instruction::CmpEq cmp;
1850 left = left.storeOnStack();
1851 right.loadInAccumulator();
1852 cmp.lhs = left.stackSlot();
1853 bytecodeGenerator->addInstruction(cmp);
1856 case QSOperator::NotEqual: {
1858 return jumpBinop(oper, left, right);
1860 Instruction::CmpNe cmp;
1861 left = left.storeOnStack();
1862 right.loadInAccumulator();
1863 cmp.lhs = left.stackSlot();
1864 bytecodeGenerator->addInstruction(cmp);
1867 case QSOperator::Gt: {
1869 return jumpBinop(oper, left, right);
1871 Instruction::CmpGt cmp;
1872 left = left.storeOnStack();
1873 right.loadInAccumulator();
1874 cmp.lhs = left.stackSlot();
1875 bytecodeGenerator->addInstruction(cmp);
1878 case QSOperator::Ge: {
1880 return jumpBinop(oper, left, right);
1882 Instruction::CmpGe cmp;
1883 left = left.storeOnStack();
1884 right.loadInAccumulator();
1885 cmp.lhs = left.stackSlot();
1886 bytecodeGenerator->addInstruction(cmp);
1889 case QSOperator::Lt: {
1891 return jumpBinop(oper, left, right);
1893 Instruction::CmpLt cmp;
1894 left = left.storeOnStack();
1895 right.loadInAccumulator();
1896 cmp.lhs = left.stackSlot();
1897 bytecodeGenerator->addInstruction(cmp);
1900 case QSOperator::Le:
1902 return jumpBinop(oper, left, right);
1904 Instruction::CmpLe cmp;
1905 left = left.storeOnStack();
1906 right.loadInAccumulator();
1907 cmp.lhs = left.stackSlot();
1908 bytecodeGenerator->addInstruction(cmp);
1914 return Reference::fromAccumulator(
this);
1917Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
1920 if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
1922 if (left.isConstant() && !right.isConstant())
1925 if (right.isConstant()) {
1926 StaticValue c = StaticValue::fromReturnedValue(right.constant);
1927 if (c.isNull() || c.isUndefined()) {
1928 left.loadInAccumulator();
1929 if (oper == QSOperator::Equal) {
1930 Instruction::CmpEqNull cmp;
1931 bytecodeGenerator->addInstruction(cmp);
1934 }
else if (oper == QSOperator::NotEqual) {
1935 Instruction::CmpNeNull cmp;
1936 bytecodeGenerator->addInstruction(cmp);
1940 }
else if (c.isInt32()) {
1941 left.loadInAccumulator();
1942 if (oper == QSOperator::Equal) {
1943 Instruction::CmpEqInt cmp;
1944 cmp.lhs = c.int_32();
1945 bytecodeGenerator->addInstruction(cmp);
1948 }
else if (oper == QSOperator::NotEqual) {
1949 Instruction::CmpNeInt cmp;
1950 cmp.lhs = c.int_32();
1951 bytecodeGenerator->addInstruction(cmp);
1960 left = left.storeOnStack();
1961 right.loadInAccumulator();
1964 case QSOperator::StrictEqual: {
1965 Instruction::CmpStrictEqual cmp;
1966 cmp.lhs = left.stackSlot();
1967 bytecodeGenerator->addInstruction(cmp);
1971 case QSOperator::StrictNotEqual: {
1972 Instruction::CmpStrictNotEqual cmp;
1973 cmp.lhs = left.stackSlot();
1974 bytecodeGenerator->addInstruction(cmp);
1978 case QSOperator::Equal: {
1979 Instruction::CmpEq cmp;
1980 cmp.lhs = left.stackSlot();
1981 bytecodeGenerator->addInstruction(cmp);
1985 case QSOperator::NotEqual: {
1986 Instruction::CmpNe cmp;
1987 cmp.lhs = left.stackSlot();
1988 bytecodeGenerator->addInstruction(cmp);
1992 case QSOperator::Gt: {
1993 Instruction::CmpGt cmp;
1994 cmp.lhs = left.stackSlot();
1995 bytecodeGenerator->addInstruction(cmp);
1999 case QSOperator::Ge: {
2000 Instruction::CmpGe cmp;
2001 cmp.lhs = left.stackSlot();
2002 bytecodeGenerator->addInstruction(cmp);
2006 case QSOperator::Lt: {
2007 Instruction::CmpLt cmp;
2008 cmp.lhs = left.stackSlot();
2009 bytecodeGenerator->addInstruction(cmp);
2013 case QSOperator::Le: {
2014 Instruction::CmpLe cmp;
2015 cmp.lhs = left.stackSlot();
2016 bytecodeGenerator->addInstruction(cmp);
2026Codegen::Reference Codegen::loadSubscriptForCall(
const Codegen::Reference &base)
2030 base.elementSubscript.loadInAccumulator();
2031 Codegen::Instruction::LoadElement load;
2032 load.base = base.elementBase;
2033 bytecodeGenerator->addInstruction(load);
2034 return Reference::fromAccumulator(
this);
2037bool Codegen::visit(CallExpression *ast)
2042 const bool isTailOfChain = traverseOptionalChain(ast);
2044 RegisterScope scope(
this);
2045 TailCallBlocker blockTailCalls(
this);
2047 Reference expr = expression(ast->base);
2048 Reference base = expr;
2052 switch (base.type) {
2053 case Reference::Member:
2054 base = base.asLValue();
2056 case Reference::Subscript:
2057 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2058 base.subscriptLoadedForCall =
true;
2060 case Reference::Name:
2062 case Reference::Super:
2063 handleConstruct(base, ast->arguments);
2065 case Reference::SuperProperty:
2068 base = base.storeOnStack();
2072 if (expr.hasSavedCallBaseSlot) {
2074 base.hasSavedCallBaseSlot =
true;
2075 base.savedCallBaseSlot = expr.savedCallBaseSlot;
2076 base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
2079 int thisObject = bytecodeGenerator->newRegister();
2080 int functionObject = bytecodeGenerator->newRegister();
2082 if (ast->isOptional || m_optionalChainsStates->top().actuallyHasOptionals) {
2083 base.loadInAccumulator();
2084 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2085 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2086 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2089 auto calldata = pushArgs(ast->arguments);
2093 blockTailCalls.unblock();
2094 if (calldata.hasSpread || _tailCallsAreAllowed) {
2095 Reference baseObject = base.baseObject();
2096 if (!baseObject.isStackSlot()) {
2097 baseObject.storeOnStack(thisObject);
2098 baseObject = Reference::fromStackSlot(
this, thisObject);
2101 const int func = [&]() {
2102 if (base.type == Reference::Subscript)
2103 return base.element;
2105 if (!base.isStackSlot()) {
2106 base.storeOnStack(functionObject);
2107 base = Reference::fromStackSlot(
this, functionObject);
2110 return base.stackSlot();
2113 if (calldata.hasSpread) {
2114 Instruction::CallWithSpread call;
2116 call.thisObject = baseObject.stackSlot();
2117 call.argc = calldata.argc;
2118 call.argv = calldata.argv;
2119 bytecodeGenerator->addInstruction(call);
2121 Instruction::TailCall call;
2123 call.thisObject = baseObject.stackSlot();
2124 call.argc = calldata.argc;
2125 call.argv = calldata.argv;
2126 bytecodeGenerator->addInstruction(call);
2129 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2133 handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
2134 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2138void Codegen::endVisit(CallExpression *ast)
2140 m_seenOptionalChainNodes.remove(ast);
2143void Codegen::handleCall(Reference &base, Arguments calldata,
int slotForFunction,
int slotForThisObject,
bool optional)
2145 if (base.sourceLocation.isValid())
2146 bytecodeGenerator->setLocation(base.sourceLocation);
2149 if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
2150 if (useFastLookups) {
2151 Instruction::CallPropertyLookup call;
2152 if (base.hasSavedCallBaseSlot) {
2153 call.base = base.savedCallBaseSlot;
2154 call.lookupIndex = registerGetterLookup(
2155 base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
2157 call.base = base.propertyBase.stackSlot();
2158 call.lookupIndex = registerGetterLookup(
2159 base.propertyNameIndex, JSUnitGenerator::LookupForCall);
2161 call.argc = calldata.argc;
2162 call.argv = calldata.argv;
2163 bytecodeGenerator->addInstruction(call);
2165 Instruction::CallProperty call;
2166 if (base.hasSavedCallBaseSlot) {
2167 call.base = base.savedCallBaseSlot;
2168 call.name = base.savedCallPropertyNameIndex;
2170 call.base = base.propertyBase.stackSlot();
2171 call.name = base.propertyNameIndex;
2173 call.argc = calldata.argc;
2174 call.argv = calldata.argv;
2175 bytecodeGenerator->addInstruction(call);
2177 }
else if (base.type == Reference::Subscript) {
2178 Instruction::CallWithReceiver call;
2179 call.thisObject = base.elementBase.stackSlot();
2180 call.name = base.element;
2181 call.argc = calldata.argc;
2182 call.argv = calldata.argv;
2183 bytecodeGenerator->addInstruction(call);
2184 }
else if (base.type == Reference::Name) {
2185 if (base.name == QStringLiteral(
"eval") && !optional) {
2186 Instruction::CallPossiblyDirectEval call;
2187 call.argc = calldata.argc;
2188 call.argv = calldata.argv;
2189 bytecodeGenerator->addInstruction(call);
2190 }
else if (useFastLookups && base.global) {
2191 if (base.qmlGlobal) {
2192 Instruction::CallQmlContextPropertyLookup call;
2193 call.index = registerQmlContextPropertyGetterLookup(
2194 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2195 call.argc = calldata.argc;
2196 call.argv = calldata.argv;
2197 bytecodeGenerator->addInstruction(call);
2199 Instruction::CallGlobalLookup call;
2200 call.index = registerGlobalGetterLookup(
2201 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2202 call.argc = calldata.argc;
2203 call.argv = calldata.argv;
2204 bytecodeGenerator->addInstruction(call);
2207 Instruction::CallName call;
2208 call.name = base.nameAsIndex();
2209 call.argc = calldata.argc;
2210 call.argv = calldata.argv;
2211 bytecodeGenerator->addInstruction(call);
2213 }
else if (base.type == Reference::SuperProperty) {
2214 Reference receiver = base.baseObject();
2215 if (!base.isStackSlot()) {
2216 base.storeOnStack(slotForFunction);
2217 base = Reference::fromStackSlot(
this, slotForFunction);
2219 if (!receiver.isStackSlot()) {
2220 receiver.storeOnStack(slotForThisObject);
2221 receiver = Reference::fromStackSlot(
this, slotForThisObject);
2223 Instruction::CallWithReceiver call;
2224 call.name = base.stackSlot();
2225 call.thisObject = receiver.stackSlot();
2226 call.argc = calldata.argc;
2227 call.argv = calldata.argv;
2228 bytecodeGenerator->addInstruction(call);
2230 Q_ASSERT(base.isStackSlot());
2231 Instruction::CallValue call;
2232 call.name = base.stackSlot();
2233 call.argc = calldata.argc;
2234 call.argv = calldata.argv;
2235 bytecodeGenerator->addInstruction(call);
2239Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
2241 bool hasSpread =
false;
2243 for (ArgumentList *it = args; it; it = it->next) {
2244 if (it->spreadToken.isValid()) {
2252 return { 0, 0,
false };
2254 int calldata = bytecodeGenerator->newRegisterArray(argc);
2257 for (ArgumentList *it = args; it; it = it->next) {
2258 if (it->spreadToken.isValid()) {
2259 Reference::fromConst(
2261 StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
2264 RegisterScope scope(
this);
2265 Reference e = expression(it->expression);
2268 if (!argc && !it->next && !hasSpread) {
2270 if (e.isStackSlot()) {
2272 return { 1, e.stackSlot(), hasSpread };
2275 (
void) e.storeOnStack(calldata + argc);
2279 return { argc, calldata, hasSpread };
2282Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
2285 for (TemplateLiteral *it = args; it; it = it->next)
2289 return { 0, 0,
false };
2291 int calldata = bytecodeGenerator->newRegisterArray(argc);
2294 for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
2295 RegisterScope scope(
this);
2296 Reference e = expression(it->expression);
2299 (
void) e.storeOnStack(calldata + argc);
2303 return { argc, calldata,
false };
2306bool Codegen::visit(ConditionalExpression *ast)
2311 RegisterScope scope(
this);
2312 TailCallBlocker blockTailCalls(
this);
2314 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
2315 BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
2316 condition(ast->expression, &iftrue, &iffalse,
true);
2318 blockTailCalls.unblock();
2321 Reference ok = expression(ast->ok);
2324 ok.loadInAccumulator();
2325 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
2328 Reference ko = expression(ast->ko);
2333 ko.loadInAccumulator();
2336 setExprResult(Reference::fromAccumulator(
this));
2341bool Codegen::visit(DeleteExpression *ast)
2346 const bool isTailOfChain = traverseOptionalChain(ast);
2348 RegisterScope scope(
this);
2349 TailCallBlocker blockTailCalls(
this);
2350 Reference expr = expression(ast->expression);
2354 const bool chainActuallyHasOptionals = m_optionalChainsStates->top().actuallyHasOptionals;
2355 if (chainActuallyHasOptionals)
2356 Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
2358 switch (expr.type) {
2359 case Reference::SuperProperty:
2362 case Reference::StackSlot:
2363 if (!expr.stackSlotIsLocalOrArgument)
2366 case Reference::ScopedLocal:
2368 if (_context->isStrict) {
2369 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2372 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2374 case Reference::Name: {
2375 if (_context->isStrict) {
2376 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2379 Instruction::DeleteName del;
2380 del.name = expr.nameAsIndex();
2381 bytecodeGenerator->addInstruction(del);
2382 setExprResult(Reference::fromAccumulator(
this));
2385 case Reference::Member: {
2387 expr = expr.asLValue();
2389 if (chainActuallyHasOptionals) {
2390 expr.loadInAccumulator();
2391 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2392 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2393 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2396 Instruction::LoadRuntimeString instr;
2397 instr.stringId = expr.propertyNameIndex;
2398 bytecodeGenerator->addInstruction(instr);
2399 Reference index = Reference::fromStackSlot(
this);
2400 index.storeConsumeAccumulator();
2401 Instruction::DeleteProperty del;
2402 del.base = expr.propertyBase.stackSlot();
2403 del.index = index.stackSlot();
2404 bytecodeGenerator->addInstruction(del);
2405 auto ref = Reference::fromAccumulator(
this);
2407 optionalChainFinalizer(ref, isTailOfChain,
true);
2410 case Reference::Subscript: {
2412 expr = expr.asLValue();
2414 if (chainActuallyHasOptionals) {
2415 expr.loadInAccumulator();
2416 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2417 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2418 m_optionalChainsStates->top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2421 Instruction::DeleteProperty del;
2422 del.base = expr.elementBase;
2423 del.index = expr.elementSubscript.stackSlot();
2424 bytecodeGenerator->addInstruction(del);
2425 auto ref = Reference::fromAccumulator(
this);
2427 optionalChainFinalizer(ref, isTailOfChain,
true);
2434 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
2438void Codegen::endVisit(DeleteExpression *ast) {
2439 m_seenOptionalChainNodes.remove(ast);
2442bool Codegen::visit(FalseLiteral *)
2447 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2451bool Codegen::visit(SuperLiteral *)
2456 setExprResult(Reference::fromSuper(
this));
2460bool Codegen::traverseOptionalChain(Node *node)
2462 if (m_seenOptionalChainNodes.contains(node))
2465 const auto isOptionalChainableNode = [](
const Node *node) {
2466 return node->kind == Node::Kind_FieldMemberExpression ||
2467 node->kind == Node::Kind_CallExpression ||
2468 node->kind == Node::Kind_ArrayMemberExpression ||
2469 node->kind == Node::Kind_DeleteExpression;
2471 m_optionalChainsStates->emplace();
2472 while (isOptionalChainableNode(node)) {
2473 m_seenOptionalChainNodes.insert(node);
2475 switch (node->kind) {
2476 case Node::Kind_FieldMemberExpression: {
2477 auto *fme = AST::cast<FieldMemberExpression *>(node);
2478 m_optionalChainsStates->top().actuallyHasOptionals |= fme->isOptional;
2482 case Node::Kind_CallExpression: {
2483 auto *ce = AST::cast<CallExpression *>(node);
2484 m_optionalChainsStates->top().actuallyHasOptionals |= ce->isOptional;
2488 case Node::Kind_ArrayMemberExpression: {
2489 auto *ame = AST::cast<ArrayMemberExpression *>(node);
2490 m_optionalChainsStates->top().actuallyHasOptionals |= ame->isOptional;
2494 case Node::Kind_DeleteExpression:
2495 node = AST::cast<DeleteExpression *>(node)->expression;
2505void Codegen::optionalChainFinalizer(
const Reference &expressionResult,
bool tailOfChain,
2506 bool isDeleteExpression)
2508 auto &chainState = m_optionalChainsStates->top();
2510 setExprResult(expressionResult);
2512 }
else if (!chainState.actuallyHasOptionals) {
2513 setExprResult(expressionResult);
2514 m_optionalChainsStates->pop();
2518 auto savedBaseSlot = -1;
2519 if (expressionResult.type == Reference::Member)
2520 savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
2521 expressionResult.loadInAccumulator();
2523 std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
2524 if (!isDeleteExpression)
2525 jumpToDone.emplace(bytecodeGenerator->jump());
2527 for (
auto &jump : chainState.jumpsToPatch)
2530 if (isDeleteExpression)
2531 bytecodeGenerator->addInstruction(Instruction::LoadTrue());
2533 bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
2535 if (jumpToDone.has_value())
2536 jumpToDone.value().link();
2538 auto ref = Reference::fromAccumulator(
this);
2539 if (expressionResult.type == Reference::Member) {
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552 ref.hasSavedCallBaseSlot =
true;
2553 ref.savedCallBaseSlot = savedBaseSlot;
2554 ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
2557 m_optionalChainsStates->pop();
2560bool Codegen::visit(FieldMemberExpression *ast)
2565 const bool isTailOfChain = traverseOptionalChain(ast);
2567 TailCallBlocker blockTailCalls(
this);
2569 if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
2570 if (id->name == QLatin1String(
"new")) {
2572 Q_ASSERT(ast->name == QLatin1String(
"target"));
2574 if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
2575 Reference r = referenceForName(QStringLiteral(
"new.target"),
false);
2576 r.isReadonly =
true;
2582 auto ref = Reference::fromStackSlot(
this, CallData::NewTarget);
2583 optionalChainFinalizer(ref, isTailOfChain);
2588 Reference base = expression(ast->base);
2592 if (base.isSuper()) {
2593 Instruction::LoadRuntimeString load;
2594 load.stringId = registerString(ast->name.toString());
2595 bytecodeGenerator->addInstruction(load);
2596 Reference property = Reference::fromAccumulator(
this).storeOnStack();
2598 optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
2602 auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
2603 ast->isOptional, &m_optionalChainsStates->top().jumpsToPatch);
2605 optionalChainFinalizer(ref, isTailOfChain);
2609void Codegen::endVisit(FieldMemberExpression *ast)
2611 m_seenOptionalChainNodes.remove(ast);
2614bool Codegen::visit(TaggedTemplate *ast)
2619 RegisterScope scope(
this);
2620 auto base = expression(ast->base);
2623 return handleTaggedTemplate(std::move(base), ast);
2626bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
2631 int functionObject = -1, thisObject = -1;
2632 switch (base.type) {
2633 case Reference::Member:
2634 base = base.asLValue();
2636 case Reference::Subscript:
2637 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2638 base.subscriptLoadedForCall =
true;
2640 case Reference::Name:
2642 case Reference::SuperProperty:
2643 thisObject = bytecodeGenerator->newRegister();
2644 functionObject = bytecodeGenerator->newRegister();
2647 base = base.storeOnStack();
2651 createTemplateObject(ast->templateLiteral);
2652 int templateObjectTemp = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
2653 Q_UNUSED(templateObjectTemp);
2654 auto calldata = pushTemplateArgs(ast->templateLiteral);
2658 Q_ASSERT(calldata.argv == templateObjectTemp + 1);
2661 handleCall(base, calldata, functionObject, thisObject);
2662 setExprResult(Reference::fromAccumulator(
this));
2666void Codegen::createTemplateObject(TemplateLiteral *t)
2670 for (TemplateLiteral *it = t; it; it = it->next) {
2671 obj.strings.append(registerString(it->value.toString()));
2672 obj.rawStrings.append(registerString(it->rawValue.toString()));
2675 int index = _module->templateObjects.size();
2676 _module->templateObjects.append(obj);
2678 Instruction::GetTemplateObject getTemplateObject;
2679 getTemplateObject.index = index;
2680 bytecodeGenerator->addInstruction(getTemplateObject);
2683bool Codegen::visit(FunctionExpression *ast)
2688 TailCallBlocker blockTailCalls(
this);
2690 RegisterScope scope(
this);
2692 int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
2695 loadClosure(function);
2696 setExprResult(Reference::fromAccumulator(
this));
2700Codegen::Reference Codegen::referenceForName(
const QString &name,
bool isLhs,
const SourceLocation &accessLocation)
2702 Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
2703 bool throwsReferenceError =
false;
2705 if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
2706 || resolved.type == Context::ResolvedName::Import) {
2707 if (resolved.isArgOrEval && isLhs)
2709 throwSyntaxError(SourceLocation(), QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
2711 if (resolved.declarationLocation.isValid() && accessLocation.isValid()
2712 && resolved.declarationLocation.begin() > accessLocation.end()) {
2713 Q_ASSERT(_interface);
2714 if (resolved.memberType == Context::FunctionDefinition) {
2715 _interface->reportFunctionUsedBeforeDeclaration(
2716 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2718 _interface->reportVarUsedBeforeDeclaration(
2719 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2721 if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
2722 throwsReferenceError =
true;
2725 if (resolved.isInjected && accessLocation.isValid()) {
2726 qCWarning(lcQmlInjectedParameter).nospace().noquote()
2727 << url().toString() <<
":" << accessLocation.startLine
2728 <<
":" << accessLocation.startColumn <<
" Parameter \"" << name
2729 <<
"\" is not declared."
2730 <<
" Injection of parameters into signal handlers is deprecated."
2731 <<
" Use JavaScript functions with formal parameters instead.";
2735 switch (resolved.type) {
2736 case Context::ResolvedName::Local:
2737 r = Reference::fromScopedLocal(
this, resolved.index, resolved.scope);
break;
2738 case Context::ResolvedName::Stack:
2739 r = Reference::fromStackSlot(
this, resolved.index,
true );
break;
2740 case Context::ResolvedName::Import:
2741 r = Reference::fromImport(
this, resolved.index);
break;
2742 default: Q_UNREACHABLE();
2744 if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
2745 r.isVolatile =
true;
2746 r.isArgOrEval = resolved.isArgOrEval;
2747 r.isReferenceToConst = resolved.isConst;
2748 r.requiresTDZCheck = resolved.requiresTDZCheck;
2750 r.sourceLocation = accessLocation;
2751 r.throwsReferenceError = throwsReferenceError;
2755 Reference r = Reference::fromName(
this, name);
2756 r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
2757 r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
2758 r.sourceLocation = accessLocation;
2759 if (!r.global && !r.qmlGlobal
2760 && _context->contextType == ContextType::ScriptImportedByQML
2761 && Codegen::isNameGlobal(name)) {
2771void Codegen::loadClosure(
int closureId)
2773 if (closureId >= 0) {
2774 Instruction::LoadClosure load;
2775 load.value = closureId;
2776 bytecodeGenerator->addInstruction(load);
2778 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
2782bool Codegen::visit(IdentifierExpression *ast)
2787 setExprResult(referenceForName(ast->name.toString(),
false, ast->firstSourceLocation()));
2791bool Codegen::visit(NestedExpression *ast)
2796 accept(ast->expression);
2800void Codegen::handleConstruct(
const Reference &base, ArgumentList *arguments)
2802 Reference constructor;
2803 if (base.isSuper()) {
2804 Instruction::LoadSuperConstructor super;
2805 bytecodeGenerator->addInstruction(super);
2806 constructor = Reference::fromAccumulator(
this).storeOnStack();
2808 constructor = base.storeOnStack();
2811 auto calldata = pushArgs(arguments);
2816 Reference::fromStackSlot(
this, CallData::NewTarget).loadInAccumulator();
2818 constructor.loadInAccumulator();
2820 if (calldata.hasSpread) {
2821 Instruction::ConstructWithSpread create;
2822 create.func = constructor.stackSlot();
2823 create.argc = calldata.argc;
2824 create.argv = calldata.argv;
2825 bytecodeGenerator->addInstruction(create);
2827 Instruction::Construct create;
2828 create.func = constructor.stackSlot();
2829 create.argc = calldata.argc;
2830 create.argv = calldata.argv;
2831 bytecodeGenerator->addInstruction(create);
2835 Reference::fromAccumulator(
this).storeOnStack(CallData::This);
2837 setExprResult(Reference::fromAccumulator(
this));
2840bool Codegen::visit(NewExpression *ast)
2845 RegisterScope scope(
this);
2846 TailCallBlocker blockTailCalls(
this);
2848 Reference base = expression(ast->expression);
2851 if (base.isSuper()) {
2852 throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2856 handleConstruct(base,
nullptr);
2860bool Codegen::visit(NewMemberExpression *ast)
2865 RegisterScope scope(
this);
2866 TailCallBlocker blockTailCalls(
this);
2868 Reference base = expression(ast->base);
2871 if (base.isSuper()) {
2872 throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2876 handleConstruct(base, ast->arguments);
2880bool Codegen::visit(NotExpression *ast)
2885 TailCallBlocker blockTailCalls(
this);
2886 auto e = expression(ast->expression);
2889 setExprResult(unop(Not, e));
2893bool Codegen::visit(NullExpression *)
2899 bytecodeGenerator->jump().link(*currentExpr().iffalse());
2901 setExprResult(Reference::fromConst(
this, Encode::null()));
2906bool Codegen::visit(NumericLiteral *ast)
2911 setExprResult(Reference::fromConst(
this, QV4::Encode::smallestNumber(ast->value)));
2915bool Codegen::visit(ObjectPattern *ast)
2920 TailCallBlocker blockTailCalls(
this);
2922 RegisterScope scope(
this);
2924 QStringList members;
2928 auto push = [
this, &args, &argc](
const Reference &arg) {
2929 int temp = bytecodeGenerator->newRegister();
2932 (
void) arg.storeOnStack(temp);
2936 PatternPropertyList *it = ast->properties;
2937 for (; it; it = it->next) {
2938 PatternProperty *p = it->property;
2939 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2940 if (cname || p->type != PatternProperty::Literal)
2942 QString name = p->name->asString();
2943 uint arrayIndex = stringToArrayIndex(name);
2944 if (arrayIndex != UINT_MAX)
2946 if (members.contains(name))
2948 members.append(name);
2951 RegisterScope innerScope(
this);
2952 Reference value = expression(p->initializer, name);
2955 value.loadInAccumulator();
2957 push(Reference::fromAccumulator(
this));
2960 int classId = jsUnitGenerator->registerJSClass(members);
2963 for (; it; it = it->next) {
2964 PatternProperty *p = it->property;
2965 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2966 ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
2967 if (p->type == PatternProperty::Method)
2968 argType = ObjectLiteralArgument::Method;
2969 else if (p->type == PatternProperty::Getter)
2970 argType = ObjectLiteralArgument::Getter;
2971 else if (p->type == PatternProperty::Setter)
2972 argType = ObjectLiteralArgument::Setter;
2974 Reference::fromConst(
this, Encode(
int(argType))).loadInAccumulator();
2975 push(Reference::fromAccumulator(
this));
2978 RegisterScope innerScope(
this);
2979 Reference name = expression(cname->expression);
2982 name.loadInAccumulator();
2984 QString name = p->name->asString();
2986 uint arrayIndex = QV4::String::toArrayIndex(name);
2987 if (arrayIndex != UINT_MAX) {
2988 Reference::fromConst(
this, Encode(arrayIndex)).loadInAccumulator();
2992 Instruction::LoadRuntimeString instr;
2993 instr.stringId = registerString(name);
2994 bytecodeGenerator->addInstruction(instr);
2997 push(Reference::fromAccumulator(
this));
2999 RegisterScope innerScope(
this);
3000 if (p->type != PatternProperty::Literal) {
3002 FunctionExpression *f = p->initializer->asFunctionDefinition();
3004 int function = defineFunction(f->name.toString(), f, f->formals, f->body);
3007 Reference::fromConst(
this, Encode(function)).loadInAccumulator();
3009 Reference value = expression(p->initializer);
3012 value.loadInAccumulator();
3015 push(Reference::fromAccumulator(
this));
3018 Instruction::DefineObjectLiteral call;
3019 call.internalClassId = classId;
3021 call.args = Moth::StackSlot::createRegister(args);
3022 bytecodeGenerator->addInstruction(call);
3023 setExprResult(Reference::fromAccumulator(
this));
3027bool Codegen::visit(PostDecrementExpression *ast)
3032 Reference expr = expression(ast->base);
3035 if (!expr.isLValue()) {
3036 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3039 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3042 setExprResult(unop(PostDecrement, expr));
3047bool Codegen::visit(PostIncrementExpression *ast)
3052 Reference expr = expression(ast->base);
3055 if (!expr.isLValue()) {
3056 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3059 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3062 setExprResult(unop(PostIncrement, expr));
3066bool Codegen::visit(PreDecrementExpression *ast)
3070 Reference expr = expression(ast->expression);
3073 if (!expr.isLValue()) {
3074 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix -- operator applied to value that is not a reference."));
3078 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3080 setExprResult(unop(PreDecrement, expr));
3084bool Codegen::visit(PreIncrementExpression *ast)
3089 Reference expr = expression(ast->expression);
3092 if (!expr.isLValue()) {
3093 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3097 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3099 setExprResult(unop(PreIncrement, expr));
3103bool Codegen::visit(RegExpLiteral *ast)
3108 auto r = Reference::fromStackSlot(
this);
3109 r.isReadonly =
true;
3112 Instruction::MoveRegExp instr;
3113 instr.regExpId = jsUnitGenerator->registerRegExp(ast);
3114 instr.destReg = r.stackSlot();
3115 bytecodeGenerator->addInstruction(instr);
3119bool Codegen::visit(StringLiteral *ast)
3124 auto r = Reference::fromAccumulator(
this);
3125 r.isReadonly =
true;
3128 Instruction::LoadRuntimeString instr;
3129 instr.stringId = registerString(ast->value.toString());
3130 bytecodeGenerator->addInstruction(instr);
3134bool Codegen::visit(TemplateLiteral *ast)
3139 TailCallBlocker blockTailCalls(
this);
3141 Instruction::LoadRuntimeString instr;
3142 instr.stringId = registerString(ast->value.toString());
3143 bytecodeGenerator->addInstruction(instr);
3145 if (ast->expression) {
3146 RegisterScope scope(
this);
3147 int temp = bytecodeGenerator->newRegister();
3148 Instruction::StoreReg store;
3150 bytecodeGenerator->addInstruction(store);
3152 Reference expr = expression(ast->expression);
3157 int temp2 = bytecodeGenerator->newRegister();
3158 expr.storeOnStack(temp2);
3161 Instruction::Add instr;
3163 bytecodeGenerator->addInstruction(instr);
3165 expr.loadInAccumulator();
3168 Instruction::Add instr;
3170 bytecodeGenerator->addInstruction(instr);
3173 auto r = Reference::fromAccumulator(
this);
3174 r.isReadonly =
true;
3181bool Codegen::visit(ThisExpression *)
3186 for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
3187 if (parentContext->isArrowFunction) {
3188 Reference r = referenceForName(QStringLiteral(
"this"),
false);
3189 r.isReadonly =
true;
3193 if (parentContext->contextType != ContextType::Block)
3197 setExprResult(Reference::fromThis(
this));
3201bool Codegen::visit(TildeExpression *ast)
3206 TailCallBlocker blockTailCalls(
this);
3207 auto e = expression(ast->expression);
3211 setExprResult(unop(Compl, e));
3215bool Codegen::visit(TrueLiteral *)
3220 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
3224bool Codegen::visit(TypeOfExpression *ast)
3229 RegisterScope scope(
this);
3230 TailCallBlocker blockTailCalls(
this);
3232 Reference expr = expression(ast->expression);
3236 if (expr.type == Reference::Name) {
3238 Instruction::TypeofName instr;
3239 instr.name = expr.nameAsIndex();
3240 bytecodeGenerator->addInstruction(instr);
3242 expr.loadInAccumulator();
3243 Instruction::TypeofValue instr;
3244 bytecodeGenerator->addInstruction(instr);
3246 setExprResult(Reference::fromAccumulator(
this));
3251bool Codegen::visit(UnaryMinusExpression *ast)
3256 TailCallBlocker blockTailCalls(
this);
3257 auto e = expression(ast->expression);
3261 setExprResult(unop(UMinus, e));
3265bool Codegen::visit(UnaryPlusExpression *ast)
3270 TailCallBlocker blockTailCalls(
this);
3271 auto e = expression(ast->expression);
3275 setExprResult(unop(UPlus, e));
3279bool Codegen::visit(VoidExpression *ast)
3284 RegisterScope scope(
this);
3285 TailCallBlocker blockTailCalls(
this);
3287 statement(ast->expression);
3288 setExprResult(Reference::fromConst(
this, Encode::undefined()));
3292bool Codegen::visit(FunctionDeclaration * ast)
3298 RegisterScope scope(
this);
3300 if (_functionContext->contextType == ContextType::Binding)
3301 referenceForName(ast->name.toString(),
true).loadInAccumulator();
3306bool Codegen::visit(YieldExpression *ast)
3308 if (inFormalParameterList) {
3309 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"yield is not allowed inside parameter lists"));
3313 auto innerMostCurentFunctionContext = _context;
3314 while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
3315 innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
3317 Q_ASSERT(innerMostCurentFunctionContext);
3319 if (!innerMostCurentFunctionContext->isGenerator) {
3320 throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
3324 RegisterScope scope(
this);
3325 TailCallBlocker blockTailCalls(
this);
3326 Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(
this, Encode::undefined());
3330 Reference acc = Reference::fromAccumulator(
this);
3332 if (ast->isYieldStar) {
3333 Reference iterator = Reference::fromStackSlot(
this);
3334 Reference lhsValue = Reference::fromConst(
this, Encode::undefined()).storeOnStack();
3336 expr.loadInAccumulator();
3337 Instruction::GetIterator getIterator;
3338 getIterator.iterator =
static_cast<
int>(AST::ForEachType::Of);
3339 bytecodeGenerator->addInstruction(getIterator);
3340 iterator.storeConsumeAccumulator();
3341 Instruction::LoadUndefined load;
3342 bytecodeGenerator->addInstruction(load);
3344 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3345 bytecodeGenerator->jump().link(in);
3347 BytecodeGenerator::Label loop = bytecodeGenerator->label();
3349 lhsValue.loadInAccumulator();
3350 Instruction::YieldStar yield;
3351 bytecodeGenerator->addInstruction(yield);
3355 Instruction::IteratorNextForYieldStar next;
3356 next.object = lhsValue.stackSlot();
3357 next.iterator = iterator.stackSlot();
3358 BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
3359 bytecodeGenerator->jumpNotUndefined().link(loop);
3361 lhsValue.loadInAccumulator();
3366 bytecodeGenerator->checkException();
3368 lhsValue.loadInAccumulator();
3373 expr.loadInAccumulator();
3374 Instruction::Yield yield;
3375 bytecodeGenerator->addInstruction(yield);
3376 Instruction::Resume resume;
3377 BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
3388 if (AST::cast<ReturnStatement *>(node))
3390 if (AST::cast<ThrowStatement *>(node))
3392 if (Program *p = AST::cast<Program *>(node))
3393 return endsWithReturn(module, p->statements);
3394 if (StatementList *sl = AST::cast<StatementList *>(node)) {
3397 return endsWithReturn(module, sl->statement);
3399 if (Block *b = AST::cast<Block *>(node)) {
3400 Context *blockContext = module->contextMap.value(node);
3401 if (blockContext->requiresExecutionContext)
3405 return endsWithReturn(module, b->statements);
3407 if (IfStatement *is = AST::cast<IfStatement *>(node))
3408 return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
3412int Codegen::defineFunction(
const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
3413 AST::StatementList *body)
3417 if (_context->functionIndex >= 0)
3419 return leaveContext();
3421 _context->name = name.isEmpty() ? currentExpr().result().name : name;
3422 _module->functions.append(_context);
3423 _context->functionIndex = _module->functions.size() - 1;
3425 Context *savedFunctionContext = _functionContext;
3426 _functionContext = _context;
3427 ControlFlow *savedControlFlow = controlFlow;
3428 controlFlow =
nullptr;
3430 if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
3431 _module->blocks.append(_context);
3432 _context->blockIndex = _module->blocks.size() - 1;
3434 if (_module->debugMode)
3435 _context->argumentsCanEscape =
true;
3443 _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
3444 && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
3446 BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
3447 BytecodeGenerator *savedBytecodeGenerator;
3448 savedBytecodeGenerator = bytecodeGenerator;
3449 bytecodeGenerator = &bytecode;
3450 bytecodeGenerator->setLocation(ast->firstSourceLocation());
3451 BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
3452 _returnLabel =
nullptr;
3454 OptionalChainStates optionalChainStates;
3455 OptionalChainStates *savedOptionalChainStates = m_optionalChainsStates;
3456 m_optionalChainsStates = &optionalChainStates;
3458 bool savedFunctionEndsWithReturn = functionEndsWithReturn;
3459 functionEndsWithReturn = endsWithReturn(_module, body);
3462 bytecodeGenerator->newRegisterArray(
3463 sizeof(CallData) /
sizeof(StaticValue) - 1 + _context->arguments.size());
3465 bool _inFormalParameterList =
false;
3466 qSwap(_inFormalParameterList, inFormalParameterList);
3468 int returnAddress = -1;
3469 bool _requiresReturnValue = _context->requiresImplicitReturnValue();
3470 qSwap(requiresReturnValue, _requiresReturnValue);
3471 returnAddress = bytecodeGenerator->newRegister();
3472 qSwap(_returnAddress, returnAddress);
3475 if (!_context->parent && _context->requiresExecutionContext) {
3476 _module->blocks.append(_context);
3477 _context->blockIndex = _module->blocks.size() - 1;
3480 TailCallBlocker maybeBlockTailCalls(
this, _context->canHaveTailCalls());
3482 RegisterScope registerScope(
this);
3483 _context->emitBlockHeader(
this);
3486 QScopedValueRollback<
bool> inFormals(inFormalParameterList,
true);
3487 TailCallBlocker blockTailCalls(
this);
3491 PatternElement *e = formals->element;
3499 Reference arg = referenceForName(e->bindingIdentifier.toString(),
true);
3500 if (e->type == PatternElement::RestElement) {
3501 Q_ASSERT(!formals->next);
3502 Instruction::CreateRestParameter rest;
3503 rest.argIndex = argc;
3504 bytecodeGenerator->addInstruction(rest);
3505 arg.storeConsumeAccumulator();
3507 if (e->bindingTarget || e->initializer) {
3508 initializeAndDestructureBindingElement(e, arg);
3513 formals = formals->next;
3518 if (_context->isGenerator) {
3519 Instruction::Yield yield;
3520 bytecodeGenerator->addInstruction(yield);
3523 statementList(body);
3526 bytecodeGenerator->setError(
true);
3528 bytecodeGenerator->setLocation(ast->lastSourceLocation());
3529 _context->emitBlockFooter(
this);
3531 if (_returnLabel || !functionEndsWithReturn) {
3533 _returnLabel->link();
3535 if (_returnLabel || requiresReturnValue) {
3536 Instruction::LoadReg load;
3537 load.reg = Moth::StackSlot::createRegister(_returnAddress);
3538 bytecodeGenerator->addInstruction(load);
3540 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
3543 bytecodeGenerator->addInstruction(Instruction::Ret());
3546 Q_ASSERT(_context == _functionContext);
3547 bytecodeGenerator->finalize(_context);
3548 _context->registerCountInFunction = bytecodeGenerator->registerCount();
3549 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
3551 qDebug() <<
"=== Bytecode for" << _context->name <<
"strict mode" << _context->isStrict
3552 <<
"register count" << _context->registerCountInFunction <<
"implicit return" << requiresReturnValue;
3553 qDebug().noquote() << QV4::Moth::dumpBytecode(
3554 _context->code, _context->locals.size(), _context->arguments.size(),
3555 _context->line, _context->lineAndStatementNumberMapping);
3560 qSwap(_returnAddress, returnAddress);
3561 qSwap(requiresReturnValue, _requiresReturnValue);
3562 qSwap(_inFormalParameterList, inFormalParameterList);
3563 m_optionalChainsStates = savedOptionalChainStates;
3564 bytecodeGenerator = savedBytecodeGenerator;
3565 delete _returnLabel;
3566 _returnLabel = savedReturnLabel;
3567 controlFlow = savedControlFlow;
3568 functionEndsWithReturn = savedFunctionEndsWithReturn;
3569 _functionContext = savedFunctionContext;
3571 return leaveContext();
3574bool Codegen::visit(Block *ast)
3579 RegisterScope scope(
this);
3581 ControlFlowBlock controlFlow(
this, ast);
3582 statementList(ast->statements);
3586bool Codegen::visit(BreakStatement *ast)
3593 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3597 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
3598 if (!target.linkLabel.isValid()) {
3599 if (ast->label.isEmpty())
3600 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3602 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3606 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3611bool Codegen::visit(ContinueStatement *ast)
3617 RegisterScope scope(
this);
3620 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Continue outside of loop"));
3624 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
3625 if (!target.linkLabel.isValid()) {
3626 if (ast->label.isEmpty())
3627 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3629 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"continue outside of loop"));
3633 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3638bool Codegen::visit(DebuggerStatement *)
3644bool Codegen::visit(DoWhileStatement *ast)
3649 RegisterScope scope(
this);
3651 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3652 BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
3653 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3655 ControlFlowLoop flow(
this, &end, &cond);
3659 if (!AST::cast<FalseLiteral *>(ast->expression))
3660 bytecodeGenerator->addLoopStart(body);
3663 statement(ast->statement);
3664 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
3667 if (AST::cast<TrueLiteral *>(ast->expression)) {
3669 bytecodeGenerator->checkException();
3670 bytecodeGenerator->jump().link(body);
3671 }
else if (AST::cast<FalseLiteral *>(ast->expression)) {
3674 TailCallBlocker blockTailCalls(
this);
3675 bytecodeGenerator->checkException();
3676 condition(ast->expression, &body, &end,
false);
3684bool Codegen::visit(EmptyStatement *)
3689bool Codegen::visit(ExpressionStatement *ast)
3694 RegisterScope scope(
this);
3695 TailCallBlocker blockTailCalls(
this);
3697 if (requiresReturnValue) {
3698 Reference e = expression(ast->expression);
3701 (
void) e.storeOnStack(_returnAddress);
3703 statement(ast->expression);
3708bool Codegen::visit(ForEachStatement *ast)
3713 RegisterScope scope(
this);
3714 TailCallBlocker blockTailCalls(
this);
3716 Reference iterator = Reference::fromStackSlot(
this);
3717 Reference lhsValue = Reference::fromStackSlot(
this);
3722 RegisterScope innerScope(
this);
3723 ControlFlowBlock controlFlow(
this, ast);
3724 Reference expr = expression(ast->expression);
3728 expr.loadInAccumulator();
3729 Instruction::GetIterator iteratorObjInstr;
3730 iteratorObjInstr.iterator =
static_cast<
int>(ast->type);
3731 bytecodeGenerator->addInstruction(iteratorObjInstr);
3732 iterator.storeConsumeAccumulator();
3735 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3736 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3737 BytecodeGenerator::Label done;
3740 std::function<
void()> cleanup;
3741 if (ast->type == ForEachType::Of) {
3742 done = bytecodeGenerator->newLabel();
3743 cleanup = [iterator,
this, done]() {
3744 iterator.loadInAccumulator();
3745 Instruction::IteratorClose close;
3746 bytecodeGenerator->addInstruction(close);
3752 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
3753 bytecodeGenerator->addLoopStart(in);
3755 iterator.loadInAccumulator();
3756 Instruction::IteratorNext next;
3757 next.value = lhsValue.stackSlot();
3758 bytecodeGenerator->addJumpInstruction(next).link(done);
3762 RegisterScope innerScope(
this);
3763 ControlFlowBlock controlFlow(
this, ast);
3765 if (ExpressionNode *e = ast->lhs->expressionCast()) {
3766 if (AST::Pattern *p = e->patternCast()) {
3767 RegisterScope scope(
this);
3768 destructurePattern(p, lhsValue);
3770 Reference lhs = expression(e);
3773 if (!lhs.isLValue()) {
3774 throwReferenceError(e->firstSourceLocation(), QStringLiteral(
"Invalid left-hand side expression for 'in' expression"));
3777 lhs = lhs.asLValue();
3778 lhsValue.loadInAccumulator();
3779 lhs.storeConsumeAccumulator();
3781 }
else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
3782 initializeAndDestructureBindingElement(p, lhsValue,
true);
3789 blockTailCalls.unblock();
3790 statement(ast->statement);
3791 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3794 bytecodeGenerator->checkException();
3795 bytecodeGenerator->jump().link(in);
3807bool Codegen::visit(ForStatement *ast)
3812 RegisterScope scope(
this);
3813 TailCallBlocker blockTailCalls(
this);
3815 ControlFlowBlock controlFlow(
this, ast);
3817 if (ast->initialiser)
3818 statement(ast->initialiser);
3819 else if (ast->declarations)
3820 variableDeclarationList(ast->declarations);
3822 BytecodeGenerator::Label cond = bytecodeGenerator->label();
3823 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3824 BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
3825 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3827 ControlFlowLoop flow(
this, &end, &step);
3828 bytecodeGenerator->addLoopStart(cond);
3829 condition(ast->condition, &body, &end,
true);
3832 blockTailCalls.unblock();
3833 statement(ast->statement);
3834 blockTailCalls.reblock();
3835 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3838 if (_context->requiresExecutionContext) {
3839 Instruction::CloneBlockContext clone;
3840 bytecodeGenerator->addInstruction(clone);
3842 statement(ast->expression);
3843 bytecodeGenerator->checkException();
3844 bytecodeGenerator->jump().link(cond);
3851bool Codegen::visit(IfStatement *ast)
3856 RegisterScope scope(
this);
3857 TailCallBlocker blockTailCalls(
this);
3859 BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
3860 BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
3861 condition(ast->expression, &trueLabel, &falseLabel,
true);
3862 blockTailCalls.unblock();
3867 if (endsWithReturn(_module, ast)) {
3871 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
3883bool Codegen::visit(LabelledStatement *ast)
3888 RegisterScope scope(
this);
3891 ControlFlow *l = controlFlow;
3893 if (l->label() == ast->label) {
3894 QString error = QString(QStringLiteral(
"Label '%1' has already been declared")).arg(ast->label.toString());
3895 throwSyntaxError(ast->firstSourceLocation(), error);
3900 _labelledStatement = ast;
3902 if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
3903 AST::cast<AST::WhileStatement *>(ast->statement) ||
3904 AST::cast<AST::DoWhileStatement *>(ast->statement) ||
3905 AST::cast<AST::ForStatement *>(ast->statement) ||
3906 AST::cast<AST::ForEachStatement *>(ast->statement)) {
3907 statement(ast->statement);
3909 BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
3910 ControlFlowLoop flow(
this, &breakLabel);
3911 statement(ast->statement);
3918void Codegen::emitReturn(
const Reference &expr)
3920 ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
3921 if (target.linkLabel.isValid() && target.unwindLevel) {
3922 Q_ASSERT(_returnAddress >= 0);
3923 (
void) expr.storeOnStack(_returnAddress);
3924 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3926 expr.loadInAccumulator();
3927 bytecodeGenerator->addInstruction(Instruction::Ret());
3931bool Codegen::visit(ReturnStatement *ast)
3936 if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
3937 throwSyntaxError(ast->returnToken, QStringLiteral(
"Return statement outside of function"));
3941 if (ast->expression) {
3942 expr = expression(ast->expression);
3946 expr = Reference::fromConst(
this, Encode::undefined());
3954bool Codegen::visit(SwitchStatement *ast)
3959 if (requiresReturnValue)
3960 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
3962 RegisterScope scope(
this);
3963 TailCallBlocker blockTailCalls(
this);
3966 BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
3968 Reference lhs = expression(ast->expression);
3971 lhs = lhs.storeOnStack();
3973 ControlFlowBlock controlFlow(
this, ast->block);
3976 QHash<Node *, BytecodeGenerator::Label> blockMap;
3977 for (CaseClauses *it = ast->block->clauses; it; it = it->next)
3978 blockMap[it->clause] = bytecodeGenerator->newLabel();
3979 if (ast->block->defaultClause)
3980 blockMap[ast->block->defaultClause] = bytecodeGenerator->newLabel();
3981 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next)
3982 blockMap[it->clause] = bytecodeGenerator->newLabel();
3985 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3986 CaseClause *clause = it->clause;
3987 Reference rhs = expression(clause->expression);
3990 rhs.loadInAccumulator();
3991 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3994 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3995 CaseClause *clause = it->clause;
3996 Reference rhs = expression(clause->expression);
3999 rhs.loadInAccumulator();
4000 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
4003 if (DefaultClause *defaultClause = ast->block->defaultClause)
4004 bytecodeGenerator->jump().link(blockMap.value(defaultClause));
4006 bytecodeGenerator->jump().link(switchEnd);
4008 ControlFlowLoop flow(
this, &switchEnd);
4010 insideSwitch =
true;
4011 blockTailCalls.unblock();
4012 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
4013 CaseClause *clause = it->clause;
4014 blockMap[clause].link();
4016 statementList(clause->statements);
4019 if (ast->block->defaultClause) {
4020 DefaultClause *clause = ast->block->defaultClause;
4021 blockMap[clause].link();
4023 statementList(clause->statements);
4026 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
4027 CaseClause *clause = it->clause;
4028 blockMap[clause].link();
4030 statementList(clause->statements);
4032 insideSwitch =
false;
4041bool Codegen::visit(ThrowStatement *ast)
4046 RegisterScope scope(
this);
4047 TailCallBlocker blockTailCalls(
this);
4049 Reference expr = expression(ast->expression);
4053 expr.loadInAccumulator();
4054 Instruction::ThrowException instr;
4055 bytecodeGenerator->addInstruction(instr);
4059void Codegen::handleTryCatch(TryStatement *ast)
4062 RegisterScope scope(
this);
4064 ControlFlowCatch catchFlow(
this, ast->catchExpression);
4065 RegisterScope scope(
this);
4066 TailCallBlocker blockTailCalls(
this);
4067 statement(ast->statement);
4071void Codegen::handleTryFinally(TryStatement *ast)
4073 RegisterScope scope(
this);
4074 const bool hasCatchBlock = ast->catchExpression;
4075 ControlFlowFinally finally(
this, ast->finallyExpression, hasCatchBlock);
4076 TailCallBlocker blockTailCalls(
this);
4078 if (ast->catchExpression) {
4079 handleTryCatch(ast);
4081 RegisterScope scope(
this);
4082 statement(ast->statement);
4086bool Codegen::visit(TryStatement *ast)
4091 RegisterScope scope(
this);
4093 if (ast->finallyExpression && ast->finallyExpression->statement) {
4094 handleTryFinally(ast);
4096 handleTryCatch(ast);
4102bool Codegen::visit(VariableStatement *ast)
4107 variableDeclarationList(ast->declarations);
4111bool Codegen::visit(WhileStatement *ast)
4116 if (AST::cast<FalseLiteral *>(ast->expression))
4119 RegisterScope scope(
this);
4121 BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
4122 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
4123 BytecodeGenerator::Label cond = bytecodeGenerator->label();
4124 ControlFlowLoop flow(
this, &end, &cond);
4125 bytecodeGenerator->addLoopStart(cond);
4127 bytecodeGenerator->checkException();
4129 if (!AST::cast<TrueLiteral *>(ast->expression)) {
4130 TailCallBlocker blockTailCalls(
this);
4131 condition(ast->expression, &start, &end,
true);
4135 statement(ast->statement);
4136 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->whileToken);
4137 bytecodeGenerator->jump().link(cond);
4143bool Codegen::visit(WithStatement *ast)
4148 RegisterScope scope(
this);
4149 TailCallBlocker blockTailCalls(
this);
4151 Reference src = expression(ast->expression);
4154 src = src.storeOnStack();
4155 src.loadInAccumulator();
4159 blockTailCalls.unblock();
4160 ControlFlowWith flow(
this);
4161 statement(ast->statement);
4168bool Codegen::visit(UiArrayBinding *)
4174bool Codegen::visit(UiObjectBinding *)
4180bool Codegen::visit(UiObjectDefinition *)
4186bool Codegen::visit(UiPublicMember *)
4192bool Codegen::visit(UiScriptBinding *)
4198bool Codegen::visit(UiSourceElement *)
4204bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(
const Reference &r,
const SourceLocation& loc)
4206 if (!_context->isStrict)
4208 bool isArgOrEval =
false;
4209 if (r.type == Reference::Name) {
4210 QString str = jsUnitGenerator->stringForIndex(r.nameAsIndex());
4211 if (str == QLatin1String(
"eval") || str == QLatin1String(
"arguments")) {
4214 }
else if (r.type == Reference::ScopedLocal || r.isRegister()) {
4215 isArgOrEval = r.isArgOrEval;
4218 throwSyntaxError(loc, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
4222void Codegen::throwError(ErrorType errorType,
const SourceLocation &loc,
const QString &detail)
4227 _errorType = errorType;
4228 _error.message = detail;
4232void Codegen::throwSyntaxError(
const SourceLocation &loc,
const QString &detail)
4234 throwError(SyntaxError, loc, detail);
4237void Codegen::throwReferenceError(
const SourceLocation &loc,
const QString &detail)
4239 throwError(ReferenceError, loc, detail);
4242QQmlJS::DiagnosticMessage Codegen::error()
const
4247QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
4248 bool generateUnitData)
4250 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
4251 new QV4::CompiledData::CompilationUnit(
4252 generateUnitData ? jsUnitGenerator->generateUnit() :
nullptr),
4253 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
4256QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
4257 bool debugMode,
const QString &url,
const QString &sourceCode,
4258 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
4261 QQmlJS::Lexer lexer(&ee);
4262 lexer.setCode(sourceCode, 1,
false);
4263 QQmlJS::Parser parser(&ee);
4265 const bool parsed = parser.parseModule();
4268 *diagnostics = parser.diagnosticMessages();
4271 return QQmlRefPointer<CompiledData::CompilationUnit>();
4273 QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
4278 diagnostics->clear();
4282 using namespace QV4::Compiler;
4283 Compiler::Module compilerModule(url, url, debugMode);
4284 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4285 compilerModule.sourceTimeStamp = sourceTimeStamp;
4286 JSUnitGenerator jsGenerator(&compilerModule);
4287 Codegen cg(&jsGenerator,
true);
4288 cg.generateFromModule(sourceCode, moduleNode, &compilerModule);
4289 if (cg.hasError()) {
4291 *diagnostics << cg.error();
4292 return QQmlRefPointer<CompiledData::CompilationUnit>();
4295 return cg.generateCompilationUnit();
4298const QV4::CompiledData::Unit *Codegen::generateNativeModuleUnitData(
4299 bool debugMode,
const QString &url,
const Value &value)
4301 using namespace QV4::Compiler;
4302 Compiler::Module compilerModule(url, url, debugMode);
4303 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4304 JSUnitGenerator jsGenerator(&compilerModule);
4305 Codegen cg(&jsGenerator,
true);
4306 cg.generateFromModule(value, &compilerModule);
4307 Q_ASSERT(!cg.hasError());
4308 return jsGenerator.generateUnit();
4313 VolatileMemoryLocations locs;
4328 bool visit(ArrayMemberExpression *)
override
4330 locs.setAllVolatile();
4334 bool visit(FieldMemberExpression *)
override
4336 locs.setAllVolatile();
4340 bool visit(PostIncrementExpression *e)
override
4342 collectIdentifiers(locs.specificLocations, e->base);
4346 bool visit(PostDecrementExpression *e)
override
4348 collectIdentifiers(locs.specificLocations, e->base);
4352 bool visit(PreIncrementExpression *e)
override
4354 collectIdentifiers(locs.specificLocations, e->expression);
4358 bool visit(PreDecrementExpression *e)
override
4360 collectIdentifiers(locs.specificLocations, e->expression);
4364 bool visit(BinaryExpression *e)
override
4367 case QSOperator::InplaceAnd:
4368 case QSOperator::InplaceSub:
4369 case QSOperator::InplaceDiv:
4370 case QSOperator::InplaceAdd:
4371 case QSOperator::InplaceLeftShift:
4372 case QSOperator::InplaceMod:
4373 case QSOperator::InplaceMul:
4374 case QSOperator::InplaceOr:
4375 case QSOperator::InplaceRightShift:
4376 case QSOperator::InplaceURightShift:
4377 case QSOperator::InplaceXor:
4378 collectIdentifiers(locs.specificLocations, e);
4392 void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
4393 class Collector:
public QQmlJS::AST::Visitor {
4395 QList<QStringView> &ids;
4396 VolatileMemoryLocationScanner *parent;
4399 Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
4400 QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
4403 bool visit(IdentifierExpression *ie) final {
4404 ids.append(ie->name);
4408 void throwRecursionDepthError() final
4410 parent->throwRecursionDepthError();
4413 Collector collector(ids,
this);
4414 node->accept(&collector);
4418Codegen::VolatileMemoryLocations
Codegen::scanVolatileMemoryLocations(AST::Node *ast)
4420 VolatileMemoryLocationScanner scanner(
this);
4421 return scanner.scan(ast);
4426 return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
4429bool Codegen::RValue::operator==(
const RValue &other)
const
4433 return other.isAccumulator();
4435 return other.isStackSlot() && theStackSlot == other.theStackSlot;
4437 return other.isConst() && constant == other.constant;
4443Codegen::RValue Codegen::RValue::storeOnStack()
const
4447 return RValue::fromStackSlot(codegen, Reference::fromAccumulator(codegen).storeOnStack().stackSlot());
4451 return RValue::fromStackSlot(codegen, Reference::storeConstOnStack(codegen, constant).stackSlot());
4457void Codegen::RValue::loadInAccumulator()
const
4464 return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
4466 return Reference::fromConst(codegen, constant).loadInAccumulator();
4473bool Codegen::Reference::operator==(
const Codegen::Reference &other)
const
4475 if (type != other.type)
4484 return property == other.property;
4486 return theStackSlot == other.theStackSlot;
4488 return index == other.index && scope == other.scope;
4490 return nameAsIndex() == other.nameAsIndex();
4492 return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
4494 return elementBase == other.elementBase && other.subscriptLoadedForCall
4495 ? (subscriptLoadedForCall && element == other.element)
4496 : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
4498 return index == other.index;
4500 return constant == other.constant;
4505Codegen::RValue Codegen::Reference::asRValue()
const
4511 return RValue::fromAccumulator(codegen);
4513 return RValue::fromStackSlot(codegen, stackSlot());
4515 return RValue::fromConst(codegen, constant);
4517 loadInAccumulator();
4518 return RValue::fromAccumulator(codegen);
4522Codegen::Reference Codegen::Reference::asLValue()
const
4529 codegen->throwSyntaxError(SourceLocation(), QStringLiteral(
"Super lvalues not implemented."));
4532 if (!propertyBase.isStackSlot()) {
4533 Reference r = *
this;
4534 r.propertyBase = propertyBase.storeOnStack();
4539 if (!elementSubscript.isStackSlot()) {
4540 Reference r = *
this;
4541 r.elementSubscript = elementSubscript.storeOnStack();
4550Codegen::Reference Codegen::Reference::storeConsumeAccumulator()
const
4556Codegen::Reference Codegen::Reference::baseObject()
const
4558 if (type == Reference::Member) {
4559 RValue rval = propertyBase;
4560 if (!rval.isValid())
4561 return Reference::fromConst(codegen, Encode::undefined());
4562 if (rval.isAccumulator())
4563 return Reference::fromAccumulator(codegen);
4564 if (rval.isStackSlot())
4565 return Reference::fromStackSlot(codegen, rval.stackSlot());
4567 return Reference::fromConst(codegen, rval.constantValue());
4569 }
else if (type == Reference::Subscript) {
4570 return Reference::fromStackSlot(codegen, elementBase.stackSlot());
4571 }
else if (type == Reference::SuperProperty) {
4572 return Reference::fromStackSlot(codegen, CallData::This);
4574 return Reference::fromConst(codegen, Encode::undefined());
4578Codegen::Reference Codegen::Reference::storeOnStack()
const
4579{
return doStoreOnStack(-1); }
4581void Codegen::Reference::storeOnStack(
int slotIndex)
const
4582{ doStoreOnStack(slotIndex); }
4584Codegen::Reference Codegen::Reference::doStoreOnStack(
int slotIndex)
const
4586 Q_ASSERT(isValid());
4588 if (isStackSlot() && slotIndex == -1 && !(stackSlotIsLocalOrArgument && isVolatile) && !requiresTDZCheck)
4591 if (isStackSlot() && !requiresTDZCheck) {
4592 Reference dest = Reference::fromStackSlot(codegen, slotIndex);
4593 Instruction::MoveReg move;
4594 move.srcReg = stackSlot();
4595 move.destReg = dest.stackSlot();
4596 codegen->bytecodeGenerator->addInstruction(move);
4600 Reference slot = Reference::fromStackSlot(codegen, slotIndex);
4602 Instruction::MoveConst move;
4603 move.constIndex = codegen->registerConstant(constant);
4604 move.destTemp = slot.stackSlot();
4605 codegen->bytecodeGenerator->addInstruction(move);
4607 loadInAccumulator();
4608 slot.storeConsumeAccumulator();
4613void Codegen::Reference::tdzCheck(
bool requiresCheck,
bool throwsReferenceError)
const {
4614 if (throwsReferenceError) {
4615 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4616 name + QStringLiteral(
" is not defined"));
4621 Instruction::DeadTemporalZoneCheck check;
4622 check.name = codegen->registerString(name);
4623 codegen->bytecodeGenerator->addInstruction(check);
4626void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot,
bool requiresCheck,
bool throwsReferenceError)
const {
4629 Instruction::LoadReg load;
4631 codegen->bytecodeGenerator->addInstruction(load);
4632 tdzCheck(
true, throwsReferenceError);
4635Codegen::Reference Codegen::Reference::storeRetainAccumulator()
const
4637 if (storeWipesAccumulator()) {
4639 auto tmp = Reference::fromStackSlot(codegen);
4640 tmp.storeAccumulator();
4641 tmp.isReadonly = isReadonly;
4651bool Codegen::Reference::storeWipesAccumulator()
const
4670void Codegen::Reference::storeAccumulator()
const
4672 if (throwsReferenceError) {
4673 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4674 name + QStringLiteral(
" is not defined"));
4678 if (isReferenceToConst) {
4680 codegen->generateThrowException(QStringLiteral(
"TypeError"));
4686 Q_UNREACHABLE_RETURN();
4688 Instruction::StoreSuperProperty store;
4689 store.property = property.stackSlot();
4690 codegen->bytecodeGenerator->addInstruction(store);
4693 Instruction::StoreReg store;
4694 store.reg = theStackSlot;
4695 codegen->bytecodeGenerator->addInstruction(store);
4700 Instruction::StoreLocal store;
4701 store.index = index;
4702 codegen->bytecodeGenerator->addInstruction(store);
4704 Instruction::StoreScopedLocal store;
4705 store.index = index;
4706 store.scope = scope;
4707 codegen->bytecodeGenerator->addInstruction(store);
4712 Context *c = codegen->currentContext();
4714 Instruction::StoreNameStrict store;
4715 store.name = nameAsIndex();
4716 codegen->bytecodeGenerator->addInstruction(store);
4718 Instruction::StoreNameSloppy store;
4719 store.name = nameAsIndex();
4720 codegen->bytecodeGenerator->addInstruction(store);
4724 if (codegen->useFastLookups) {
4725 Instruction::SetLookup store;
4726 store.base = propertyBase.stackSlot();
4727 store.index = codegen->registerSetterLookup(propertyNameIndex);
4728 codegen->bytecodeGenerator->addInstruction(store);
4730 Instruction::StoreProperty store;
4731 store.base = propertyBase.stackSlot();
4732 store.name = propertyNameIndex;
4733 codegen->bytecodeGenerator->addInstruction(store);
4737 Instruction::StoreElement store;
4738 store.base = elementBase;
4739 store.index = elementSubscript.stackSlot();
4740 codegen->bytecodeGenerator->addInstruction(store);
4752void Codegen::Reference::loadInAccumulator()
const
4758 Q_UNREACHABLE_RETURN();
4760 tdzCheckStackSlot(property, subscriptRequiresTDZCheck,
false);
4761 Instruction::LoadSuperProperty load;
4762 load.property = property.stackSlot();
4763 codegen->bytecodeGenerator->addInstruction(load);
4767QT_WARNING_DISABLE_GCC(
"-Wmaybe-uninitialized")
4768 if (constant == Encode::null()) {
4769 Instruction::LoadNull load;
4770 codegen->bytecodeGenerator->addInstruction(load);
4771 }
else if (constant == Encode(
true)) {
4772 Instruction::LoadTrue load;
4773 codegen->bytecodeGenerator->addInstruction(load);
4774 }
else if (constant == Encode(
false)) {
4775 Instruction::LoadFalse load;
4776 codegen->bytecodeGenerator->addInstruction(load);
4777 }
else if (constant == Encode::undefined()) {
4778 Instruction::LoadUndefined load;
4779 codegen->bytecodeGenerator->addInstruction(load);
4781 StaticValue p = StaticValue::fromReturnedValue(constant);
4783 double d = p.asDouble();
4784 int i = QJSNumberCoercion::toInteger(d);
4785 if (d == i && (d != 0 || !std::signbit(d))) {
4787 Instruction::LoadZero load;
4788 codegen->bytecodeGenerator->addInstruction(load);
4791 Instruction::LoadInt load;
4792 load.value = StaticValue::fromReturnedValue(constant).toInt32();
4793 codegen->bytecodeGenerator->addInstruction(load);
4797 Instruction::LoadConst load;
4798 load.index = codegen->registerConstant(constant);
4799 codegen->bytecodeGenerator->addInstruction(load);
4804 Instruction::LoadReg load;
4805 load.reg = stackSlot();
4806 codegen->bytecodeGenerator->addInstruction(load);
4807 tdzCheck(requiresTDZCheck, throwsReferenceError);
4811 Instruction::LoadLocal load;
4813 codegen->bytecodeGenerator->addInstruction(load);
4815 Instruction::LoadScopedLocal load;
4818 codegen->bytecodeGenerator->addInstruction(load);
4820 tdzCheck(requiresTDZCheck, throwsReferenceError);
4827 if (name == QStringLiteral(
"undefined")) {
4828 Reference::fromConst(codegen, Encode::undefined()).loadInAccumulator();
4830 }
else if (name == QStringLiteral(
"Infinity")) {
4831 Reference::fromConst(codegen, Encode(qInf())).loadInAccumulator();
4833 }
else if (name == QStringLiteral(
"Nan")) {
4834 Reference::fromConst(codegen, Encode(qQNaN())).loadInAccumulator();
4839 if (sourceLocation.isValid())
4840 codegen->bytecodeGenerator->setLocation(sourceLocation);
4844 Instruction::LoadQmlContextPropertyLookup load;
4845 load.index = codegen->registerQmlContextPropertyGetterLookup(
4846 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4847 codegen->bytecodeGenerator->addInstruction(load);
4849 Instruction::LoadGlobalLookup load;
4850 load.index = codegen->registerGlobalGetterLookup(
4851 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4852 codegen->bytecodeGenerator->addInstruction(load);
4855 Instruction::LoadName load;
4856 load.name = nameAsIndex();
4857 codegen->bytecodeGenerator->addInstruction(load);
4861 propertyBase.loadInAccumulator();
4862 tdzCheck(requiresTDZCheck, throwsReferenceError);
4864 if (sourceLocation.isValid())
4865 codegen->bytecodeGenerator->setLocation(sourceLocation);
4867 if (codegen->useFastLookups) {
4868 if (optionalChainJumpsToPatch && isOptional) {
4869 auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
4870 codegen->registerGetterLookup(
4871 propertyNameIndex, JSUnitGenerator::LookupForStorage));
4872 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4874 Instruction::GetLookup load;
4875 load.index = codegen->registerGetterLookup(
4876 propertyNameIndex, JSUnitGenerator::LookupForStorage);
4877 codegen->bytecodeGenerator->addInstruction(load);
4880 if (optionalChainJumpsToPatch && isOptional) {
4881 auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
4882 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4884 Instruction::LoadProperty load;
4885 load.name = propertyNameIndex;
4886 codegen->bytecodeGenerator->addInstruction(load);
4891 Instruction::LoadImport load;
4893 codegen->bytecodeGenerator->addInstruction(load);
4894 tdzCheck(requiresTDZCheck, throwsReferenceError);
4897 tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
4898 elementSubscript.loadInAccumulator();
4899 tdzCheck(subscriptRequiresTDZCheck,
false);
4900 Instruction::LoadElement load;
4901 load.base = elementBase;
4902 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[]