aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r--src/qml/compiler/qv4codegen.cpp136
1 files changed, 104 insertions, 32 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 8709e3fff8..4af3c99df8 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -500,6 +500,7 @@ void Codegen::statementList(StatementList *ast)
void Codegen::variableDeclaration(PatternElement *ast)
{
+ TailCallBlocker blockTailCalls(this);
RegisterScope scope(this);
if (!ast->initializer) {
@@ -807,6 +808,7 @@ bool Codegen::visit(ExportDeclaration *ast)
if (!ast->exportDefault)
return true;
+ TailCallBlocker blockTailCalls(this);
Reference exportedValue;
if (auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
@@ -903,6 +905,8 @@ bool Codegen::visit(VariableDeclarationList *)
bool Codegen::visit(ClassExpression *ast)
{
+ TailCallBlocker blockTailCalls(this);
+
Compiler::Class jsClass;
jsClass.nameIndex = registerString(ast->name.toString());
@@ -1007,6 +1011,7 @@ bool Codegen::visit(ClassExpression *ast)
bool Codegen::visit(ClassDeclaration *ast)
{
+ TailCallBlocker blockTailCalls(this);
Reference outerVar = referenceForName(ast->name.toString(), true);
visit(static_cast<ClassExpression *>(ast));
(void) outerVar.storeRetainAccumulator();
@@ -1018,7 +1023,9 @@ bool Codegen::visit(Expression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
statement(ast->left);
+ blockTailCalls.unblock();
accept(ast->right);
return false;
}
@@ -1028,6 +1035,8 @@ bool Codegen::visit(ArrayPattern *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
+
PatternElementList *it = ast->elements;
int argc = 0;
@@ -1189,6 +1198,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
if (hasError)
return false;
@@ -1240,11 +1250,14 @@ bool Codegen::visit(BinaryExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
+
if (ast->op == QSOperator::And) {
if (_expr.accept(cx)) {
auto iftrue = bytecodeGenerator->newLabel();
condition(ast->left, &iftrue, _expr.iffalse(), true);
iftrue.link();
+ blockTailCalls.unblock();
condition(ast->right, _expr.iftrue(), _expr.iffalse(), _expr.trueBlockFollowsCondition());
} else {
auto iftrue = bytecodeGenerator->newLabel();
@@ -1259,6 +1272,7 @@ bool Codegen::visit(BinaryExpression *ast)
bytecodeGenerator->jumpFalse().link(endif);
iftrue.link();
+ blockTailCalls.unblock();
Reference right = expression(ast->right);
if (hasError)
return false;
@@ -1288,6 +1302,7 @@ bool Codegen::visit(BinaryExpression *ast)
bytecodeGenerator->jumpTrue().link(endif);
iffalse.link();
+ blockTailCalls.unblock();
Reference right = expression(ast->right);
if (hasError)
return false;
@@ -1320,6 +1335,7 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.asLValue();
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
return false;
+ blockTailCalls.unblock();
Reference r = expression(ast->right);
if (hasError)
return false;
@@ -1814,6 +1830,7 @@ bool Codegen::visit(CallExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
@@ -1845,7 +1862,8 @@ bool Codegen::visit(CallExpression *ast)
if (hasError)
return false;
- if (calldata.hasSpread) {
+ blockTailCalls.unblock();
+ if (calldata.hasSpread || _tailCallsAreAllowed) {
Reference baseObject = base.baseObject();
if (!baseObject.isStackSlot()) {
baseObject.storeOnStack(thisObject);
@@ -1856,12 +1874,21 @@ bool Codegen::visit(CallExpression *ast)
base = Reference::fromStackSlot(this, functionObject);
}
- Instruction::CallWithSpread call;
- call.func = base.stackSlot();
- call.thisObject = baseObject.stackSlot();
- call.argc = calldata.argc;
- call.argv = calldata.argv;
- bytecodeGenerator->addInstruction(call);
+ if (calldata.hasSpread) {
+ Instruction::CallWithSpread call;
+ call.func = base.stackSlot();
+ call.thisObject = baseObject.stackSlot();
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(call);
+ } else {
+ Instruction::TailCall call;
+ call.func = base.stackSlot();
+ call.thisObject = baseObject.stackSlot();
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(call);
+ }
_expr.setResult(Reference::fromAccumulator(this));
return false;
@@ -2028,11 +2055,14 @@ bool Codegen::visit(ConditionalExpression *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
BytecodeGenerator::Label iffalse = bytecodeGenerator->newLabel();
condition(ast->expression, &iftrue, &iffalse, true);
+ blockTailCalls.unblock();
+
iftrue.link();
Reference ok = expression(ast->ok);
if (hasError)
@@ -2058,6 +2088,7 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
if (hasError)
return false;
@@ -2145,6 +2176,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("new")) {
// new.target
@@ -2266,6 +2298,8 @@ bool Codegen::visit(FunctionExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
+
RegisterScope scope(this);
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
@@ -2395,6 +2429,7 @@ bool Codegen::visit(NewExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->expression);
if (hasError)
@@ -2414,6 +2449,7 @@ bool Codegen::visit(NewMemberExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
if (hasError)
@@ -2432,6 +2468,7 @@ bool Codegen::visit(NotExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
_expr.setResult(unop(Not, expression(ast->expression)));
return false;
}
@@ -2463,6 +2500,8 @@ bool Codegen::visit(ObjectPattern *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
+
QVector<QPair<Reference, ObjectPropertyValue>> computedProperties;
QMap<QString, ObjectPropertyValue> valueMap;
@@ -2684,6 +2723,8 @@ bool Codegen::visit(TemplateLiteral *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
+
Instruction::LoadRuntimeString instr;
instr.stringId = registerString(ast->value.toString());
bytecodeGenerator->addInstruction(instr);
@@ -2742,6 +2783,7 @@ bool Codegen::visit(TildeExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
_expr.setResult(unop(Compl, expression(ast->expression)));
return false;
}
@@ -2761,6 +2803,7 @@ bool Codegen::visit(TypeOfExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
if (hasError)
@@ -2786,6 +2829,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
_expr.setResult(unop(UMinus, expression(ast->expression)));
return false;
}
@@ -2795,6 +2839,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
if (hasError)
return false;
+ TailCallBlocker blockTailCalls(this);
_expr.setResult(unop(UPlus, expression(ast->expression)));
return false;
}
@@ -2805,6 +2850,7 @@ bool Codegen::visit(VoidExpression *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
statement(ast->expression);
_expr.setResult(Reference::fromConst(this, Encode::undefined()));
@@ -2816,6 +2862,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
if (hasError)
return false;
+ // no need to block tail calls: the function body isn't visited here.
RegisterScope scope(this);
if (_functionContext->contextType == ContextType::Binding)
@@ -2832,6 +2879,7 @@ bool Codegen::visit(YieldExpression *ast)
}
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
if (hasError)
return false;
@@ -2981,38 +3029,43 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->blockIndex = _module->blocks.count() - 1;
}
+ TailCallBlocker maybeBlockTailCalls(this, _context->canHaveTailCalls());
+
RegisterScope registerScope(this);
_context->emitBlockHeader(this);
- inFormalParameterList = true;
- int argc = 0;
- while (formals) {
- PatternElement *e = formals->element;
- if (!e) {
- if (!formals->next)
- // trailing comma
- break;
- Q_UNREACHABLE();
- }
-
- Reference arg = referenceForName(e->bindingIdentifier.toString(), true);
- if (e->type == PatternElement::RestElement) {
- Q_ASSERT(!formals->next);
- Instruction::CreateRestParameter rest;
- rest.argIndex = argc;
- bytecodeGenerator->addInstruction(rest);
- arg.storeConsumeAccumulator();
- } else {
- if (e->bindingTarget || e->initializer) {
- initializeAndDestructureBindingElement(e, arg);
- if (hasError)
+ {
+ QScopedValueRollback<bool> inFormals(inFormalParameterList, true);
+ TailCallBlocker blockTailCalls(this); // we're not in the FunctionBody or ConciseBody yet
+
+ int argc = 0;
+ while (formals) {
+ PatternElement *e = formals->element;
+ if (!e) {
+ if (!formals->next)
+ // trailing comma
break;
+ Q_UNREACHABLE();
}
+
+ Reference arg = referenceForName(e->bindingIdentifier.toString(), true);
+ if (e->type == PatternElement::RestElement) {
+ Q_ASSERT(!formals->next);
+ Instruction::CreateRestParameter rest;
+ rest.argIndex = argc;
+ bytecodeGenerator->addInstruction(rest);
+ arg.storeConsumeAccumulator();
+ } else {
+ if (e->bindingTarget || e->initializer) {
+ initializeAndDestructureBindingElement(e, arg);
+ if (hasError)
+ break;
+ }
+ }
+ formals = formals->next;
+ ++argc;
}
- formals = formals->next;
- ++argc;
}
- inFormalParameterList = false;
if (_context->isGenerator) {
Instruction::Yield yield;
@@ -3083,6 +3136,7 @@ bool Codegen::visit(BreakStatement *ast)
if (hasError)
return false;
+ // no need to block tail calls here: children aren't visited
if (!controlFlow) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
return false;
@@ -3107,6 +3161,7 @@ bool Codegen::visit(ContinueStatement *ast)
if (hasError)
return false;
+ // no need to block tail calls here: children aren't visited
RegisterScope scope(this);
if (!controlFlow) {
@@ -3152,6 +3207,7 @@ bool Codegen::visit(DoWhileStatement *ast)
cond.link();
+ TailCallBlocker blockTailCalls(this);
if (!AST::cast<FalseLiteral *>(ast->expression)) {
if (AST::cast<TrueLiteral *>(ast->expression))
bytecodeGenerator->jump().link(body);
@@ -3178,6 +3234,7 @@ bool Codegen::visit(ExpressionStatement *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
if (requiresReturnValue) {
Reference e = expression(ast->expression);
@@ -3196,6 +3253,7 @@ bool Codegen::visit(ForEachStatement *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference iterator = Reference::fromStackSlot(this);
Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
@@ -3289,6 +3347,7 @@ bool Codegen::visit(ForStatement *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
ControlFlowBlock controlFlow(this, ast);
@@ -3307,7 +3366,9 @@ bool Codegen::visit(ForStatement *ast)
condition(ast->condition, &body, &end, true);
body.link();
+ blockTailCalls.unblock();
statement(ast->statement);
+ blockTailCalls.reblock();
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
step.link();
@@ -3329,10 +3390,12 @@ bool Codegen::visit(IfStatement *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
BytecodeGenerator::Label trueLabel = bytecodeGenerator->newLabel();
BytecodeGenerator::Label falseLabel = bytecodeGenerator->newLabel();
condition(ast->expression, &trueLabel, &falseLabel, true);
+ blockTailCalls.unblock();
trueLabel.link();
statement(ast->ok);
@@ -3433,6 +3496,7 @@ bool Codegen::visit(SwitchStatement *ast)
Reference::fromConst(this, Encode::undefined()).storeOnStack(_returnAddress);
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
if (ast->block) {
BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
@@ -3480,6 +3544,7 @@ bool Codegen::visit(SwitchStatement *ast)
ControlFlowLoop flow(this, &switchEnd);
insideSwitch = true;
+ blockTailCalls.unblock();
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
blockMap[clause].link();
@@ -3515,6 +3580,7 @@ bool Codegen::visit(ThrowStatement *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
if (hasError)
@@ -3534,6 +3600,7 @@ void Codegen::handleTryCatch(TryStatement *ast)
{
ControlFlowCatch catchFlow(this, ast->catchExpression);
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this); // IMPORTANT: destruction will unblock tail calls before catch is generated
statement(ast->statement);
bytecodeGenerator->jump().link(noException);
}
@@ -3544,6 +3611,7 @@ void Codegen::handleTryFinally(TryStatement *ast)
{
RegisterScope scope(this);
ControlFlowFinally finally(this, ast->finallyExpression);
+ TailCallBlocker blockTailCalls(this); // IMPORTANT: destruction will unblock tail calls before finally is generated
if (ast->catchExpression) {
handleTryCatch(ast);
@@ -3587,6 +3655,7 @@ bool Codegen::visit(WhileStatement *ast)
return false;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
BytecodeGenerator::Label start = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
@@ -3595,6 +3664,7 @@ bool Codegen::visit(WhileStatement *ast)
if (!AST::cast<TrueLiteral *>(ast->expression))
condition(ast->expression, &start, &end, true);
+ blockTailCalls.unblock();
start.link();
statement(ast->statement);
@@ -3611,6 +3681,7 @@ bool Codegen::visit(WithStatement *ast)
return true;
RegisterScope scope(this);
+ TailCallBlocker blockTailCalls(this);
Reference src = expression(ast->expression);
if (hasError)
@@ -3620,6 +3691,7 @@ bool Codegen::visit(WithStatement *ast)
enterContext(ast);
{
+ blockTailCalls.unblock();
ControlFlowWith flow(this);
statement(ast->statement);
}