6#include <private/qqmljsast_p.h>
7#include <private/qqmljsdiagnosticmessage_p.h>
8#include <private/qqmljslexer_p.h>
9#include <private/qqmljsparser_p.h>
10#include <private/qv4bytecodegenerator_p.h>
11#include <private/qv4compilercontext_p.h>
12#include <private/qv4compilercontrolflow_p.h>
13#include <private/qv4compilerscanfunctions_p.h>
14#include <private/qv4object_p.h>
15#include <private/qv4objectiterator_p.h>
16#include <private/qv4staticvalue_p.h>
17#include <private/qv4stringtoarrayindex_p.h>
19#include <QtCore/qcoreapplication.h>
20#include <QtCore/qloggingcategory.h>
21#include <QtCore/qscopeguard.h>
22#include <QtCore/qstack.h>
23#include <QtCore/qstringlist.h>
24#include <QtCore/qurl.h>
34using namespace Qt::StringLiterals;
41using namespace QQmlJS;
42using namespace QQmlJS::AST;
44void CodegenWarningInterface::reportVarUsedBeforeDeclaration(
45 const QString &name,
const QString &fileName, QQmlJS::SourceLocation declarationLocation,
46 QQmlJS::SourceLocation accessLocation)
48 qCWarning(lcQmlUsedBeforeDeclared).nospace().noquote()
49 << fileName <<
":" << accessLocation.startLine <<
":" << accessLocation.startColumn
50 <<
" Variable \"" << name <<
"\" is used before its declaration at "
51 << declarationLocation.startLine <<
":" << declarationLocation.startColumn <<
".";
54void CodegenWarningInterface::reportFunctionUsedBeforeDeclaration(
const QString &,
const QString &,
55 QQmlJS::SourceLocation,
56 QQmlJS::SourceLocation)
62 const Statement *body,
const SourceLocation &fallback)
67 case Statement::Kind_ConditionalExpression:
68 case Statement::Kind_ForEachStatement:
69 case Statement::Kind_ForStatement:
70 case Statement::Kind_IfStatement:
71 case Statement::Kind_WhileStatement:
72 bytecodeGenerator->setLocation(fallback);
75 bytecodeGenerator->setLocation(body->lastSourceLocation());
80void Codegen::generateThrowException(
const QString &type,
const QString &text)
82 RegisterScope scope(
this);
83 Instruction::Construct construct;
89 Instruction::LoadRuntimeString load;
90 load.stringId = registerString(text);
91 bytecodeGenerator->addInstruction(load);
92 construct.argv = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
94 Reference r = referenceForName(type,
false);
96 construct.func = r.stackSlot();
97 bytecodeGenerator->addInstruction(construct);
98 Instruction::ThrowException throwException;
99 bytecodeGenerator->addInstruction(throwException);
102Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
bool strict,
103 CodegenWarningInterface *iface,
bool storeSourceLocations)
107 _labelledStatement(
nullptr),
108 jsUnitGenerator(jsUnitGenerator),
110 storeSourceLocations(storeSourceLocations),
111 _fileNameIsUrl(
false),
114 jsUnitGenerator->codeGeneratorName = QStringLiteral(
"moth");
119 QLatin1StringView(
"Array"),
120 QLatin1StringView(
"ArrayBuffer"),
121 QLatin1StringView(
"Atomics"),
122 QLatin1StringView(
"Boolean"),
123 QLatin1StringView(
"DOMException"),
124 QLatin1StringView(
"DataView"),
125 QLatin1StringView(
"Date"),
126 QLatin1StringView(
"Error"),
127 QLatin1StringView(
"EvalError"),
128 QLatin1StringView(
"Float32Array"),
129 QLatin1StringView(
"Float64Array"),
130 QLatin1StringView(
"Function"),
131 QLatin1StringView(
"Infinity"),
132 QLatin1StringView(
"Int16Array"),
133 QLatin1StringView(
"Int32Array"),
134 QLatin1StringView(
"Int8Array"),
135 QLatin1StringView(
"JSON"),
136 QLatin1StringView(
"Map"),
137 QLatin1StringView(
"Math"),
138 QLatin1StringView(
"NaN"),
139 QLatin1StringView(
"Number"),
140 QLatin1StringView(
"Object"),
141 QLatin1StringView(
"Promise"),
142 QLatin1StringView(
"Proxy"),
143 QLatin1StringView(
"QT_TRANSLATE_NOOP"),
144 QLatin1StringView(
"QT_TRID_NOOP"),
145 QLatin1StringView(
"QT_TR_NOOP"),
146 QLatin1StringView(
"Qt"),
147 QLatin1StringView(
"RangeError"),
148 QLatin1StringView(
"ReferenceError"),
149 QLatin1StringView(
"Reflect"),
150 QLatin1StringView(
"RegExp"),
151 QLatin1StringView(
"SQLException"),
152 QLatin1StringView(
"Set"),
153 QLatin1StringView(
"SharedArrayBuffer"),
154 QLatin1StringView(
"String"),
155 QLatin1StringView(
"Symbol"),
156 QLatin1StringView(
"SyntaxError"),
157 QLatin1StringView(
"TypeError"),
158 QLatin1StringView(
"URIError"),
159 QLatin1StringView(
"URL"),
160 QLatin1StringView(
"URLSearchParams"),
161 QLatin1StringView(
"Uint16Array"),
162 QLatin1StringView(
"Uint32Array"),
163 QLatin1StringView(
"Uint8Array"),
164 QLatin1StringView(
"Uint8ClampedArray"),
165 QLatin1StringView(
"WeakMap"),
166 QLatin1StringView(
"WeakSet"),
167 QLatin1StringView(
"XMLHttpRequest"),
168 QLatin1StringView(
"console"),
169 QLatin1StringView(
"decodeURI"),
170 QLatin1StringView(
"decodeURIComponent"),
171 QLatin1StringView(
"encodeURI"),
172 QLatin1StringView(
"encodeURIComponent"),
173 QLatin1StringView(
"escape"),
174 QLatin1StringView(
"eval"),
175 QLatin1StringView(
"gc"),
176 QLatin1StringView(
"isFinite"),
177 QLatin1StringView(
"isNaN"),
178 QLatin1StringView(
"parseFloat"),
179 QLatin1StringView(
"parseInt"),
180 QLatin1StringView(
"print"),
181 QLatin1StringView(
"qsTr"),
182 QLatin1StringView(
"qsTrId"),
183 QLatin1StringView(
"qsTranslate"),
184 QLatin1StringView(
"undefined"),
185 QLatin1StringView(
"unescape"),
188bool Codegen::isNameGlobal(QAnyStringView name)
190 return std::binary_search(std::begin(s_globalNames), std::end(s_globalNames), name);
193void Codegen::forEachGlobalName(qxp::function_ref<
void (QLatin1StringView)> &&handler)
195 for (QLatin1StringView name : s_globalNames)
199void Codegen::generateFromProgram(
200 const QString &sourceCode, Program *node, Module *module, ContextType contextType)
207 ScanFunctions scan(
this, sourceCode, contextType);
213 defineFunction(QStringLiteral(
"%entry"), node,
nullptr, node->statements);
216void Codegen::generateFromModule(
const QString &sourceCode, ESModule *node, Module *module)
223 ScanFunctions scan(
this, sourceCode, ContextType::ESModule);
230 Compiler::Context *moduleContext = _module->contextMap.value(node);
231 for (
const auto &entry: moduleContext->exportEntries) {
232 if (entry.moduleRequest.isEmpty()) {
234 _module->localExportEntries << entry;
235 }
else if (entry.importName == QLatin1Char(
'*')) {
236 _module->starExportEntries << entry;
238 _module->indirectExportEntries << entry;
241 _module->importEntries = moduleContext->importEntries;
243 _module->moduleRequests = std::move(moduleContext->moduleRequests);
244 _module->moduleRequests.removeDuplicates();
247 std::sort(_module->localExportEntries.begin(), _module->localExportEntries.end(), ExportEntry::lessThan);
248 std::sort(_module->starExportEntries.begin(), _module->starExportEntries.end(), ExportEntry::lessThan);
249 std::sort(_module->indirectExportEntries.begin(), _module->indirectExportEntries.end(), ExportEntry::lessThan);
251 defineFunction(QStringLiteral(
"%entry"), node,
nullptr, node->body);
254void Codegen::generateFromModule(
const Value &value, Module *module)
259 _module->newContext(
nullptr,
nullptr, ContextType::ESModule);
260 enterContext(
nullptr);
262 _context->name = QStringLiteral(
"%entry");
263 _module->functions.append(_context);
264 _context->functionIndex = _module->functions.size() - 1;
267 entry.localName = entry.exportName = QLatin1String(
"default");
268 _module->localExportEntries << entry;
270 if (Object *o = value.objectValue()) {
272 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
273 QV4::PropertyAttributes attrs;
274 QV4::ScopedPropertyKey name(scope);
276 name = it.next(
nullptr, &attrs);
277 if (!name->isValid())
281 entry.localName = entry.exportName = name->toQString();
282 _module->localExportEntries << entry;
286 std::sort(_module->localExportEntries.begin(), _module->localExportEntries.end(),
287 ExportEntry::lessThan);
289 for (
auto it = _module->localExportEntries.cbegin(), end = _module->localExportEntries.cend();
291 Context::Member member;
292 member.index = _context->locals.size();
293 _context->locals.append(it->exportName);
294 _context->members.insert(it->exportName, member);
300void Codegen::enterContext(Node *node)
302 _context = _module->contextMap.value(node);
306int Codegen::leaveContext()
309 int functionIndex = _context->functionIndex;
310 _context = _context->parent;
311 return functionIndex;
314Context *Codegen::enterBlock(Node *node)
320Codegen::Reference Codegen::unop(UnaryOperation op,
const Reference &expr)
325 if (expr.isConstant()) {
326 auto v = StaticValue::fromReturnedValue(expr.constant);
330 return Reference::fromConst(
this, Encode(!v.toBoolean()));
335 int intVal = v.integerValue();
336 if (intVal && intVal != std::numeric_limits<
int>::min())
337 r = QV4::Encode(-intVal);
339 r = QV4::Encode(-
double(intVal));
340 }
else if (v.isDouble()) {
341 r = QV4::Encode(-v.doubleValue());
343 r = QV4::Encode(-v.int_32());
345 return Reference::fromConst(
this, r);
349 return Reference::fromConst(
this, Encode((
int)~v.toInt32()));
358 expr.loadInAccumulator();
359 Instruction::UMinus uminus = {};
360 bytecodeGenerator->addInstruction(uminus);
361 return Reference::fromAccumulator(
this);
364 expr.loadInAccumulator();
365 Instruction::UPlus uplus = {};
366 bytecodeGenerator->addInstruction(uplus);
367 return Reference::fromAccumulator(
this);
370 expr.loadInAccumulator();
371 Instruction::UNot unot;
372 bytecodeGenerator->addInstruction(unot);
373 return Reference::fromAccumulator(
this);
376 expr.loadInAccumulator();
377 Instruction::UCompl ucompl;
378 bytecodeGenerator->addInstruction(ucompl);
379 return Reference::fromAccumulator(
this);
382 if (!exprAccept(nx) || requiresReturnValue) {
383 Reference e = expr.asLValue();
384 e.loadInAccumulator();
385 Instruction::UPlus uplus = {};
386 bytecodeGenerator->addInstruction(uplus);
387 Reference originalValue = Reference::fromStackSlot(
this).storeRetainAccumulator();
388 Instruction::Increment inc = {};
389 bytecodeGenerator->addInstruction(inc);
390 e.storeConsumeAccumulator();
391 return originalValue;
398 Reference e = expr.asLValue();
399 e.loadInAccumulator();
400 Instruction::Increment inc = {};
401 bytecodeGenerator->addInstruction(inc);
403 return e.storeConsumeAccumulator();
405 return e.storeRetainAccumulator();
408 if (!exprAccept(nx) || requiresReturnValue) {
409 Reference e = expr.asLValue();
410 e.loadInAccumulator();
411 Instruction::UPlus uplus = {};
412 bytecodeGenerator->addInstruction(uplus);
413 Reference originalValue = Reference::fromStackSlot(
this).storeRetainAccumulator();
414 Instruction::Decrement dec = {};
415 bytecodeGenerator->addInstruction(dec);
416 e.storeConsumeAccumulator();
417 return originalValue;
424 Reference e = expr.asLValue();
425 e.loadInAccumulator();
426 Instruction::Decrement dec = {};
427 bytecodeGenerator->addInstruction(dec);
429 return e.storeConsumeAccumulator();
431 return e.storeRetainAccumulator();
438void Codegen::addCJump()
440 const Result &expression = currentExpr();
441 bytecodeGenerator->addCJumpInstruction(expression.trueBlockFollowsCondition(),
442 expression.iftrue(), expression.iffalse());
445void Codegen::statement(Statement *ast)
447 RegisterScope scope(
this);
449 bytecodeGenerator->incrementStatement();
450 bytecodeGenerator->setLocation(ast->firstSourceLocation());
452 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
453 qSwap(_volatileMemoryLocations, vLocs);
455 qSwap(_volatileMemoryLocations, vLocs);
458void Codegen::statement(ExpressionNode *ast)
463 RegisterScope scope(
this);
465 bytecodeGenerator->incrementStatement();
466 pushExpr(Result(nx));
467 VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
468 qSwap(_volatileMemoryLocations, vLocs);
472 qSwap(_volatileMemoryLocations, vLocs);
473 Reference result = popResult();
477 if (result.loadTriggersSideEffect())
478 result.loadInAccumulator();
482void Codegen::condition(ExpressionNode *ast,
const BytecodeGenerator::Label *iftrue,
483 const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition)
491 pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition));
493 Result r = popExpr();
498 if (r.format() == ex) {
499 Q_ASSERT(iftrue == r.iftrue());
500 Q_ASSERT(iffalse == r.iffalse());
501 Q_ASSERT(r.result().isValid());
502 bytecodeGenerator->setLocation(ast->firstSourceLocation());
503 r.result().loadInAccumulator();
504 if (r.trueBlockFollowsCondition())
505 bytecodeGenerator->jumpFalse().link(*r.iffalse());
507 bytecodeGenerator->jumpTrue().link(*r.iftrue());
511void Codegen::program(Program *ast)
514 statementList(ast->statements);
526 for (StatementList *it = list; it; it = it->next) {
527 if (it->statement->kind == Statement::Kind_BreakStatement ||
528 it->statement->kind == Statement::Kind_ContinueStatement)
530 if (it->statement->kind == Statement::Kind_EmptyStatement ||
531 it->statement->kind == Statement::Kind_VariableDeclaration ||
532 it->statement->kind == Statement::Kind_FunctionDeclaration)
534 if (it->statement->kind == Statement::Kind_Block) {
535 CompletionState subState = completionState(
static_cast<Block *>(it->statement)->statements);
547 Node *completionStatement =
nullptr;
548 for (StatementList *it = list; it; it = it->next) {
549 if (it->statement->kind == Statement::Kind_BreakStatement ||
550 it->statement->kind == Statement::Kind_ContinueStatement)
551 return completionStatement;
552 if (it->statement->kind == Statement::Kind_ThrowStatement ||
553 it->statement->kind == Statement::Kind_ReturnStatement)
554 return it->statement;
555 if (it->statement->kind == Statement::Kind_EmptyStatement ||
556 it->statement->kind == Statement::Kind_VariableStatement ||
557 it->statement->kind == Statement::Kind_FunctionDeclaration)
559 if (it->statement->kind == Statement::Kind_Block) {
560 CompletionState state = completionState(
static_cast<Block *>(it->statement)->statements);
565 return it->statement;
570 completionStatement = it->statement;
572 return completionStatement;
575void Codegen::statementList(StatementList *ast)
580 bool _requiresReturnValue = requiresReturnValue;
583 if (!controlFlow || !controlFlow->hasLoop())
584 requiresReturnValue =
false;
586 Node *needsCompletion =
nullptr;
588 if (_requiresReturnValue && !requiresReturnValue)
589 needsCompletion = completionStatement(ast);
591 if (requiresReturnValue && !needsCompletion && !insideSwitch) {
593 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
596 bool _insideSwitch = insideSwitch;
597 insideSwitch =
false;
599 for (StatementList *it = ast; it; it = it->next) {
600 if (it->statement == needsCompletion)
601 requiresReturnValue =
true;
602 if (Statement *s = it->statement->statementCast())
605 statement(
static_cast<ExpressionNode *>(it->statement));
606 if (it->statement == needsCompletion)
607 requiresReturnValue =
false;
608 if (it->statement->kind == Statement::Kind_ThrowStatement
609 || it->statement->kind == Statement::Kind_BreakStatement
610 || it->statement->kind == Statement::Kind_ContinueStatement
611 || it->statement->kind == Statement::Kind_ReturnStatement) {
613 if (Visitor *visitor = _interface->unreachableVisitor())
614 Node::accept(it->next, visitor);
618 requiresReturnValue = _requiresReturnValue;
619 insideSwitch = _insideSwitch;
622void Codegen::variableDeclaration(PatternElement *ast)
624 TailCallBlocker blockTailCalls(
this);
625 RegisterScope scope(
this);
627 if (!ast->initializer) {
628 if (ast->isLexicallyScoped()) {
629 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
630 Reference varToStore = targetForPatternElement(ast);
631 varToStore.storeConsumeAccumulator();
635 initializeAndDestructureBindingElement(ast, Reference(),
true);
638void Codegen::variableDeclarationList(VariableDeclarationList *ast)
640 for (VariableDeclarationList *it = ast; it; it = it->next) {
641 variableDeclaration(it->declaration);
645Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
647 if (!p->bindingIdentifier.isNull())
648 return referenceForName(p->bindingIdentifier.toString(),
true, p->firstSourceLocation());
649 if (!p->bindingTarget || p->destructuringPattern())
650 return Codegen::Reference::fromStackSlot(
this);
651 Reference lhs = expression(p->bindingTarget);
654 if (!lhs.isLValue()) {
655 throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral(
"Binding target is not a reference."));
658 lhs = lhs.asLValue();
662void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e,
const Reference &base,
bool isDefinition)
664 Q_ASSERT(e->type == AST::PatternElement::Binding || e->type == AST::PatternElement::RestElement);
665 RegisterScope scope(
this);
666 Reference baseRef = (base.isAccumulator()) ? base.storeOnStack() : base;
667 Reference varToStore = targetForPatternElement(e);
669 varToStore.isReferenceToConst =
false;
673 accept(e->typeAnnotation);
675 if (e->initializer) {
676 if (!baseRef.isValid()) {
678 Reference expr = expression(e->initializer);
681 expr.loadInAccumulator();
682 varToStore.storeConsumeAccumulator();
683 }
else if (baseRef == varToStore) {
684 baseRef.loadInAccumulator();
685 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
686 Reference expr = expression(e->initializer);
691 expr.loadInAccumulator();
692 varToStore.storeConsumeAccumulator();
695 baseRef.loadInAccumulator();
696 BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
697 Reference expr = expression(e->initializer);
702 expr.loadInAccumulator();
704 varToStore.storeConsumeAccumulator();
706 }
else if (baseRef != varToStore && baseRef.isValid()) {
707 baseRef.loadInAccumulator();
708 varToStore.storeConsumeAccumulator();
710 Pattern *p = e->destructuringPattern();
714 if (!varToStore.isStackSlot())
715 varToStore = varToStore.storeOnStack();
716 if (PatternElementList *l = e->elementList()) {
717 destructureElementList(varToStore, l, isDefinition);
718 }
else if (PatternPropertyList *p = e->propertyList()) {
719 destructurePropertyList(varToStore, p, isDefinition);
720 }
else if (e->bindingTarget) {
722 varToStore.loadInAccumulator();
723 Instruction::ToObject toObject;
724 bytecodeGenerator->addInstruction(toObject);
729Codegen::Reference Codegen::referenceForPropertyName(
const Codegen::Reference &object, AST::PropertyName *name)
731 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(name);
734 Reference computedName = expression(cname->expression);
737 computedName = computedName.storeOnStack();
738 property = Reference::fromSubscript(object, computedName).asLValue();
740 QString propertyName = name->asString();
741 property = Reference::fromMember(object, propertyName);
746void Codegen::destructurePropertyList(
const Codegen::Reference &object, PatternPropertyList *bindingList,
bool isDefinition)
748 RegisterScope scope(
this);
750 object.loadInAccumulator();
751 Instruction::ThrowOnNullOrUndefined t;
752 bytecodeGenerator->addInstruction(t);
754 for (PatternPropertyList *it = bindingList; it; it = it->next) {
755 PatternProperty *p = it->property;
756 RegisterScope scope(
this);
757 Reference property = referenceForPropertyName(object, p->name);
760 initializeAndDestructureBindingElement(p, property, isDefinition);
766void Codegen::destructureElementList(
const Codegen::Reference &array, PatternElementList *bindingList,
bool isDefinition)
768 RegisterScope scope(
this);
770 Reference iterator = Reference::fromStackSlot(
this);
771 QVarLengthArray<Reference> iteratorValues;
774 array.loadInAccumulator();
775 Instruction::GetIterator iteratorObjInstr;
776 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
777 bytecodeGenerator->addInstruction(iteratorObjInstr);
778 iterator.storeConsumeAccumulator();
780 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
781 Reference needsClose = Reference::storeConstOnStack(
this, Encode(
false));
783 for (PatternElementList *p = bindingList; p; p = p->next) {
784 PatternElement *e = p->element;
785 for (Elision *elision = p->elision; elision; elision = elision->next) {
786 iterator.loadInAccumulator();
787 Instruction::IteratorNext next;
788 if (!ignored.isValid())
789 ignored = Reference::fromStackSlot(
this);
790 next.value = ignored.stackSlot();
791 bytecodeGenerator->addJumpInstruction(next).link(done);
797 if (e->type != PatternElement::RestElement) {
798 iterator.loadInAccumulator();
799 Instruction::IteratorNext next;
800 iteratorValues.push_back(Reference::fromStackSlot(
this));
801 next.value = iteratorValues.back().stackSlot();
802 bytecodeGenerator->addJumpInstruction(next).link(done);
810 Reference::fromConst(
this, Encode(
true)).storeOnStack(needsClose.stackSlot());
813 bytecodeGenerator->checkException();
816 ControlFlowUnwindCleanup flow(
this, [&]() {
817 BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
818 needsClose.loadInAccumulator();
819 bytecodeGenerator->jumpFalse().link(skipClose);
820 iterator.loadInAccumulator();
821 Instruction::IteratorClose close;
822 bytecodeGenerator->addInstruction(close);
826 auto it = iteratorValues.constBegin();
827 for (PatternElementList *p = bindingList; p; p = p->next) {
828 PatternElement *e = p->element;
833 if (e->type == PatternElement::RestElement) {
834 Q_ASSERT(it == iteratorValues.constEnd());
837 Reference::fromConst(
this, Encode(
false)).storeOnStack(needsClose.stackSlot());
839 iterator.loadInAccumulator();
840 bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
841 initializeAndDestructureBindingElement(
842 e, Reference::fromAccumulator(
this), isDefinition);
844 Q_ASSERT(it != iteratorValues.constEnd());
845 initializeAndDestructureBindingElement(e, *it++, isDefinition);
854void Codegen::destructurePattern(Pattern *p,
const Reference &rhs)
856 RegisterScope scope(
this);
857 if (
auto *o = AST::cast<ObjectPattern *>(p))
858 destructurePropertyList(rhs, o->properties);
859 else if (
auto *a = AST::cast<ArrayPattern *>(p))
860 destructureElementList(rhs, a->elements);
866bool Codegen::visit(ArgumentList *)
868 Q_UNREACHABLE_RETURN(
false);
871bool Codegen::visit(CaseBlock *)
873 Q_UNREACHABLE_RETURN(
false);
876bool Codegen::visit(CaseClause *)
878 Q_UNREACHABLE_RETURN(
false);
881bool Codegen::visit(CaseClauses *)
883 Q_UNREACHABLE_RETURN(
false);
886bool Codegen::visit(Catch *)
888 Q_UNREACHABLE_RETURN(
false);
891bool Codegen::visit(DefaultClause *)
893 Q_UNREACHABLE_RETURN(
false);
896bool Codegen::visit(Elision *)
898 Q_UNREACHABLE_RETURN(
false);
901bool Codegen::visit(Finally *)
903 Q_UNREACHABLE_RETURN(
false);
906bool Codegen::visit(FormalParameterList *)
908 Q_UNREACHABLE_RETURN(
false);
911bool Codegen::visit(Program *)
913 Q_UNREACHABLE_RETURN(
false);
916bool Codegen::visit(PatternElement *)
918 Q_UNREACHABLE_RETURN(
false);
921bool Codegen::visit(PatternElementList *)
923 Q_UNREACHABLE_RETURN(
false);
926bool Codegen::visit(PatternProperty *)
928 Q_UNREACHABLE_RETURN(
false);
931bool Codegen::visit(PatternPropertyList *)
933 Q_UNREACHABLE_RETURN(
false);
936bool Codegen::visit(ExportDeclaration *ast)
938 if (!ast->exportDefault)
941 TailCallBlocker blockTailCalls(
this);
942 Reference exportedValue;
944 if (
auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
946 visit(
static_cast<FunctionExpression*>(fdecl));
947 exportedValue = popResult();
948 }
else if (
auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
950 visit(
static_cast<ClassExpression*>(classDecl));
951 exportedValue = popResult();
952 }
else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
953 exportedValue = expression(expr);
956 exportedValue.loadInAccumulator();
958 const int defaultExportIndex = _context->locals.indexOf(_context->localNameForDefaultExport);
959 Q_ASSERT(defaultExportIndex != -1);
960 Reference defaultExportSlot = Reference::fromScopedLocal(
this, defaultExportIndex, 0);
961 defaultExportSlot.storeConsumeAccumulator();
966bool Codegen::visit(TypeAnnotation *ast)
968 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Type annotations are not supported (yet)."));
972bool Codegen::visit(StatementList *)
974 Q_UNREACHABLE_RETURN(
false);
977bool Codegen::visit(UiArrayMemberList *)
979 Q_UNREACHABLE_RETURN(
false);
982bool Codegen::visit(UiImport *)
984 Q_UNREACHABLE_RETURN(
false);
987bool Codegen::visit(UiHeaderItemList *)
989 Q_UNREACHABLE_RETURN(
false);
992bool Codegen::visit(UiPragmaValueList *)
994 Q_UNREACHABLE_RETURN(
false);
997bool Codegen::visit(UiPragma *)
999 Q_UNREACHABLE_RETURN(
false);
1002bool Codegen::visit(UiObjectInitializer *)
1004 Q_UNREACHABLE_RETURN(
false);
1007bool Codegen::visit(UiObjectMemberList *)
1009 Q_UNREACHABLE_RETURN(
false);
1012bool Codegen::visit(UiParameterList *)
1014 Q_UNREACHABLE_RETURN(
false);
1017bool Codegen::visit(UiProgram *)
1019 Q_UNREACHABLE_RETURN(
false);
1022bool Codegen::visit(UiQualifiedId *)
1024 Q_UNREACHABLE_RETURN(
false);
1027bool Codegen::visit(VariableDeclarationList *)
1029 Q_UNREACHABLE_RETURN(
false);
1032bool Codegen::visit(ClassExpression *ast)
1034 TailCallBlocker blockTailCalls(
this);
1036 Compiler::Class jsClass;
1037 jsClass.nameIndex = registerString(ast->name.toString());
1039 ClassElementList *constructor =
nullptr;
1040 int nComputedNames = 0;
1041 int nStaticComputedNames = 0;
1043 RegisterScope scope(
this);
1044 ControlFlowBlock controlFlow(
this, ast);
1046 for (
auto *member = ast->elements; member; member = member->next) {
1047 PatternProperty *p = member->property;
1048 FunctionExpression *f = p->initializer->asFunctionDefinition();
1050 AST::ComputedPropertyName *cname = AST::cast<ComputedPropertyName *>(p->name);
1053 if (member->isStatic)
1054 ++nStaticComputedNames;
1056 QString name = p->name->asString();
1057 uint nameIndex = cname ? UINT_MAX : registerString(name);
1058 Compiler::Class::Method::Type type = Compiler::Class::Method::Regular;
1059 if (p->type == PatternProperty::Getter)
1060 type = Compiler::Class::Method::Getter;
1061 else if (p->type == PatternProperty::Setter)
1062 type = Compiler::Class::Method::Setter;
1063 Compiler::Class::Method m{ nameIndex, type,
static_cast<uint>(defineFunction(name, f, f->formals, f->body)) };
1065 if (member->isStatic) {
1066 if (name == QStringLiteral(
"prototype")) {
1067 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a static method named 'prototype'."));
1070 jsClass.staticMethods << m;
1072 if (name == QStringLiteral(
"constructor")) {
1074 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a multiple constructors in a class."));
1077 if (m.type != Compiler::Class::Method::Regular) {
1078 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"Cannot declare a getter or setter named 'constructor'."));
1081 constructor = member;
1082 jsClass.constructorIndex = m.functionIndex;
1086 jsClass.methods << m;
1090 int classIndex = _module->classes.size();
1091 _module->classes.append(jsClass);
1093 Reference heritage = Reference::fromStackSlot(
this);
1094 if (ast->heritage) {
1095 bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
1096 Reference r = expression(ast->heritage);
1099 r.storeOnStack(heritage.stackSlot());
1101 Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1102 heritage.storeConsumeAccumulator();
1105 int computedNames = nComputedNames ? bytecodeGenerator->newRegisterArray(nComputedNames) : 0;
1106 int currentStaticName = computedNames;
1107 int currentNonStaticName = computedNames + nStaticComputedNames;
1109 for (
auto *member = ast->elements; member; member = member->next) {
1110 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(member->property->name);
1113 RegisterScope scope(
this);
1114 bytecodeGenerator->setLocation(cname->firstSourceLocation());
1115 Reference computedName = expression(cname->expression);
1118 computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
1121 Instruction::CreateClass createClass;
1122 createClass.classIndex = classIndex;
1123 createClass.heritage = heritage.stackSlot();
1124 createClass.computedNames = computedNames;
1126 bytecodeGenerator->addInstruction(createClass);
1128 if (!ast->name.isEmpty()) {
1129 Reference ctor = referenceForName(ast->name.toString(),
true);
1130 ctor.isReferenceToConst =
false;
1131 (
void) ctor.storeRetainAccumulator();
1134 setExprResult(Reference::fromAccumulator(
this));
1138bool Codegen::visit(ClassDeclaration *ast)
1140 TailCallBlocker blockTailCalls(
this);
1141 Reference outerVar = referenceForName(ast->name.toString(),
true);
1142 visit(
static_cast<ClassExpression *>(ast));
1143 (
void) outerVar.storeRetainAccumulator();
1147bool Codegen::visit(CommaExpression *ast)
1152 TailCallBlocker blockTailCalls(
this);
1153 statement(ast->left);
1154 blockTailCalls.unblock();
1155 clearExprResultName();
1160bool Codegen::visit(ArrayPattern *ast)
1165 TailCallBlocker blockTailCalls(
this);
1167 PatternElementList *it = ast->elements;
1171 RegisterScope scope(
this);
1174 auto push = [
this, &argc, &args](AST::ExpressionNode *arg) {
1175 int temp = bytecodeGenerator->newRegister();
1179 auto c = Reference::fromConst(
this, StaticValue::emptyValue().asReturnedValue());
1180 (
void) c.storeOnStack(temp);
1182 RegisterScope scope(
this);
1183 Reference r = expression(arg);
1186 (
void) r.storeOnStack(temp);
1191 for (; it; it = it->next) {
1192 PatternElement *e = it->element;
1193 if (e && e->type == PatternElement::SpreadElement)
1195 for (Elision *elision = it->elision; elision; elision = elision->next)
1201 push(e->initializer);
1207 Q_ASSERT(argc == 0);
1211 Instruction::DefineArray call;
1213 call.args = Moth::StackSlot::createRegister(args);
1214 bytecodeGenerator->addInstruction(call);
1218 setExprResult(Reference::fromAccumulator(
this));
1221 Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
1223 RegisterScope scope(
this);
1224 Reference array = Reference::fromStackSlot(
this);
1225 array.storeConsumeAccumulator();
1226 Reference index = Reference::storeConstOnStack(
this, Encode(argc));
1228 auto pushAccumulator = [&]() {
1229 Reference slot = Reference::fromSubscript(array, index);
1230 slot.storeConsumeAccumulator();
1232 index.loadInAccumulator();
1233 Instruction::Increment inc = {};
1234 bytecodeGenerator->addInstruction(inc);
1235 index.storeConsumeAccumulator();
1239 for (Elision *elision = it->elision; elision; elision = elision->next) {
1240 Reference::fromConst(
1241 this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
1251 if (it->element->type == PatternElement::SpreadElement) {
1252 RegisterScope scope(
this);
1254 Reference iterator = Reference::fromStackSlot(
this);
1255 Reference lhsValue = Reference::fromStackSlot(
this);
1260 RegisterScope innerScope(
this);
1261 Reference expr = expression(it->element->initializer);
1265 expr.loadInAccumulator();
1266 Instruction::GetIterator iteratorObjInstr;
1267 iteratorObjInstr.iterator =
static_cast<
int>(AST::ForEachType::Of);
1268 bytecodeGenerator->addInstruction(iteratorObjInstr);
1269 iterator.storeConsumeAccumulator();
1272 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
1273 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
1274 BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
1277 auto cleanup = [
this, iterator, done]() {
1278 iterator.loadInAccumulator();
1279 Instruction::IteratorClose close;
1280 bytecodeGenerator->addInstruction(close);
1283 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
1286 bytecodeGenerator->addLoopStart(in);
1287 iterator.loadInAccumulator();
1288 Instruction::IteratorNext next;
1289 next.value = lhsValue.stackSlot();
1290 bytecodeGenerator->addJumpInstruction(next).link(done);
1292 lhsValue.loadInAccumulator();
1295 bytecodeGenerator->checkException();
1296 bytecodeGenerator->jump().link(in);
1300 RegisterScope innerScope(
this);
1301 Reference expr = expression(it->element->initializer);
1305 expr.loadInAccumulator();
1312 array.loadInAccumulator();
1313 setExprResult(Reference::fromAccumulator(
this));
1318bool Codegen::visit(ArrayMemberExpression *ast)
1323 const bool isTailOfChain = traverseOptionalChain(ast);
1325 TailCallBlocker blockTailCalls(
this);
1326 Reference base = expression(ast->base);
1328 auto writeSkip = [&]() {
1329 base.loadInAccumulator();
1330 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
1331 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
1332 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
1337 if (base.isSuper()) {
1338 Reference index = expression(ast->expression).storeOnStack();
1339 optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
1342 base = base.storeOnStack();
1345 if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
1346 QString s = str->value.toString();
1347 uint arrayIndex = stringToArrayIndex(s);
1348 if (arrayIndex == UINT_MAX) {
1349 auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
1351 &m_optionalChainsStates.top().jumpsToPatch);
1353 optionalChainFinalizer(ref, isTailOfChain);
1357 if (ast->isOptional)
1360 Reference index = Reference::fromConst(
this, QV4::Encode(arrayIndex));
1361 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1366 if (ast->isOptional)
1369 Reference index = expression(ast->expression);
1374 optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
1380 switch ((QSOperator::Op) op) {
1381 case QSOperator::InplaceAnd:
return QSOperator::BitAnd;
1382 case QSOperator::InplaceSub:
return QSOperator::Sub;
1383 case QSOperator::InplaceDiv:
return QSOperator::Div;
1384 case QSOperator::InplaceAdd:
return QSOperator::Add;
1385 case QSOperator::InplaceLeftShift:
return QSOperator::LShift;
1386 case QSOperator::InplaceMod:
return QSOperator::Mod;
1387 case QSOperator::InplaceExp:
return QSOperator::Exp;
1388 case QSOperator::InplaceMul:
return QSOperator::Mul;
1389 case QSOperator::InplaceOr:
return QSOperator::BitOr;
1390 case QSOperator::InplaceRightShift:
return QSOperator::RShift;
1391 case QSOperator::InplaceURightShift:
return QSOperator::URShift;
1392 case QSOperator::InplaceXor:
return QSOperator::BitXor;
1393 default:
return QSOperator::Invalid;
1397bool Codegen::visit(BinaryExpression *ast)
1402 TailCallBlocker blockTailCalls(
this);
1404 if (ast->op == QSOperator::And) {
1405 if (exprAccept(cx)) {
1406 auto iftrue = bytecodeGenerator->newLabel();
1407 condition(ast->left, &iftrue, currentExpr().iffalse(),
true);
1409 blockTailCalls.unblock();
1410 const Result &expr = currentExpr();
1411 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1413 auto iftrue = bytecodeGenerator->newLabel();
1414 auto endif = bytecodeGenerator->newLabel();
1416 Reference left = expression(ast->left);
1419 left.loadInAccumulator();
1421 bytecodeGenerator->setLocation(ast->operatorToken);
1422 bytecodeGenerator->jumpFalse().link(endif);
1425 blockTailCalls.unblock();
1426 Reference right = expression(ast->right);
1429 right.loadInAccumulator();
1433 setExprResult(Reference::fromAccumulator(
this));
1436 }
else if (ast->op == QSOperator::Or) {
1437 if (exprAccept(cx)) {
1438 auto iffalse = bytecodeGenerator->newLabel();
1439 condition(ast->left, currentExpr().iftrue(), &iffalse,
false);
1441 const Result &expr = currentExpr();
1442 condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
1444 auto iffalse = bytecodeGenerator->newLabel();
1445 auto endif = bytecodeGenerator->newLabel();
1447 Reference left = expression(ast->left);
1450 left.loadInAccumulator();
1452 bytecodeGenerator->setLocation(ast->operatorToken);
1453 bytecodeGenerator->jumpTrue().link(endif);
1456 blockTailCalls.unblock();
1457 Reference right = expression(ast->right);
1460 right.loadInAccumulator();
1464 setExprResult(Reference::fromAccumulator(
this));
1467 }
else if (ast->op == QSOperator::Coalesce) {
1469 Reference left = expression(ast->left);
1473 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
1475 Instruction::CmpEqNull cmp;
1477 left = left.storeOnStack();
1478 left.loadInAccumulator();
1479 bytecodeGenerator->addInstruction(cmp);
1481 bytecodeGenerator->jumpTrue().link(iftrue);
1483 blockTailCalls.unblock();
1485 left.loadInAccumulator();
1486 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
1489 Reference right = expression(ast->right);
1490 right.loadInAccumulator();
1492 setExprResult(Reference::fromAccumulator(
this));
1495 }
else if (ast->op == QSOperator::Assign) {
1496 bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
1497 if (AST::Pattern *p = ast->left->patternCast()) {
1498 RegisterScope scope(
this);
1499 Reference right = expression(ast->right);
1502 right = right.storeOnStack();
1503 destructurePattern(p, right);
1504 if (!exprAccept(nx)) {
1505 right.loadInAccumulator();
1506 setExprResult(Reference::fromAccumulator(
this));
1510 Reference left = expression(ast->left);
1514 if (!left.isLValue()) {
1515 throwReferenceError(ast->operatorToken, QStringLiteral(
"left-hand side of assignment operator is not an lvalue"));
1518 left = left.asLValue();
1519 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1521 blockTailCalls.unblock();
1522 Reference r = expression(ast->right);
1525 r.loadInAccumulator();
1527 setExprResult(left.storeConsumeAccumulator());
1529 setExprResult(left.storeRetainAccumulator());
1533 Reference left = expression(ast->left);
1538 case QSOperator::Or:
1539 case QSOperator::And:
1540 case QSOperator::Assign:
1544 case QSOperator::InplaceAnd:
1545 case QSOperator::InplaceSub:
1546 case QSOperator::InplaceDiv:
1547 case QSOperator::InplaceAdd:
1548 case QSOperator::InplaceLeftShift:
1549 case QSOperator::InplaceMod:
1550 case QSOperator::InplaceExp:
1551 case QSOperator::InplaceMul:
1552 case QSOperator::InplaceOr:
1553 case QSOperator::InplaceRightShift:
1554 case QSOperator::InplaceURightShift:
1555 case QSOperator::InplaceXor: {
1556 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
1559 if (!left.isLValue()) {
1560 throwSyntaxError(ast->operatorToken, QStringLiteral(
"left-hand side of inplace operator is not an lvalue"));
1563 left = left.asLValue();
1565 Reference tempLeft = left.storeOnStack();
1566 Reference right = expression(ast->right);
1571 binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
1572 setExprResult(left.storeRetainAccumulator());
1577 case QSOperator::BitAnd:
1578 case QSOperator::BitOr:
1579 case QSOperator::BitXor:
1580 if (left.isConstant()) {
1581 Reference right = expression(ast->right);
1584 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), right, left));
1588 case QSOperator::In:
1589 case QSOperator::InstanceOf:
1590 case QSOperator::As:
1591 case QSOperator::Equal:
1592 case QSOperator::NotEqual:
1593 case QSOperator::Ge:
1594 case QSOperator::Gt:
1595 case QSOperator::Le:
1596 case QSOperator::Lt:
1597 case QSOperator::StrictEqual:
1598 case QSOperator::StrictNotEqual:
1599 case QSOperator::Add:
1600 case QSOperator::Div:
1601 case QSOperator::Exp:
1602 case QSOperator::Mod:
1603 case QSOperator::Mul:
1604 case QSOperator::Sub:
1605 case QSOperator::LShift:
1606 case QSOperator::RShift:
1607 case QSOperator::URShift: {
1609 if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
1611 right = exprResult();
1613 left = left.storeOnStack();
1614 right = expression(ast->right);
1619 setExprResult(binopHelper(ast,
static_cast<QSOperator::Op>(ast->op), left, right));
1628Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
1631 auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
1632 bytecodeGenerator->setLocation(loc);
1634 case QSOperator::Add: {
1635 left = left.storeOnStack();
1636 right.loadInAccumulator();
1637 Instruction::Add add;
1638 add.lhs = left.stackSlot();
1639 bytecodeGenerator->addInstruction(add);
1642 case QSOperator::Sub: {
1643 if (right.isConstant() && right.constant == Encode(
int(1))) {
1644 left.loadInAccumulator();
1645 Instruction::Decrement dec = {};
1646 bytecodeGenerator->addInstruction(dec);
1648 left = left.storeOnStack();
1649 right.loadInAccumulator();
1650 Instruction::Sub sub;
1651 sub.lhs = left.stackSlot();
1652 bytecodeGenerator->addInstruction(sub);
1656 case QSOperator::Exp: {
1657 left = left.storeOnStack();
1658 right.loadInAccumulator();
1659 Instruction::Exp exp;
1660 exp.lhs = left.stackSlot();
1661 bytecodeGenerator->addInstruction(exp);
1664 case QSOperator::Mul: {
1665 left = left.storeOnStack();
1666 right.loadInAccumulator();
1667 Instruction::Mul mul;
1668 mul.lhs = left.stackSlot();
1669 bytecodeGenerator->addInstruction(mul);
1672 case QSOperator::Div: {
1673 left = left.storeOnStack();
1674 right.loadInAccumulator();
1675 Instruction::Div div;
1676 div.lhs = left.stackSlot();
1677 bytecodeGenerator->addInstruction(div);
1680 case QSOperator::Mod: {
1681 left = left.storeOnStack();
1682 right.loadInAccumulator();
1683 Instruction::Mod mod;
1684 mod.lhs = left.stackSlot();
1685 bytecodeGenerator->addInstruction(mod);
1688 case QSOperator::BitAnd:
1689 if (right.isConstant()) {
1690 int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
1691 if (left.isConstant()) {
1692 int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
1693 return Reference::fromConst(
this, Encode(result));
1695 left.loadInAccumulator();
1696 Instruction::BitAndConst bitAnd;
1697 bitAnd.rhs = rightAsInt;
1698 bytecodeGenerator->addInstruction(bitAnd);
1700 right.loadInAccumulator();
1701 Instruction::BitAnd bitAnd;
1702 bitAnd.lhs = left.stackSlot();
1703 bytecodeGenerator->addInstruction(bitAnd);
1706 case QSOperator::BitOr:
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::BitOrConst bitOr;
1715 bitOr.rhs = rightAsInt;
1716 bytecodeGenerator->addInstruction(bitOr);
1718 right.loadInAccumulator();
1719 Instruction::BitOr bitOr;
1720 bitOr.lhs = left.stackSlot();
1721 bytecodeGenerator->addInstruction(bitOr);
1724 case QSOperator::BitXor:
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::BitXorConst bitXor;
1733 bitXor.rhs = rightAsInt;
1734 bytecodeGenerator->addInstruction(bitXor);
1736 right.loadInAccumulator();
1737 Instruction::BitXor bitXor;
1738 bitXor.lhs = left.stackSlot();
1739 bytecodeGenerator->addInstruction(bitXor);
1742 case QSOperator::URShift:
1743 if (right.isConstant()) {
1744 left.loadInAccumulator();
1745 Instruction::UShrConst ushr;
1746 ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1747 bytecodeGenerator->addInstruction(ushr);
1749 right.loadInAccumulator();
1750 Instruction::UShr ushr;
1751 ushr.lhs = left.stackSlot();
1752 bytecodeGenerator->addInstruction(ushr);
1755 case QSOperator::RShift:
1756 if (right.isConstant()) {
1757 left.loadInAccumulator();
1758 Instruction::ShrConst shr;
1759 shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1760 bytecodeGenerator->addInstruction(shr);
1762 right.loadInAccumulator();
1763 Instruction::Shr shr;
1764 shr.lhs = left.stackSlot();
1765 bytecodeGenerator->addInstruction(shr);
1768 case QSOperator::LShift:
1769 if (right.isConstant()) {
1770 left.loadInAccumulator();
1771 Instruction::ShlConst shl;
1772 shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
1773 bytecodeGenerator->addInstruction(shl);
1775 right.loadInAccumulator();
1776 Instruction::Shl shl;
1777 shl.lhs = left.stackSlot();
1778 bytecodeGenerator->addInstruction(shl);
1781 case QSOperator::InstanceOf: {
1782 Instruction::CmpInstanceOf binop;
1783 left = left.storeOnStack();
1784 right.loadInAccumulator();
1785 binop.lhs = left.stackSlot();
1786 bytecodeGenerator->addInstruction(binop);
1789 case QSOperator::As: {
1791 left = left.storeOnStack();
1792 right.loadInAccumulator();
1793 as.lhs = left.stackSlot();
1794 bytecodeGenerator->addInstruction(as);
1797 case QSOperator::In: {
1798 Instruction::CmpIn binop;
1799 left = left.storeOnStack();
1800 right.loadInAccumulator();
1801 binop.lhs = left.stackSlot();
1802 bytecodeGenerator->addInstruction(binop);
1805 case QSOperator::StrictEqual: {
1807 return jumpBinop(oper, left, right);
1809 Instruction::CmpStrictEqual cmp;
1810 left = left.storeOnStack();
1811 right.loadInAccumulator();
1812 cmp.lhs = left.stackSlot();
1813 bytecodeGenerator->addInstruction(cmp);
1816 case QSOperator::StrictNotEqual: {
1818 return jumpBinop(oper, left, right);
1820 Instruction::CmpStrictNotEqual cmp;
1821 left = left.storeOnStack();
1822 right.loadInAccumulator();
1823 cmp.lhs = left.stackSlot();
1824 bytecodeGenerator->addInstruction(cmp);
1827 case QSOperator::Equal: {
1829 return jumpBinop(oper, left, right);
1831 Instruction::CmpEq cmp;
1832 left = left.storeOnStack();
1833 right.loadInAccumulator();
1834 cmp.lhs = left.stackSlot();
1835 bytecodeGenerator->addInstruction(cmp);
1838 case QSOperator::NotEqual: {
1840 return jumpBinop(oper, left, right);
1842 Instruction::CmpNe cmp;
1843 left = left.storeOnStack();
1844 right.loadInAccumulator();
1845 cmp.lhs = left.stackSlot();
1846 bytecodeGenerator->addInstruction(cmp);
1849 case QSOperator::Gt: {
1851 return jumpBinop(oper, left, right);
1853 Instruction::CmpGt cmp;
1854 left = left.storeOnStack();
1855 right.loadInAccumulator();
1856 cmp.lhs = left.stackSlot();
1857 bytecodeGenerator->addInstruction(cmp);
1860 case QSOperator::Ge: {
1862 return jumpBinop(oper, left, right);
1864 Instruction::CmpGe cmp;
1865 left = left.storeOnStack();
1866 right.loadInAccumulator();
1867 cmp.lhs = left.stackSlot();
1868 bytecodeGenerator->addInstruction(cmp);
1871 case QSOperator::Lt: {
1873 return jumpBinop(oper, left, right);
1875 Instruction::CmpLt cmp;
1876 left = left.storeOnStack();
1877 right.loadInAccumulator();
1878 cmp.lhs = left.stackSlot();
1879 bytecodeGenerator->addInstruction(cmp);
1882 case QSOperator::Le:
1884 return jumpBinop(oper, left, right);
1886 Instruction::CmpLe cmp;
1887 left = left.storeOnStack();
1888 right.loadInAccumulator();
1889 cmp.lhs = left.stackSlot();
1890 bytecodeGenerator->addInstruction(cmp);
1896 return Reference::fromAccumulator(
this);
1899Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right)
1902 if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) {
1904 if (left.isConstant() && !right.isConstant())
1907 if (right.isConstant()) {
1908 StaticValue c = StaticValue::fromReturnedValue(right.constant);
1909 if (c.isNull() || c.isUndefined()) {
1910 left.loadInAccumulator();
1911 if (oper == QSOperator::Equal) {
1912 Instruction::CmpEqNull cmp;
1913 bytecodeGenerator->addInstruction(cmp);
1916 }
else if (oper == QSOperator::NotEqual) {
1917 Instruction::CmpNeNull cmp;
1918 bytecodeGenerator->addInstruction(cmp);
1922 }
else if (c.isInt32()) {
1923 left.loadInAccumulator();
1924 if (oper == QSOperator::Equal) {
1925 Instruction::CmpEqInt cmp;
1926 cmp.lhs = c.int_32();
1927 bytecodeGenerator->addInstruction(cmp);
1930 }
else if (oper == QSOperator::NotEqual) {
1931 Instruction::CmpNeInt cmp;
1932 cmp.lhs = c.int_32();
1933 bytecodeGenerator->addInstruction(cmp);
1942 left = left.storeOnStack();
1943 right.loadInAccumulator();
1946 case QSOperator::StrictEqual: {
1947 Instruction::CmpStrictEqual cmp;
1948 cmp.lhs = left.stackSlot();
1949 bytecodeGenerator->addInstruction(cmp);
1953 case QSOperator::StrictNotEqual: {
1954 Instruction::CmpStrictNotEqual cmp;
1955 cmp.lhs = left.stackSlot();
1956 bytecodeGenerator->addInstruction(cmp);
1960 case QSOperator::Equal: {
1961 Instruction::CmpEq cmp;
1962 cmp.lhs = left.stackSlot();
1963 bytecodeGenerator->addInstruction(cmp);
1967 case QSOperator::NotEqual: {
1968 Instruction::CmpNe cmp;
1969 cmp.lhs = left.stackSlot();
1970 bytecodeGenerator->addInstruction(cmp);
1974 case QSOperator::Gt: {
1975 Instruction::CmpGt cmp;
1976 cmp.lhs = left.stackSlot();
1977 bytecodeGenerator->addInstruction(cmp);
1981 case QSOperator::Ge: {
1982 Instruction::CmpGe cmp;
1983 cmp.lhs = left.stackSlot();
1984 bytecodeGenerator->addInstruction(cmp);
1988 case QSOperator::Lt: {
1989 Instruction::CmpLt cmp;
1990 cmp.lhs = left.stackSlot();
1991 bytecodeGenerator->addInstruction(cmp);
1995 case QSOperator::Le: {
1996 Instruction::CmpLe cmp;
1997 cmp.lhs = left.stackSlot();
1998 bytecodeGenerator->addInstruction(cmp);
2008Codegen::Reference Codegen::loadSubscriptForCall(
const Codegen::Reference &base)
2012 base.elementSubscript.loadInAccumulator();
2013 Codegen::Instruction::LoadElement load;
2014 load.base = base.elementBase;
2015 bytecodeGenerator->addInstruction(load);
2016 return Reference::fromAccumulator(
this);
2019bool Codegen::visit(CallExpression *ast)
2024 const bool isTailOfChain = traverseOptionalChain(ast);
2026 RegisterScope scope(
this);
2027 TailCallBlocker blockTailCalls(
this);
2029 Reference expr = expression(ast->base);
2030 Reference base = expr;
2034 switch (base.type) {
2035 case Reference::Member:
2036 base = base.asLValue();
2038 case Reference::Subscript:
2039 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2040 base.subscriptLoadedForCall =
true;
2042 case Reference::Name:
2044 case Reference::Super:
2045 handleConstruct(base, ast->arguments);
2047 case Reference::SuperProperty:
2050 base = base.storeOnStack();
2054 if (expr.hasSavedCallBaseSlot) {
2056 base.hasSavedCallBaseSlot =
true;
2057 base.savedCallBaseSlot = expr.savedCallBaseSlot;
2058 base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
2061 int thisObject = bytecodeGenerator->newRegister();
2062 int functionObject = bytecodeGenerator->newRegister();
2064 if (ast->isOptional || m_optionalChainsStates.top().actuallyHasOptionals) {
2065 base.loadInAccumulator();
2066 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2067 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2068 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2071 auto calldata = pushArgs(ast->arguments);
2075 blockTailCalls.unblock();
2076 if (calldata.hasSpread || _tailCallsAreAllowed) {
2077 Reference baseObject = base.baseObject();
2078 if (!baseObject.isStackSlot()) {
2079 baseObject.storeOnStack(thisObject);
2080 baseObject = Reference::fromStackSlot(
this, thisObject);
2083 const int func = [&]() {
2084 if (base.type == Reference::Subscript)
2085 return base.element;
2087 if (!base.isStackSlot()) {
2088 base.storeOnStack(functionObject);
2089 base = Reference::fromStackSlot(
this, functionObject);
2092 return base.stackSlot();
2095 if (calldata.hasSpread) {
2096 Instruction::CallWithSpread call;
2098 call.thisObject = baseObject.stackSlot();
2099 call.argc = calldata.argc;
2100 call.argv = calldata.argv;
2101 bytecodeGenerator->addInstruction(call);
2103 Instruction::TailCall call;
2105 call.thisObject = baseObject.stackSlot();
2106 call.argc = calldata.argc;
2107 call.argv = calldata.argv;
2108 bytecodeGenerator->addInstruction(call);
2111 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2115 handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
2116 optionalChainFinalizer(Reference::fromAccumulator(
this), isTailOfChain);
2120void Codegen::endVisit(CallExpression *ast)
2122 m_seenOptionalChainNodes.remove(ast);
2125void Codegen::handleCall(Reference &base, Arguments calldata,
int slotForFunction,
int slotForThisObject,
bool optional)
2127 if (base.sourceLocation.isValid())
2128 bytecodeGenerator->setLocation(base.sourceLocation);
2131 if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
2132 if (useFastLookups) {
2133 Instruction::CallPropertyLookup call;
2134 if (base.hasSavedCallBaseSlot) {
2135 call.base = base.savedCallBaseSlot;
2136 call.lookupIndex = registerGetterLookup(
2137 base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
2139 call.base = base.propertyBase.stackSlot();
2140 call.lookupIndex = registerGetterLookup(
2141 base.propertyNameIndex, JSUnitGenerator::LookupForCall);
2143 call.argc = calldata.argc;
2144 call.argv = calldata.argv;
2145 bytecodeGenerator->addInstruction(call);
2147 Instruction::CallProperty call;
2148 if (base.hasSavedCallBaseSlot) {
2149 call.base = base.savedCallBaseSlot;
2150 call.name = base.savedCallPropertyNameIndex;
2152 call.base = base.propertyBase.stackSlot();
2153 call.name = base.propertyNameIndex;
2155 call.argc = calldata.argc;
2156 call.argv = calldata.argv;
2157 bytecodeGenerator->addInstruction(call);
2159 }
else if (base.type == Reference::Subscript) {
2160 Instruction::CallWithReceiver call;
2161 call.thisObject = base.elementBase.stackSlot();
2162 call.name = base.element;
2163 call.argc = calldata.argc;
2164 call.argv = calldata.argv;
2165 bytecodeGenerator->addInstruction(call);
2166 }
else if (base.type == Reference::Name) {
2167 if (base.name == QStringLiteral(
"eval") && !optional) {
2168 Instruction::CallPossiblyDirectEval call;
2169 call.argc = calldata.argc;
2170 call.argv = calldata.argv;
2171 bytecodeGenerator->addInstruction(call);
2172 }
else if (useFastLookups && base.global) {
2173 if (base.qmlGlobal) {
2174 Instruction::CallQmlContextPropertyLookup call;
2175 call.index = registerQmlContextPropertyGetterLookup(
2176 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2177 call.argc = calldata.argc;
2178 call.argv = calldata.argv;
2179 bytecodeGenerator->addInstruction(call);
2181 Instruction::CallGlobalLookup call;
2182 call.index = registerGlobalGetterLookup(
2183 base.nameAsIndex(), JSUnitGenerator::LookupForCall);
2184 call.argc = calldata.argc;
2185 call.argv = calldata.argv;
2186 bytecodeGenerator->addInstruction(call);
2189 Instruction::CallName call;
2190 call.name = base.nameAsIndex();
2191 call.argc = calldata.argc;
2192 call.argv = calldata.argv;
2193 bytecodeGenerator->addInstruction(call);
2195 }
else if (base.type == Reference::SuperProperty) {
2196 Reference receiver = base.baseObject();
2197 if (!base.isStackSlot()) {
2198 base.storeOnStack(slotForFunction);
2199 base = Reference::fromStackSlot(
this, slotForFunction);
2201 if (!receiver.isStackSlot()) {
2202 receiver.storeOnStack(slotForThisObject);
2203 receiver = Reference::fromStackSlot(
this, slotForThisObject);
2205 Instruction::CallWithReceiver call;
2206 call.name = base.stackSlot();
2207 call.thisObject = receiver.stackSlot();
2208 call.argc = calldata.argc;
2209 call.argv = calldata.argv;
2210 bytecodeGenerator->addInstruction(call);
2212 Q_ASSERT(base.isStackSlot());
2213 Instruction::CallValue call;
2214 call.name = base.stackSlot();
2215 call.argc = calldata.argc;
2216 call.argv = calldata.argv;
2217 bytecodeGenerator->addInstruction(call);
2221Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
2223 bool hasSpread =
false;
2225 for (ArgumentList *it = args; it; it = it->next) {
2226 if (it->isSpreadElement) {
2234 return { 0, 0,
false };
2236 int calldata = bytecodeGenerator->newRegisterArray(argc);
2239 for (ArgumentList *it = args; it; it = it->next) {
2240 if (it->isSpreadElement) {
2241 Reference::fromConst(
2243 StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
2246 RegisterScope scope(
this);
2247 Reference e = expression(it->expression);
2250 if (!argc && !it->next && !hasSpread) {
2252 if (e.isStackSlot()) {
2254 return { 1, e.stackSlot(), hasSpread };
2257 (
void) e.storeOnStack(calldata + argc);
2261 return { argc, calldata, hasSpread };
2264Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
2267 for (TemplateLiteral *it = args; it; it = it->next)
2271 return { 0, 0,
false };
2273 int calldata = bytecodeGenerator->newRegisterArray(argc);
2276 for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
2277 RegisterScope scope(
this);
2278 Reference e = expression(it->expression);
2281 (
void) e.storeOnStack(calldata + argc);
2285 return { argc, calldata,
false };
2288bool Codegen::visit(ConditionalExpression *ast)
2293 RegisterScope scope(
this);
2294 TailCallBlocker blockTailCalls(
this);
2296 BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
2297 BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
2298 condition(ast->expression, &iftrue, &iffalse,
true);
2300 blockTailCalls.unblock();
2303 Reference ok = expression(ast->ok);
2306 ok.loadInAccumulator();
2307 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
2310 Reference ko = expression(ast->ko);
2315 ko.loadInAccumulator();
2318 setExprResult(Reference::fromAccumulator(
this));
2323bool Codegen::visit(DeleteExpression *ast)
2328 const bool isTailOfChain = traverseOptionalChain(ast);
2330 RegisterScope scope(
this);
2331 TailCallBlocker blockTailCalls(
this);
2332 Reference expr = expression(ast->expression);
2336 const bool chainActuallyHasOptionals = m_optionalChainsStates.top().actuallyHasOptionals;
2337 if (chainActuallyHasOptionals)
2338 Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
2340 switch (expr.type) {
2341 case Reference::SuperProperty:
2344 case Reference::StackSlot:
2345 if (!expr.stackSlotIsLocalOrArgument)
2348 case Reference::ScopedLocal:
2350 if (_context->isStrict) {
2351 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2354 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2356 case Reference::Name: {
2357 if (_context->isStrict) {
2358 throwSyntaxError(ast->deleteToken, QStringLiteral(
"Delete of an unqualified identifier in strict mode."));
2361 Instruction::DeleteName del;
2362 del.name = expr.nameAsIndex();
2363 bytecodeGenerator->addInstruction(del);
2364 setExprResult(Reference::fromAccumulator(
this));
2367 case Reference::Member: {
2369 expr = expr.asLValue();
2371 if (chainActuallyHasOptionals) {
2372 expr.loadInAccumulator();
2373 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2374 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2375 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2378 Instruction::LoadRuntimeString instr;
2379 instr.stringId = expr.propertyNameIndex;
2380 bytecodeGenerator->addInstruction(instr);
2381 Reference index = Reference::fromStackSlot(
this);
2382 index.storeConsumeAccumulator();
2383 Instruction::DeleteProperty del;
2384 del.base = expr.propertyBase.stackSlot();
2385 del.index = index.stackSlot();
2386 bytecodeGenerator->addInstruction(del);
2387 auto ref = Reference::fromAccumulator(
this);
2389 optionalChainFinalizer(ref, isTailOfChain,
true);
2392 case Reference::Subscript: {
2394 expr = expr.asLValue();
2396 if (chainActuallyHasOptionals) {
2397 expr.loadInAccumulator();
2398 bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
2399 auto jumpToUndefined = bytecodeGenerator->jumpTrue();
2400 m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
2403 Instruction::DeleteProperty del;
2404 del.base = expr.elementBase;
2405 del.index = expr.elementSubscript.stackSlot();
2406 bytecodeGenerator->addInstruction(del);
2407 auto ref = Reference::fromAccumulator(
this);
2409 optionalChainFinalizer(ref, isTailOfChain,
true);
2416 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
2420void Codegen::endVisit(DeleteExpression *ast) {
2421 m_seenOptionalChainNodes.remove(ast);
2424bool Codegen::visit(FalseLiteral *)
2429 setExprResult(Reference::fromConst(
this, QV4::Encode(
false)));
2433bool Codegen::visit(SuperLiteral *)
2438 setExprResult(Reference::fromSuper(
this));
2442bool Codegen::traverseOptionalChain(Node *node)
2444 if (m_seenOptionalChainNodes.contains(node))
2447 const auto isOptionalChainableNode = [](
const Node *node) {
2448 return node->kind == Node::Kind_FieldMemberExpression ||
2449 node->kind == Node::Kind_CallExpression ||
2450 node->kind == Node::Kind_ArrayMemberExpression ||
2451 node->kind == Node::Kind_DeleteExpression;
2453 m_optionalChainsStates.emplace();
2454 while (isOptionalChainableNode(node)) {
2455 m_seenOptionalChainNodes.insert(node);
2457 switch (node->kind) {
2458 case Node::Kind_FieldMemberExpression: {
2459 auto *fme = AST::cast<FieldMemberExpression *>(node);
2460 m_optionalChainsStates.top().actuallyHasOptionals |= fme->isOptional;
2464 case Node::Kind_CallExpression: {
2465 auto *ce = AST::cast<CallExpression *>(node);
2466 m_optionalChainsStates.top().actuallyHasOptionals |= ce->isOptional;
2470 case Node::Kind_ArrayMemberExpression: {
2471 auto *ame = AST::cast<ArrayMemberExpression *>(node);
2472 m_optionalChainsStates.top().actuallyHasOptionals |= ame->isOptional;
2476 case Node::Kind_DeleteExpression:
2477 node = AST::cast<DeleteExpression *>(node)->expression;
2487void Codegen::optionalChainFinalizer(
const Reference &expressionResult,
bool tailOfChain,
2488 bool isDeleteExpression)
2490 auto &chainState = m_optionalChainsStates.top();
2492 setExprResult(expressionResult);
2494 }
else if (!chainState.actuallyHasOptionals) {
2495 setExprResult(expressionResult);
2496 m_optionalChainsStates.pop();
2500 auto savedBaseSlot = -1;
2501 if (expressionResult.type == Reference::Member)
2502 savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
2503 expressionResult.loadInAccumulator();
2505 std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
2506 if (!isDeleteExpression)
2507 jumpToDone.emplace(bytecodeGenerator->jump());
2509 for (
auto &jump : chainState.jumpsToPatch)
2512 if (isDeleteExpression)
2513 bytecodeGenerator->addInstruction(Instruction::LoadTrue());
2515 bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
2517 if (jumpToDone.has_value())
2518 jumpToDone.value().link();
2520 auto ref = Reference::fromAccumulator(
this);
2521 if (expressionResult.type == Reference::Member) {
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534 ref.hasSavedCallBaseSlot =
true;
2535 ref.savedCallBaseSlot = savedBaseSlot;
2536 ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
2539 m_optionalChainsStates.pop();
2542bool Codegen::visit(FieldMemberExpression *ast)
2547 const bool isTailOfChain = traverseOptionalChain(ast);
2549 TailCallBlocker blockTailCalls(
this);
2551 if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
2552 if (id->name == QLatin1String(
"new")) {
2554 Q_ASSERT(ast->name == QLatin1String(
"target"));
2556 if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
2557 Reference r = referenceForName(QStringLiteral(
"new.target"),
false);
2558 r.isReadonly =
true;
2564 auto ref = Reference::fromStackSlot(
this, CallData::NewTarget);
2565 optionalChainFinalizer(ref, isTailOfChain);
2570 Reference base = expression(ast->base);
2574 if (base.isSuper()) {
2575 Instruction::LoadRuntimeString load;
2576 load.stringId = registerString(ast->name.toString());
2577 bytecodeGenerator->addInstruction(load);
2578 Reference property = Reference::fromAccumulator(
this).storeOnStack();
2580 optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
2584 auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
2585 ast->isOptional, &m_optionalChainsStates.top().jumpsToPatch);
2587 optionalChainFinalizer(ref, isTailOfChain);
2591void Codegen::endVisit(FieldMemberExpression *ast)
2593 m_seenOptionalChainNodes.remove(ast);
2596bool Codegen::visit(TaggedTemplate *ast)
2601 RegisterScope scope(
this);
2602 return handleTaggedTemplate(expression(ast->base), ast);
2605bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
2610 int functionObject = -1, thisObject = -1;
2611 switch (base.type) {
2612 case Reference::Member:
2613 base = base.asLValue();
2615 case Reference::Subscript:
2616 base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
2617 base.subscriptLoadedForCall =
true;
2619 case Reference::Name:
2621 case Reference::SuperProperty:
2622 thisObject = bytecodeGenerator->newRegister();
2623 functionObject = bytecodeGenerator->newRegister();
2626 base = base.storeOnStack();
2630 createTemplateObject(ast->templateLiteral);
2631 int templateObjectTemp = Reference::fromAccumulator(
this).storeOnStack().stackSlot();
2632 Q_UNUSED(templateObjectTemp);
2633 auto calldata = pushTemplateArgs(ast->templateLiteral);
2637 Q_ASSERT(calldata.argv == templateObjectTemp + 1);
2640 handleCall(base, calldata, functionObject, thisObject);
2641 setExprResult(Reference::fromAccumulator(
this));
2645void Codegen::createTemplateObject(TemplateLiteral *t)
2649 for (TemplateLiteral *it = t; it; it = it->next) {
2650 obj.strings.append(registerString(it->value.toString()));
2651 obj.rawStrings.append(registerString(it->rawValue.toString()));
2654 int index = _module->templateObjects.size();
2655 _module->templateObjects.append(obj);
2657 Instruction::GetTemplateObject getTemplateObject;
2658 getTemplateObject.index = index;
2659 bytecodeGenerator->addInstruction(getTemplateObject);
2662bool Codegen::visit(FunctionExpression *ast)
2667 TailCallBlocker blockTailCalls(
this);
2669 RegisterScope scope(
this);
2671 int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
2674 loadClosure(function);
2675 setExprResult(Reference::fromAccumulator(
this));
2679Codegen::Reference Codegen::referenceForName(
const QString &name,
bool isLhs,
const SourceLocation &accessLocation)
2681 Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
2682 bool throwsReferenceError =
false;
2684 if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
2685 || resolved.type == Context::ResolvedName::Import) {
2686 if (resolved.isArgOrEval && isLhs)
2688 throwSyntaxError(SourceLocation(), QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
2690 if (resolved.declarationLocation.isValid() && accessLocation.isValid()
2691 && resolved.declarationLocation.begin() > accessLocation.end()) {
2692 Q_ASSERT(_interface);
2693 if (resolved.memberType == Context::FunctionDefinition) {
2694 _interface->reportFunctionUsedBeforeDeclaration(
2695 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2697 _interface->reportVarUsedBeforeDeclaration(
2698 name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
2700 if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
2701 throwsReferenceError =
true;
2704 if (resolved.isInjected && accessLocation.isValid()) {
2705 qCWarning(lcQmlInjectedParameter).nospace().noquote()
2706 << url().toString() <<
":" << accessLocation.startLine
2707 <<
":" << accessLocation.startColumn <<
" Parameter \"" << name
2708 <<
"\" is not declared."
2709 <<
" Injection of parameters into signal handlers is deprecated."
2710 <<
" Use JavaScript functions with formal parameters instead.";
2714 switch (resolved.type) {
2715 case Context::ResolvedName::Local:
2716 r = Reference::fromScopedLocal(
this, resolved.index, resolved.scope);
break;
2717 case Context::ResolvedName::Stack:
2718 r = Reference::fromStackSlot(
this, resolved.index,
true );
break;
2719 case Context::ResolvedName::Import:
2720 r = Reference::fromImport(
this, resolved.index);
break;
2721 default: Q_UNREACHABLE();
2723 if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
2724 r.isVolatile =
true;
2725 r.isArgOrEval = resolved.isArgOrEval;
2726 r.isReferenceToConst = resolved.isConst;
2727 r.requiresTDZCheck = resolved.requiresTDZCheck;
2729 r.sourceLocation = accessLocation;
2730 r.throwsReferenceError = throwsReferenceError;
2734 Reference r = Reference::fromName(
this, name);
2735 r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
2736 r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
2737 r.sourceLocation = accessLocation;
2738 if (!r.global && !r.qmlGlobal
2739 && _context->contextType == ContextType::ScriptImportedByQML
2740 && Codegen::isNameGlobal(name)) {
2750void Codegen::loadClosure(
int closureId)
2752 if (closureId >= 0) {
2753 Instruction::LoadClosure load;
2754 load.value = closureId;
2755 bytecodeGenerator->addInstruction(load);
2757 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
2761bool Codegen::visit(IdentifierExpression *ast)
2766 setExprResult(referenceForName(ast->name.toString(),
false, ast->firstSourceLocation()));
2770bool Codegen::visit(NestedExpression *ast)
2775 accept(ast->expression);
2779void Codegen::handleConstruct(
const Reference &base, ArgumentList *arguments)
2781 Reference constructor;
2782 if (base.isSuper()) {
2783 Instruction::LoadSuperConstructor super;
2784 bytecodeGenerator->addInstruction(super);
2785 constructor = Reference::fromAccumulator(
this).storeOnStack();
2787 constructor = base.storeOnStack();
2790 auto calldata = pushArgs(arguments);
2795 Reference::fromStackSlot(
this, CallData::NewTarget).loadInAccumulator();
2797 constructor.loadInAccumulator();
2799 if (calldata.hasSpread) {
2800 Instruction::ConstructWithSpread create;
2801 create.func = constructor.stackSlot();
2802 create.argc = calldata.argc;
2803 create.argv = calldata.argv;
2804 bytecodeGenerator->addInstruction(create);
2806 Instruction::Construct create;
2807 create.func = constructor.stackSlot();
2808 create.argc = calldata.argc;
2809 create.argv = calldata.argv;
2810 bytecodeGenerator->addInstruction(create);
2814 Reference::fromAccumulator(
this).storeOnStack(CallData::This);
2816 setExprResult(Reference::fromAccumulator(
this));
2819bool Codegen::visit(NewExpression *ast)
2824 RegisterScope scope(
this);
2825 TailCallBlocker blockTailCalls(
this);
2827 Reference base = expression(ast->expression);
2830 if (base.isSuper()) {
2831 throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2835 handleConstruct(base,
nullptr);
2839bool Codegen::visit(NewMemberExpression *ast)
2844 RegisterScope scope(
this);
2845 TailCallBlocker blockTailCalls(
this);
2847 Reference base = expression(ast->base);
2850 if (base.isSuper()) {
2851 throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral(
"Cannot use new with super."));
2855 handleConstruct(base, ast->arguments);
2859bool Codegen::visit(NotExpression *ast)
2864 TailCallBlocker blockTailCalls(
this);
2865 setExprResult(unop(Not, expression(ast->expression)));
2869bool Codegen::visit(NullExpression *)
2875 bytecodeGenerator->jump().link(*currentExpr().iffalse());
2877 setExprResult(Reference::fromConst(
this, Encode::null()));
2882bool Codegen::visit(NumericLiteral *ast)
2887 setExprResult(Reference::fromConst(
this, QV4::Encode::smallestNumber(ast->value)));
2891bool Codegen::visit(ObjectPattern *ast)
2896 TailCallBlocker blockTailCalls(
this);
2898 RegisterScope scope(
this);
2900 QStringList members;
2904 auto push = [
this, &args, &argc](
const Reference &arg) {
2905 int temp = bytecodeGenerator->newRegister();
2908 (
void) arg.storeOnStack(temp);
2912 PatternPropertyList *it = ast->properties;
2913 for (; it; it = it->next) {
2914 PatternProperty *p = it->property;
2915 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2916 if (cname || p->type != PatternProperty::Literal)
2918 QString name = p->name->asString();
2919 uint arrayIndex = stringToArrayIndex(name);
2920 if (arrayIndex != UINT_MAX)
2922 if (members.contains(name))
2924 members.append(name);
2927 RegisterScope innerScope(
this);
2928 Reference value = expression(p->initializer, name);
2931 value.loadInAccumulator();
2933 push(Reference::fromAccumulator(
this));
2936 int classId = jsUnitGenerator->registerJSClass(members);
2939 for (; it; it = it->next) {
2940 PatternProperty *p = it->property;
2941 AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
2942 ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
2943 if (p->type == PatternProperty::Method)
2944 argType = ObjectLiteralArgument::Method;
2945 else if (p->type == PatternProperty::Getter)
2946 argType = ObjectLiteralArgument::Getter;
2947 else if (p->type == PatternProperty::Setter)
2948 argType = ObjectLiteralArgument::Setter;
2950 Reference::fromConst(
this, Encode(
int(argType))).loadInAccumulator();
2951 push(Reference::fromAccumulator(
this));
2954 RegisterScope innerScope(
this);
2955 Reference name = expression(cname->expression);
2958 name.loadInAccumulator();
2960 QString name = p->name->asString();
2962 uint arrayIndex = QV4::String::toArrayIndex(name);
2963 if (arrayIndex != UINT_MAX) {
2964 Reference::fromConst(
this, Encode(arrayIndex)).loadInAccumulator();
2968 Instruction::LoadRuntimeString instr;
2969 instr.stringId = registerString(name);
2970 bytecodeGenerator->addInstruction(instr);
2973 push(Reference::fromAccumulator(
this));
2975 RegisterScope innerScope(
this);
2976 if (p->type != PatternProperty::Literal) {
2978 FunctionExpression *f = p->initializer->asFunctionDefinition();
2980 int function = defineFunction(f->name.toString(), f, f->formals, f->body);
2983 Reference::fromConst(
this, Encode(function)).loadInAccumulator();
2985 Reference value = expression(p->initializer);
2988 value.loadInAccumulator();
2991 push(Reference::fromAccumulator(
this));
2994 Instruction::DefineObjectLiteral call;
2995 call.internalClassId = classId;
2997 call.args = Moth::StackSlot::createRegister(args);
2998 bytecodeGenerator->addInstruction(call);
2999 setExprResult(Reference::fromAccumulator(
this));
3003bool Codegen::visit(PostDecrementExpression *ast)
3008 Reference expr = expression(ast->base);
3011 if (!expr.isLValue()) {
3012 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3015 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3018 setExprResult(unop(PostDecrement, expr));
3023bool Codegen::visit(PostIncrementExpression *ast)
3028 Reference expr = expression(ast->base);
3031 if (!expr.isLValue()) {
3032 throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral(
"Invalid left-hand side expression in postfix operation"));
3035 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3038 setExprResult(unop(PostIncrement, expr));
3042bool Codegen::visit(PreDecrementExpression *ast)
3046 Reference expr = expression(ast->expression);
3049 if (!expr.isLValue()) {
3050 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3054 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
3056 setExprResult(unop(PreDecrement, expr));
3060bool Codegen::visit(PreIncrementExpression *ast)
3065 Reference expr = expression(ast->expression);
3068 if (!expr.isLValue()) {
3069 throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral(
"Prefix ++ operator applied to value that is not a reference."));
3073 if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
3075 setExprResult(unop(PreIncrement, expr));
3079bool Codegen::visit(RegExpLiteral *ast)
3084 auto r = Reference::fromStackSlot(
this);
3085 r.isReadonly =
true;
3088 Instruction::MoveRegExp instr;
3089 instr.regExpId = jsUnitGenerator->registerRegExp(ast);
3090 instr.destReg = r.stackSlot();
3091 bytecodeGenerator->addInstruction(instr);
3095bool Codegen::visit(StringLiteral *ast)
3100 auto r = Reference::fromAccumulator(
this);
3101 r.isReadonly =
true;
3104 Instruction::LoadRuntimeString instr;
3105 instr.stringId = registerString(ast->value.toString());
3106 bytecodeGenerator->addInstruction(instr);
3110bool Codegen::visit(TemplateLiteral *ast)
3115 TailCallBlocker blockTailCalls(
this);
3117 Instruction::LoadRuntimeString instr;
3118 instr.stringId = registerString(ast->value.toString());
3119 bytecodeGenerator->addInstruction(instr);
3121 if (ast->expression) {
3122 RegisterScope scope(
this);
3123 int temp = bytecodeGenerator->newRegister();
3124 Instruction::StoreReg store;
3126 bytecodeGenerator->addInstruction(store);
3128 Reference expr = expression(ast->expression);
3133 int temp2 = bytecodeGenerator->newRegister();
3134 expr.storeOnStack(temp2);
3137 Instruction::Add instr;
3139 bytecodeGenerator->addInstruction(instr);
3141 expr.loadInAccumulator();
3144 Instruction::Add instr;
3146 bytecodeGenerator->addInstruction(instr);
3149 auto r = Reference::fromAccumulator(
this);
3150 r.isReadonly =
true;
3157bool Codegen::visit(ThisExpression *)
3162 for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
3163 if (parentContext->isArrowFunction) {
3164 Reference r = referenceForName(QStringLiteral(
"this"),
false);
3165 r.isReadonly =
true;
3169 if (parentContext->contextType != ContextType::Block)
3173 setExprResult(Reference::fromThis(
this));
3177bool Codegen::visit(TildeExpression *ast)
3182 TailCallBlocker blockTailCalls(
this);
3183 setExprResult(unop(Compl, expression(ast->expression)));
3187bool Codegen::visit(TrueLiteral *)
3192 setExprResult(Reference::fromConst(
this, QV4::Encode(
true)));
3196bool Codegen::visit(TypeOfExpression *ast)
3201 RegisterScope scope(
this);
3202 TailCallBlocker blockTailCalls(
this);
3204 Reference expr = expression(ast->expression);
3208 if (expr.type == Reference::Name) {
3210 Instruction::TypeofName instr;
3211 instr.name = expr.nameAsIndex();
3212 bytecodeGenerator->addInstruction(instr);
3214 expr.loadInAccumulator();
3215 Instruction::TypeofValue instr;
3216 bytecodeGenerator->addInstruction(instr);
3218 setExprResult(Reference::fromAccumulator(
this));
3223bool Codegen::visit(UnaryMinusExpression *ast)
3228 TailCallBlocker blockTailCalls(
this);
3229 setExprResult(unop(UMinus, expression(ast->expression)));
3233bool Codegen::visit(UnaryPlusExpression *ast)
3238 TailCallBlocker blockTailCalls(
this);
3239 setExprResult(unop(UPlus, expression(ast->expression)));
3243bool Codegen::visit(VoidExpression *ast)
3248 RegisterScope scope(
this);
3249 TailCallBlocker blockTailCalls(
this);
3251 statement(ast->expression);
3252 setExprResult(Reference::fromConst(
this, Encode::undefined()));
3256bool Codegen::visit(FunctionDeclaration * ast)
3262 RegisterScope scope(
this);
3264 if (_functionContext->contextType == ContextType::Binding)
3265 referenceForName(ast->name.toString(),
true).loadInAccumulator();
3270bool Codegen::visit(YieldExpression *ast)
3272 if (inFormalParameterList) {
3273 throwSyntaxError(ast->firstSourceLocation(), QLatin1String(
"yield is not allowed inside parameter lists"));
3277 auto innerMostCurentFunctionContext = _context;
3278 while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
3279 innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
3281 Q_ASSERT(innerMostCurentFunctionContext);
3283 if (!innerMostCurentFunctionContext->isGenerator) {
3284 throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
3288 RegisterScope scope(
this);
3289 TailCallBlocker blockTailCalls(
this);
3290 Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(
this, Encode::undefined());
3294 Reference acc = Reference::fromAccumulator(
this);
3296 if (ast->isYieldStar) {
3297 Reference iterator = Reference::fromStackSlot(
this);
3298 Reference lhsValue = Reference::fromConst(
this, Encode::undefined()).storeOnStack();
3300 expr.loadInAccumulator();
3301 Instruction::GetIterator getIterator;
3302 getIterator.iterator =
static_cast<
int>(AST::ForEachType::Of);
3303 bytecodeGenerator->addInstruction(getIterator);
3304 iterator.storeConsumeAccumulator();
3305 Instruction::LoadUndefined load;
3306 bytecodeGenerator->addInstruction(load);
3308 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3309 bytecodeGenerator->jump().link(in);
3311 BytecodeGenerator::Label loop = bytecodeGenerator->label();
3313 lhsValue.loadInAccumulator();
3314 Instruction::YieldStar yield;
3315 bytecodeGenerator->addInstruction(yield);
3319 Instruction::IteratorNextForYieldStar next;
3320 next.object = lhsValue.stackSlot();
3321 next.iterator = iterator.stackSlot();
3322 BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
3323 bytecodeGenerator->jumpNotUndefined().link(loop);
3325 lhsValue.loadInAccumulator();
3330 bytecodeGenerator->checkException();
3332 lhsValue.loadInAccumulator();
3337 expr.loadInAccumulator();
3338 Instruction::Yield yield;
3339 bytecodeGenerator->addInstruction(yield);
3340 Instruction::Resume resume;
3341 BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
3352 if (AST::cast<ReturnStatement *>(node))
3354 if (AST::cast<ThrowStatement *>(node))
3356 if (Program *p = AST::cast<Program *>(node))
3357 return endsWithReturn(module, p->statements);
3358 if (StatementList *sl = AST::cast<StatementList *>(node)) {
3361 return endsWithReturn(module, sl->statement);
3363 if (Block *b = AST::cast<Block *>(node)) {
3364 Context *blockContext = module->contextMap.value(node);
3365 if (blockContext->requiresExecutionContext)
3369 return endsWithReturn(module, b->statements);
3371 if (IfStatement *is = AST::cast<IfStatement *>(node))
3372 return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
3376int Codegen::defineFunction(
const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
3377 AST::StatementList *body)
3381 if (_context->functionIndex >= 0)
3383 return leaveContext();
3385 _context->name = name.isEmpty() ? currentExpr().result().name : name;
3386 _module->functions.append(_context);
3387 _context->functionIndex = _module->functions.size() - 1;
3389 Context *savedFunctionContext = _functionContext;
3390 _functionContext = _context;
3391 ControlFlow *savedControlFlow = controlFlow;
3392 controlFlow =
nullptr;
3394 if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
3395 _module->blocks.append(_context);
3396 _context->blockIndex = _module->blocks.size() - 1;
3398 if (_module->debugMode)
3399 _context->argumentsCanEscape =
true;
3407 _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
3408 && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
3410 BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
3411 BytecodeGenerator *savedBytecodeGenerator;
3412 savedBytecodeGenerator = bytecodeGenerator;
3413 bytecodeGenerator = &bytecode;
3414 bytecodeGenerator->setLocation(ast->firstSourceLocation());
3415 BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
3416 _returnLabel =
nullptr;
3418 bool savedFunctionEndsWithReturn = functionEndsWithReturn;
3419 functionEndsWithReturn = endsWithReturn(_module, body);
3422 bytecodeGenerator->newRegisterArray(
3423 sizeof(CallData) /
sizeof(StaticValue) - 1 + _context->arguments.size());
3425 bool _inFormalParameterList =
false;
3426 qSwap(_inFormalParameterList, inFormalParameterList);
3428 int returnAddress = -1;
3429 bool _requiresReturnValue = _context->requiresImplicitReturnValue();
3430 qSwap(requiresReturnValue, _requiresReturnValue);
3431 returnAddress = bytecodeGenerator->newRegister();
3432 qSwap(_returnAddress, returnAddress);
3435 if (!_context->parent && _context->requiresExecutionContext) {
3436 _module->blocks.append(_context);
3437 _context->blockIndex = _module->blocks.size() - 1;
3440 TailCallBlocker maybeBlockTailCalls(
this, _context->canHaveTailCalls());
3442 RegisterScope registerScope(
this);
3443 _context->emitBlockHeader(
this);
3446 QScopedValueRollback<
bool> inFormals(inFormalParameterList,
true);
3447 TailCallBlocker blockTailCalls(
this);
3451 PatternElement *e = formals->element;
3459 Reference arg = referenceForName(e->bindingIdentifier.toString(),
true);
3460 if (e->type == PatternElement::RestElement) {
3461 Q_ASSERT(!formals->next);
3462 Instruction::CreateRestParameter rest;
3463 rest.argIndex = argc;
3464 bytecodeGenerator->addInstruction(rest);
3465 arg.storeConsumeAccumulator();
3467 if (e->bindingTarget || e->initializer) {
3468 initializeAndDestructureBindingElement(e, arg);
3473 formals = formals->next;
3478 if (_context->isGenerator) {
3479 Instruction::Yield yield;
3480 bytecodeGenerator->addInstruction(yield);
3483 statementList(body);
3486 bytecodeGenerator->setLocation(ast->lastSourceLocation());
3487 _context->emitBlockFooter(
this);
3489 if (_returnLabel || !functionEndsWithReturn) {
3491 _returnLabel->link();
3493 if (_returnLabel || requiresReturnValue) {
3494 Instruction::LoadReg load;
3495 load.reg = Moth::StackSlot::createRegister(_returnAddress);
3496 bytecodeGenerator->addInstruction(load);
3498 Reference::fromConst(
this, Encode::undefined()).loadInAccumulator();
3501 bytecodeGenerator->addInstruction(Instruction::Ret());
3504 Q_ASSERT(_context == _functionContext);
3505 bytecodeGenerator->finalize(_context);
3506 _context->registerCountInFunction = bytecodeGenerator->registerCount();
3507 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
3509 qDebug() <<
"=== Bytecode for" << _context->name <<
"strict mode" << _context->isStrict
3510 <<
"register count" << _context->registerCountInFunction <<
"implicit return" << requiresReturnValue;
3511 qDebug().noquote() << QV4::Moth::dumpBytecode(
3512 _context->code, _context->locals.size(), _context->arguments.size(),
3513 _context->line, _context->lineAndStatementNumberMapping);
3518 qSwap(_returnAddress, returnAddress);
3519 qSwap(requiresReturnValue, _requiresReturnValue);
3520 qSwap(_inFormalParameterList, inFormalParameterList);
3521 bytecodeGenerator = savedBytecodeGenerator;
3522 delete _returnLabel;
3523 _returnLabel = savedReturnLabel;
3524 controlFlow = savedControlFlow;
3525 functionEndsWithReturn = savedFunctionEndsWithReturn;
3526 _functionContext = savedFunctionContext;
3528 return leaveContext();
3531bool Codegen::visit(Block *ast)
3536 RegisterScope scope(
this);
3538 ControlFlowBlock controlFlow(
this, ast);
3539 statementList(ast->statements);
3543bool Codegen::visit(BreakStatement *ast)
3550 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3554 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
3555 if (!target.linkLabel.isValid()) {
3556 if (ast->label.isEmpty())
3557 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Break outside of loop"));
3559 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3563 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3568bool Codegen::visit(ContinueStatement *ast)
3574 RegisterScope scope(
this);
3577 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Continue outside of loop"));
3581 ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
3582 if (!target.linkLabel.isValid()) {
3583 if (ast->label.isEmpty())
3584 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"Undefined label '%1'").arg(ast->label.toString()));
3586 throwSyntaxError(ast->lastSourceLocation(), QStringLiteral(
"continue outside of loop"));
3590 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3595bool Codegen::visit(DebuggerStatement *)
3601bool Codegen::visit(DoWhileStatement *ast)
3606 RegisterScope scope(
this);
3608 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3609 BytecodeGenerator::Label cond = bytecodeGenerator->newLabel();
3610 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3612 ControlFlowLoop flow(
this, &end, &cond);
3616 if (!AST::cast<FalseLiteral *>(ast->expression))
3617 bytecodeGenerator->addLoopStart(body);
3620 statement(ast->statement);
3621 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
3624 if (AST::cast<TrueLiteral *>(ast->expression)) {
3626 bytecodeGenerator->checkException();
3627 bytecodeGenerator->jump().link(body);
3628 }
else if (AST::cast<FalseLiteral *>(ast->expression)) {
3631 TailCallBlocker blockTailCalls(
this);
3632 bytecodeGenerator->checkException();
3633 condition(ast->expression, &body, &end,
false);
3641bool Codegen::visit(EmptyStatement *)
3646bool Codegen::visit(ExpressionStatement *ast)
3651 RegisterScope scope(
this);
3652 TailCallBlocker blockTailCalls(
this);
3654 if (requiresReturnValue) {
3655 Reference e = expression(ast->expression);
3658 (
void) e.storeOnStack(_returnAddress);
3660 statement(ast->expression);
3665bool Codegen::visit(ForEachStatement *ast)
3670 RegisterScope scope(
this);
3671 TailCallBlocker blockTailCalls(
this);
3673 Reference iterator = Reference::fromStackSlot(
this);
3674 Reference lhsValue = Reference::fromStackSlot(
this);
3679 RegisterScope innerScope(
this);
3680 ControlFlowBlock controlFlow(
this, ast);
3681 Reference expr = expression(ast->expression);
3685 expr.loadInAccumulator();
3686 Instruction::GetIterator iteratorObjInstr;
3687 iteratorObjInstr.iterator =
static_cast<
int>(ast->type);
3688 bytecodeGenerator->addInstruction(iteratorObjInstr);
3689 iterator.storeConsumeAccumulator();
3692 BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
3693 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3694 BytecodeGenerator::Label done;
3697 std::function<
void()> cleanup;
3698 if (ast->type == ForEachType::Of) {
3699 done = bytecodeGenerator->newLabel();
3700 cleanup = [iterator,
this, done]() {
3701 iterator.loadInAccumulator();
3702 Instruction::IteratorClose close;
3703 bytecodeGenerator->addInstruction(close);
3709 ControlFlowLoop flow(
this, &end, &in, std::move(cleanup));
3710 bytecodeGenerator->addLoopStart(in);
3712 iterator.loadInAccumulator();
3713 Instruction::IteratorNext next;
3714 next.value = lhsValue.stackSlot();
3715 bytecodeGenerator->addJumpInstruction(next).link(done);
3719 RegisterScope innerScope(
this);
3720 ControlFlowBlock controlFlow(
this, ast);
3722 if (ExpressionNode *e = ast->lhs->expressionCast()) {
3723 if (AST::Pattern *p = e->patternCast()) {
3724 RegisterScope scope(
this);
3725 destructurePattern(p, lhsValue);
3727 Reference lhs = expression(e);
3730 if (!lhs.isLValue()) {
3731 throwReferenceError(e->firstSourceLocation(), QStringLiteral(
"Invalid left-hand side expression for 'in' expression"));
3734 lhs = lhs.asLValue();
3735 lhsValue.loadInAccumulator();
3736 lhs.storeConsumeAccumulator();
3738 }
else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
3739 initializeAndDestructureBindingElement(p, lhsValue,
true);
3746 blockTailCalls.unblock();
3747 statement(ast->statement);
3748 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3751 bytecodeGenerator->checkException();
3752 bytecodeGenerator->jump().link(in);
3764bool Codegen::visit(ForStatement *ast)
3769 RegisterScope scope(
this);
3770 TailCallBlocker blockTailCalls(
this);
3772 ControlFlowBlock controlFlow(
this, ast);
3774 if (ast->initialiser)
3775 statement(ast->initialiser);
3776 else if (ast->declarations)
3777 variableDeclarationList(ast->declarations);
3779 BytecodeGenerator::Label cond = bytecodeGenerator->label();
3780 BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
3781 BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
3782 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
3784 ControlFlowLoop flow(
this, &end, &step);
3785 bytecodeGenerator->addLoopStart(cond);
3786 condition(ast->condition, &body, &end,
true);
3789 blockTailCalls.unblock();
3790 statement(ast->statement);
3791 blockTailCalls.reblock();
3792 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
3795 if (_context->requiresExecutionContext) {
3796 Instruction::CloneBlockContext clone;
3797 bytecodeGenerator->addInstruction(clone);
3799 statement(ast->expression);
3800 bytecodeGenerator->checkException();
3801 bytecodeGenerator->jump().link(cond);
3808bool Codegen::visit(IfStatement *ast)
3813 RegisterScope scope(
this);
3814 TailCallBlocker blockTailCalls(
this);
3816 BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
3817 BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
3818 condition(ast->expression, &trueLabel, &falseLabel,
true);
3819 blockTailCalls.unblock();
3824 if (endsWithReturn(_module, ast)) {
3828 BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
3840bool Codegen::visit(LabelledStatement *ast)
3845 RegisterScope scope(
this);
3848 ControlFlow *l = controlFlow;
3850 if (l->label() == ast->label) {
3851 QString error = QString(QStringLiteral(
"Label '%1' has already been declared")).arg(ast->label.toString());
3852 throwSyntaxError(ast->firstSourceLocation(), error);
3857 _labelledStatement = ast;
3859 if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
3860 AST::cast<AST::WhileStatement *>(ast->statement) ||
3861 AST::cast<AST::DoWhileStatement *>(ast->statement) ||
3862 AST::cast<AST::ForStatement *>(ast->statement) ||
3863 AST::cast<AST::ForEachStatement *>(ast->statement)) {
3864 statement(ast->statement);
3866 BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
3867 ControlFlowLoop flow(
this, &breakLabel);
3868 statement(ast->statement);
3875void Codegen::emitReturn(
const Reference &expr)
3877 ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
3878 if (target.linkLabel.isValid() && target.unwindLevel) {
3879 Q_ASSERT(_returnAddress >= 0);
3880 (
void) expr.storeOnStack(_returnAddress);
3881 bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
3883 expr.loadInAccumulator();
3884 bytecodeGenerator->addInstruction(Instruction::Ret());
3888bool Codegen::visit(ReturnStatement *ast)
3893 if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
3894 throwSyntaxError(ast->returnToken, QStringLiteral(
"Return statement outside of function"));
3898 if (ast->expression) {
3899 expr = expression(ast->expression);
3903 expr = Reference::fromConst(
this, Encode::undefined());
3911bool Codegen::visit(SwitchStatement *ast)
3916 if (requiresReturnValue)
3917 Reference::fromConst(
this, Encode::undefined()).storeOnStack(_returnAddress);
3919 RegisterScope scope(
this);
3920 TailCallBlocker blockTailCalls(
this);
3923 BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
3925 Reference lhs = expression(ast->expression);
3928 lhs = lhs.storeOnStack();
3930 ControlFlowBlock controlFlow(
this, ast->block);
3933 QHash<Node *, BytecodeGenerator::Label> blockMap;
3934 for (CaseClauses *it = ast->block->clauses; it; it = it->next)
3935 blockMap[it->clause] = bytecodeGenerator->newLabel();
3936 if (ast->block->defaultClause)
3937 blockMap[ast->block->defaultClause] = bytecodeGenerator->newLabel();
3938 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next)
3939 blockMap[it->clause] = bytecodeGenerator->newLabel();
3942 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3943 CaseClause *clause = it->clause;
3944 Reference rhs = expression(clause->expression);
3947 rhs.loadInAccumulator();
3948 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3951 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3952 CaseClause *clause = it->clause;
3953 Reference rhs = expression(clause->expression);
3956 rhs.loadInAccumulator();
3957 bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
3960 if (DefaultClause *defaultClause = ast->block->defaultClause)
3961 bytecodeGenerator->jump().link(blockMap.value(defaultClause));
3963 bytecodeGenerator->jump().link(switchEnd);
3965 ControlFlowLoop flow(
this, &switchEnd);
3967 insideSwitch =
true;
3968 blockTailCalls.unblock();
3969 for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
3970 CaseClause *clause = it->clause;
3971 blockMap[clause].link();
3973 statementList(clause->statements);
3976 if (ast->block->defaultClause) {
3977 DefaultClause *clause = ast->block->defaultClause;
3978 blockMap[clause].link();
3980 statementList(clause->statements);
3983 for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
3984 CaseClause *clause = it->clause;
3985 blockMap[clause].link();
3987 statementList(clause->statements);
3989 insideSwitch =
false;
3998bool Codegen::visit(ThrowStatement *ast)
4003 RegisterScope scope(
this);
4004 TailCallBlocker blockTailCalls(
this);
4006 Reference expr = expression(ast->expression);
4010 expr.loadInAccumulator();
4011 Instruction::ThrowException instr;
4012 bytecodeGenerator->addInstruction(instr);
4016void Codegen::handleTryCatch(TryStatement *ast)
4019 RegisterScope scope(
this);
4021 ControlFlowCatch catchFlow(
this, ast->catchExpression);
4022 RegisterScope scope(
this);
4023 TailCallBlocker blockTailCalls(
this);
4024 statement(ast->statement);
4028void Codegen::handleTryFinally(TryStatement *ast)
4030 RegisterScope scope(
this);
4031 const bool hasCatchBlock = ast->catchExpression;
4032 ControlFlowFinally finally(
this, ast->finallyExpression, hasCatchBlock);
4033 TailCallBlocker blockTailCalls(
this);
4035 if (ast->catchExpression) {
4036 handleTryCatch(ast);
4038 RegisterScope scope(
this);
4039 statement(ast->statement);
4043bool Codegen::visit(TryStatement *ast)
4048 RegisterScope scope(
this);
4050 if (ast->finallyExpression && ast->finallyExpression->statement) {
4051 handleTryFinally(ast);
4053 handleTryCatch(ast);
4059bool Codegen::visit(VariableStatement *ast)
4064 variableDeclarationList(ast->declarations);
4068bool Codegen::visit(WhileStatement *ast)
4073 if (AST::cast<FalseLiteral *>(ast->expression))
4076 RegisterScope scope(
this);
4078 BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
4079 BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
4080 BytecodeGenerator::Label cond = bytecodeGenerator->label();
4081 ControlFlowLoop flow(
this, &end, &cond);
4082 bytecodeGenerator->addLoopStart(cond);
4084 bytecodeGenerator->checkException();
4086 if (!AST::cast<TrueLiteral *>(ast->expression)) {
4087 TailCallBlocker blockTailCalls(
this);
4088 condition(ast->expression, &start, &end,
true);
4092 statement(ast->statement);
4093 setJumpOutLocation(bytecodeGenerator, ast->statement, ast->whileToken);
4094 bytecodeGenerator->jump().link(cond);
4100bool Codegen::visit(WithStatement *ast)
4105 RegisterScope scope(
this);
4106 TailCallBlocker blockTailCalls(
this);
4108 Reference src = expression(ast->expression);
4111 src = src.storeOnStack();
4112 src.loadInAccumulator();
4116 blockTailCalls.unblock();
4117 ControlFlowWith flow(
this);
4118 statement(ast->statement);
4125bool Codegen::visit(UiArrayBinding *)
4131bool Codegen::visit(UiObjectBinding *)
4137bool Codegen::visit(UiObjectDefinition *)
4143bool Codegen::visit(UiPublicMember *)
4149bool Codegen::visit(UiScriptBinding *)
4155bool Codegen::visit(UiSourceElement *)
4161bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(
const Reference &r,
const SourceLocation& loc)
4163 if (!_context->isStrict)
4165 bool isArgOrEval =
false;
4166 if (r.type == Reference::Name) {
4167 QString str = jsUnitGenerator->stringForIndex(r.nameAsIndex());
4168 if (str == QLatin1String(
"eval") || str == QLatin1String(
"arguments")) {
4171 }
else if (r.type == Reference::ScopedLocal || r.isRegister()) {
4172 isArgOrEval = r.isArgOrEval;
4175 throwSyntaxError(loc, QStringLiteral(
"Variable name may not be eval or arguments in strict mode"));
4179void Codegen::throwError(ErrorType errorType,
const SourceLocation &loc,
const QString &detail)
4184 _errorType = errorType;
4185 _error.message = detail;
4189void Codegen::throwSyntaxError(
const SourceLocation &loc,
const QString &detail)
4191 throwError(SyntaxError, loc, detail);
4194void Codegen::throwReferenceError(
const SourceLocation &loc,
const QString &detail)
4196 throwError(ReferenceError, loc, detail);
4199QQmlJS::DiagnosticMessage Codegen::error()
const
4204QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
4205 bool generateUnitData)
4207 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
4208 new QV4::CompiledData::CompilationUnit(
4209 generateUnitData ? jsUnitGenerator->generateUnit() :
nullptr),
4210 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
4213QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
4214 bool debugMode,
const QString &url,
const QString &sourceCode,
4215 const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
4218 QQmlJS::Lexer lexer(&ee);
4219 lexer.setCode(sourceCode, 1,
false);
4220 QQmlJS::Parser parser(&ee);
4222 const bool parsed = parser.parseModule();
4225 *diagnostics = parser.diagnosticMessages();
4228 return QQmlRefPointer<CompiledData::CompilationUnit>();
4230 QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
4235 diagnostics->clear();
4239 using namespace QV4::Compiler;
4240 Compiler::Module compilerModule(url, url, debugMode);
4241 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4242 compilerModule.sourceTimeStamp = sourceTimeStamp;
4243 JSUnitGenerator jsGenerator(&compilerModule);
4244 Codegen cg(&jsGenerator,
true);
4245 cg.generateFromModule(sourceCode, moduleNode, &compilerModule);
4246 if (cg.hasError()) {
4248 *diagnostics << cg.error();
4249 return QQmlRefPointer<CompiledData::CompilationUnit>();
4252 return cg.generateCompilationUnit();
4255const QV4::CompiledData::Unit *Codegen::generateNativeModuleUnitData(
4256 bool debugMode,
const QString &url,
const Value &value)
4258 using namespace QV4::Compiler;
4259 Compiler::Module compilerModule(url, url, debugMode);
4260 compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
4261 JSUnitGenerator jsGenerator(&compilerModule);
4262 Codegen cg(&jsGenerator,
true);
4263 cg.generateFromModule(value, &compilerModule);
4264 Q_ASSERT(!cg.hasError());
4265 return jsGenerator.generateUnit();
4270 VolatileMemoryLocations locs;
4285 bool visit(ArrayMemberExpression *)
override
4287 locs.setAllVolatile();
4291 bool visit(FieldMemberExpression *)
override
4293 locs.setAllVolatile();
4297 bool visit(PostIncrementExpression *e)
override
4299 collectIdentifiers(locs.specificLocations, e->base);
4303 bool visit(PostDecrementExpression *e)
override
4305 collectIdentifiers(locs.specificLocations, e->base);
4309 bool visit(PreIncrementExpression *e)
override
4311 collectIdentifiers(locs.specificLocations, e->expression);
4315 bool visit(PreDecrementExpression *e)
override
4317 collectIdentifiers(locs.specificLocations, e->expression);
4321 bool visit(BinaryExpression *e)
override
4324 case QSOperator::InplaceAnd:
4325 case QSOperator::InplaceSub:
4326 case QSOperator::InplaceDiv:
4327 case QSOperator::InplaceAdd:
4328 case QSOperator::InplaceLeftShift:
4329 case QSOperator::InplaceMod:
4330 case QSOperator::InplaceMul:
4331 case QSOperator::InplaceOr:
4332 case QSOperator::InplaceRightShift:
4333 case QSOperator::InplaceURightShift:
4334 case QSOperator::InplaceXor:
4335 collectIdentifiers(locs.specificLocations, e);
4349 void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
4350 class Collector:
public QQmlJS::AST::Visitor {
4352 QList<QStringView> &ids;
4353 VolatileMemoryLocationScanner *parent;
4356 Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
4357 QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
4360 bool visit(IdentifierExpression *ie) final {
4361 ids.append(ie->name);
4365 void throwRecursionDepthError() final
4367 parent->throwRecursionDepthError();
4370 Collector collector(ids,
this);
4371 node->accept(&collector);
4375Codegen::VolatileMemoryLocations
Codegen::scanVolatileMemoryLocations(AST::Node *ast)
4377 VolatileMemoryLocationScanner scanner(
this);
4378 return scanner.scan(ast);
4383 return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
4386bool Codegen::RValue::operator==(
const RValue &other)
const
4390 return other.isAccumulator();
4392 return other.isStackSlot() && theStackSlot == other.theStackSlot;
4394 return other.isConst() && constant == other.constant;
4400Codegen::RValue Codegen::RValue::storeOnStack()
const
4404 return RValue::fromStackSlot(codegen, Reference::fromAccumulator(codegen).storeOnStack().stackSlot());
4408 return RValue::fromStackSlot(codegen, Reference::storeConstOnStack(codegen, constant).stackSlot());
4414void Codegen::RValue::loadInAccumulator()
const
4421 return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
4423 return Reference::fromConst(codegen, constant).loadInAccumulator();
4430bool Codegen::Reference::operator==(
const Codegen::Reference &other)
const
4432 if (type != other.type)
4441 return property == other.property;
4443 return theStackSlot == other.theStackSlot;
4445 return index == other.index && scope == other.scope;
4447 return nameAsIndex() == other.nameAsIndex();
4449 return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
4451 return elementBase == other.elementBase && other.subscriptLoadedForCall
4452 ? (subscriptLoadedForCall && element == other.element)
4453 : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
4455 return index == other.index;
4457 return constant == other.constant;
4462Codegen::RValue Codegen::Reference::asRValue()
const
4468 return RValue::fromAccumulator(codegen);
4470 return RValue::fromStackSlot(codegen, stackSlot());
4472 return RValue::fromConst(codegen, constant);
4474 loadInAccumulator();
4475 return RValue::fromAccumulator(codegen);
4479Codegen::Reference Codegen::Reference::asLValue()
const
4486 codegen->throwSyntaxError(SourceLocation(), QStringLiteral(
"Super lvalues not implemented."));
4489 if (!propertyBase.isStackSlot()) {
4490 Reference r = *
this;
4491 r.propertyBase = propertyBase.storeOnStack();
4496 if (!elementSubscript.isStackSlot()) {
4497 Reference r = *
this;
4498 r.elementSubscript = elementSubscript.storeOnStack();
4507Codegen::Reference Codegen::Reference::storeConsumeAccumulator()
const
4513Codegen::Reference Codegen::Reference::baseObject()
const
4515 if (type == Reference::Member) {
4516 RValue rval = propertyBase;
4517 if (!rval.isValid())
4518 return Reference::fromConst(codegen, Encode::undefined());
4519 if (rval.isAccumulator())
4520 return Reference::fromAccumulator(codegen);
4521 if (rval.isStackSlot())
4522 return Reference::fromStackSlot(codegen, rval.stackSlot());
4524 return Reference::fromConst(codegen, rval.constantValue());
4526 }
else if (type == Reference::Subscript) {
4527 return Reference::fromStackSlot(codegen, elementBase.stackSlot());
4528 }
else if (type == Reference::SuperProperty) {
4529 return Reference::fromStackSlot(codegen, CallData::This);
4531 return Reference::fromConst(codegen, Encode::undefined());
4535Codegen::Reference Codegen::Reference::storeOnStack()
const
4536{
return doStoreOnStack(-1); }
4538void Codegen::Reference::storeOnStack(
int slotIndex)
const
4539{ doStoreOnStack(slotIndex); }
4541Codegen::Reference Codegen::Reference::doStoreOnStack(
int slotIndex)
const
4543 Q_ASSERT(isValid());
4545 if (isStackSlot() && slotIndex == -1 && !(stackSlotIsLocalOrArgument && isVolatile) && !requiresTDZCheck)
4548 if (isStackSlot() && !requiresTDZCheck) {
4549 Reference dest = Reference::fromStackSlot(codegen, slotIndex);
4550 Instruction::MoveReg move;
4551 move.srcReg = stackSlot();
4552 move.destReg = dest.stackSlot();
4553 codegen->bytecodeGenerator->addInstruction(move);
4557 Reference slot = Reference::fromStackSlot(codegen, slotIndex);
4559 Instruction::MoveConst move;
4560 move.constIndex = codegen->registerConstant(constant);
4561 move.destTemp = slot.stackSlot();
4562 codegen->bytecodeGenerator->addInstruction(move);
4564 loadInAccumulator();
4565 slot.storeConsumeAccumulator();
4570void Codegen::Reference::tdzCheck(
bool requiresCheck,
bool throwsReferenceError)
const {
4571 if (throwsReferenceError) {
4572 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4573 name + QStringLiteral(
" is not defined"));
4578 Instruction::DeadTemporalZoneCheck check;
4579 check.name = codegen->registerString(name);
4580 codegen->bytecodeGenerator->addInstruction(check);
4583void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot,
bool requiresCheck,
bool throwsReferenceError)
const {
4586 Instruction::LoadReg load;
4588 codegen->bytecodeGenerator->addInstruction(load);
4589 tdzCheck(
true, throwsReferenceError);
4592Codegen::Reference Codegen::Reference::storeRetainAccumulator()
const
4594 if (storeWipesAccumulator()) {
4596 auto tmp = Reference::fromStackSlot(codegen);
4597 tmp.storeAccumulator();
4607bool Codegen::Reference::storeWipesAccumulator()
const
4626void Codegen::Reference::storeAccumulator()
const
4628 if (throwsReferenceError) {
4629 codegen->generateThrowException(QStringLiteral(
"ReferenceError"),
4630 name + QStringLiteral(
" is not defined"));
4634 if (isReferenceToConst) {
4636 codegen->generateThrowException(QStringLiteral(
"TypeError"));
4642 Q_UNREACHABLE_RETURN();
4644 Instruction::StoreSuperProperty store;
4645 store.property = property.stackSlot();
4646 codegen->bytecodeGenerator->addInstruction(store);
4649 Instruction::StoreReg store;
4650 store.reg = theStackSlot;
4651 codegen->bytecodeGenerator->addInstruction(store);
4656 Instruction::StoreLocal store;
4657 store.index = index;
4658 codegen->bytecodeGenerator->addInstruction(store);
4660 Instruction::StoreScopedLocal store;
4661 store.index = index;
4662 store.scope = scope;
4663 codegen->bytecodeGenerator->addInstruction(store);
4668 Context *c = codegen->currentContext();
4670 Instruction::StoreNameStrict store;
4671 store.name = nameAsIndex();
4672 codegen->bytecodeGenerator->addInstruction(store);
4674 Instruction::StoreNameSloppy store;
4675 store.name = nameAsIndex();
4676 codegen->bytecodeGenerator->addInstruction(store);
4680 if (codegen->useFastLookups) {
4681 Instruction::SetLookup store;
4682 store.base = propertyBase.stackSlot();
4683 store.index = codegen->registerSetterLookup(propertyNameIndex);
4684 codegen->bytecodeGenerator->addInstruction(store);
4686 Instruction::StoreProperty store;
4687 store.base = propertyBase.stackSlot();
4688 store.name = propertyNameIndex;
4689 codegen->bytecodeGenerator->addInstruction(store);
4693 Instruction::StoreElement store;
4694 store.base = elementBase;
4695 store.index = elementSubscript.stackSlot();
4696 codegen->bytecodeGenerator->addInstruction(store);
4708void Codegen::Reference::loadInAccumulator()
const
4714 Q_UNREACHABLE_RETURN();
4716 tdzCheckStackSlot(property, subscriptRequiresTDZCheck,
false);
4717 Instruction::LoadSuperProperty load;
4718 load.property = property.stackSlot();
4719 codegen->bytecodeGenerator->addInstruction(load);
4723QT_WARNING_DISABLE_GCC(
"-Wmaybe-uninitialized")
4724 if (constant == Encode::null()) {
4725 Instruction::LoadNull load;
4726 codegen->bytecodeGenerator->addInstruction(load);
4727 }
else if (constant == Encode(
true)) {
4728 Instruction::LoadTrue load;
4729 codegen->bytecodeGenerator->addInstruction(load);
4730 }
else if (constant == Encode(
false)) {
4731 Instruction::LoadFalse load;
4732 codegen->bytecodeGenerator->addInstruction(load);
4733 }
else if (constant == Encode::undefined()) {
4734 Instruction::LoadUndefined load;
4735 codegen->bytecodeGenerator->addInstruction(load);
4737 StaticValue p = StaticValue::fromReturnedValue(constant);
4739 double d = p.asDouble();
4740 int i = QJSNumberCoercion::toInteger(d);
4741 if (d == i && (d != 0 || !std::signbit(d))) {
4743 Instruction::LoadZero load;
4744 codegen->bytecodeGenerator->addInstruction(load);
4747 Instruction::LoadInt load;
4748 load.value = StaticValue::fromReturnedValue(constant).toInt32();
4749 codegen->bytecodeGenerator->addInstruction(load);
4753 Instruction::LoadConst load;
4754 load.index = codegen->registerConstant(constant);
4755 codegen->bytecodeGenerator->addInstruction(load);
4760 Instruction::LoadReg load;
4761 load.reg = stackSlot();
4762 codegen->bytecodeGenerator->addInstruction(load);
4763 tdzCheck(requiresTDZCheck, throwsReferenceError);
4767 Instruction::LoadLocal load;
4769 codegen->bytecodeGenerator->addInstruction(load);
4771 Instruction::LoadScopedLocal load;
4774 codegen->bytecodeGenerator->addInstruction(load);
4776 tdzCheck(requiresTDZCheck, throwsReferenceError);
4783 if (name == QStringLiteral(
"undefined")) {
4784 Reference::fromConst(codegen, Encode::undefined()).loadInAccumulator();
4786 }
else if (name == QStringLiteral(
"Infinity")) {
4787 Reference::fromConst(codegen, Encode(qInf())).loadInAccumulator();
4789 }
else if (name == QStringLiteral(
"Nan")) {
4790 Reference::fromConst(codegen, Encode(qQNaN())).loadInAccumulator();
4795 if (sourceLocation.isValid())
4796 codegen->bytecodeGenerator->setLocation(sourceLocation);
4800 Instruction::LoadQmlContextPropertyLookup load;
4801 load.index = codegen->registerQmlContextPropertyGetterLookup(
4802 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4803 codegen->bytecodeGenerator->addInstruction(load);
4805 Instruction::LoadGlobalLookup load;
4806 load.index = codegen->registerGlobalGetterLookup(
4807 nameAsIndex(), JSUnitGenerator::LookupForStorage);
4808 codegen->bytecodeGenerator->addInstruction(load);
4811 Instruction::LoadName load;
4812 load.name = nameAsIndex();
4813 codegen->bytecodeGenerator->addInstruction(load);
4817 propertyBase.loadInAccumulator();
4818 tdzCheck(requiresTDZCheck, throwsReferenceError);
4820 if (sourceLocation.isValid())
4821 codegen->bytecodeGenerator->setLocation(sourceLocation);
4823 if (codegen->useFastLookups) {
4824 if (optionalChainJumpsToPatch && isOptional) {
4825 auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
4826 codegen->registerGetterLookup(
4827 propertyNameIndex, JSUnitGenerator::LookupForStorage));
4828 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4830 Instruction::GetLookup load;
4831 load.index = codegen->registerGetterLookup(
4832 propertyNameIndex, JSUnitGenerator::LookupForStorage);
4833 codegen->bytecodeGenerator->addInstruction(load);
4836 if (optionalChainJumpsToPatch && isOptional) {
4837 auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
4838 optionalChainJumpsToPatch->emplace_back(std::move(jump));
4840 Instruction::LoadProperty load;
4841 load.name = propertyNameIndex;
4842 codegen->bytecodeGenerator->addInstruction(load);
4847 Instruction::LoadImport load;
4849 codegen->bytecodeGenerator->addInstruction(load);
4850 tdzCheck(requiresTDZCheck, throwsReferenceError);
4853 tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
4854 elementSubscript.loadInAccumulator();
4855 tdzCheck(subscriptRequiresTDZCheck,
false);
4856 Instruction::LoadElement load;
4857 load.base = elementBase;
4858 codegen->bytecodeGenerator->addInstruction(load);
void throwRecursionDepthError() override
VolatileMemoryLocationScanner(Codegen *parent)
Codegen::VolatileMemoryLocations scan(AST::Node *s)
bool visit(ArrayMemberExpression *) override
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
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[]