Commit d7fda252 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[ignition] Move suspend_id assignment to bytecode generation

Instead of building suspend_ids in the AST numbering, collect suspend
counts in the parser and assigning suspend ids during bytecode
generation.

Bug: v8:7178
Change-Id: I53421442afddc894db789fb9d0d3e3cc10e32ff0
Reviewed-on: https://chromium-review.googlesource.com/817598
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50830}
parent 476a4576
......@@ -16,7 +16,7 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
public:
AstNumberingVisitor(uintptr_t stack_limit, Zone* zone,
Compiler::EagerInnerFunctionLiterals* eager_literals)
: zone_(zone), eager_literals_(eager_literals), suspend_count_(0) {
: zone_(zone), eager_literals_(eager_literals) {
InitializeAstVisitor(stack_limit);
}
......@@ -40,7 +40,6 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
Zone* zone_;
Compiler::EagerInnerFunctionLiterals* eager_literals_;
int suspend_count_;
FunctionKind function_kind_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
......@@ -110,19 +109,12 @@ void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
}
void AstNumberingVisitor::VisitSuspend(Suspend* node) {
node->set_suspend_id(suspend_count_);
suspend_count_++;
Visit(node->expression());
}
void AstNumberingVisitor::VisitYield(Yield* node) { VisitSuspend(node); }
void AstNumberingVisitor::VisitYieldStar(YieldStar* node) {
node->set_suspend_id(suspend_count_++);
if (IsAsyncGeneratorFunction(function_kind_)) {
node->set_await_iterator_close_suspend_id(suspend_count_++);
node->set_await_delegated_iterator_output_suspend_id(suspend_count_++);
}
Visit(node->expression());
}
......@@ -166,17 +158,13 @@ void AstNumberingVisitor::VisitWithStatement(WithStatement* node) {
}
void AstNumberingVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
node->set_first_suspend_id(suspend_count_);
Visit(node->body());
Visit(node->cond());
node->set_suspend_count(suspend_count_ - node->first_suspend_id());
}
void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) {
node->set_first_suspend_id(suspend_count_);
Visit(node->cond());
Visit(node->body());
node->set_suspend_count(suspend_count_ - node->first_suspend_id());
}
void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
......@@ -207,7 +195,10 @@ void AstNumberingVisitor::VisitAssignment(Assignment* node) {
void AstNumberingVisitor::VisitCompoundAssignment(CompoundAssignment* node) {
VisitBinaryOperation(node->binary_operation());
VisitAssignment(node);
// We don't need to recurse down the assignment version since we already did
// the binop.
DCHECK_EQ(node->target(), node->binary_operation()->left());
DCHECK_EQ(node->value(), node->binary_operation()->right());
}
void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) {
......@@ -248,21 +239,17 @@ void AstNumberingVisitor::VisitImportCallExpression(
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
Visit(node->enumerable()); // Not part of loop.
node->set_first_suspend_id(suspend_count_);
Visit(node->each());
Visit(node->body());
node->set_suspend_count(suspend_count_ - node->first_suspend_id());
}
void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) {
Visit(node->assign_iterator()); // Not part of loop.
Visit(node->assign_next());
node->set_first_suspend_id(suspend_count_);
Visit(node->next_result());
Visit(node->result_done());
Visit(node->assign_each());
Visit(node->body());
node->set_suspend_count(suspend_count_ - node->first_suspend_id());
}
void AstNumberingVisitor::VisitConditional(Conditional* node) {
......@@ -273,8 +260,10 @@ void AstNumberingVisitor::VisitConditional(Conditional* node) {
void AstNumberingVisitor::VisitIfStatement(IfStatement* node) {
Visit(node->condition());
Visit(node->then_statement());
if (node->HasElseStatement()) {
if (!node->condition()->ToBooleanIsFalse()) {
Visit(node->then_statement());
}
if (node->HasElseStatement() && !node->condition()->ToBooleanIsTrue()) {
Visit(node->else_statement());
}
}
......@@ -289,11 +278,9 @@ void AstNumberingVisitor::VisitSwitchStatement(SwitchStatement* node) {
void AstNumberingVisitor::VisitForStatement(ForStatement* node) {
if (node->init() != nullptr) Visit(node->init()); // Not part of loop.
node->set_first_suspend_id(suspend_count_);
if (node->cond() != nullptr) Visit(node->cond());
if (node->next() != nullptr) Visit(node->next());
Visit(node->body());
node->set_suspend_count(suspend_count_ - node->first_suspend_id());
}
void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) {
......@@ -391,8 +378,6 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
VisitDeclarations(scope->declarations());
VisitStatements(node->body());
node->set_suspend_count(suspend_count_);
return !HasStackOverflow();
}
......
......@@ -437,21 +437,12 @@ class IterationStatement : public BreakableStatement {
ZoneList<const AstRawString*>* labels() const { return labels_; }
int suspend_count() const { return suspend_count_; }
int first_suspend_id() const { return first_suspend_id_; }
void set_suspend_count(int suspend_count) { suspend_count_ = suspend_count; }
void set_first_suspend_id(int first_suspend_id) {
first_suspend_id_ = first_suspend_id;
}
protected:
IterationStatement(ZoneList<const AstRawString*>* labels, int pos,
NodeType type)
: BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type),
labels_(labels),
body_(nullptr),
suspend_count_(0),
first_suspend_id_(0) {}
body_(nullptr) {}
void Initialize(Statement* body) { body_ = body; }
static const uint8_t kNextBitFieldIndex =
......@@ -460,8 +451,6 @@ class IterationStatement : public BreakableStatement {
private:
ZoneList<const AstRawString*>* labels_;
Statement* body_;
int suspend_count_;
int first_suspend_id_;
};
......@@ -2096,11 +2085,6 @@ class Suspend : public Expression {
return OnAbruptResumeField::decode(bit_field_);
}
int suspend_id() const { return suspend_id_; }
void set_suspend_id(int id) { suspend_id_ = id; }
inline bool IsInitialYield() const { return suspend_id_ == 0 && IsYield(); }
private:
friend class AstNodeFactory;
friend class Yield;
......@@ -2109,11 +2093,10 @@ class Suspend : public Expression {
Suspend(NodeType node_type, Expression* expression, int pos,
OnAbruptResume on_abrupt_resume)
: Expression(pos, node_type), suspend_id_(-1), expression_(expression) {
: Expression(pos, node_type), expression_(expression) {
bit_field_ |= OnAbruptResumeField::encode(on_abrupt_resume);
}
int suspend_id_;
Expression* expression_;
class OnAbruptResumeField
......@@ -2128,47 +2111,11 @@ class Yield final : public Suspend {
};
class YieldStar final : public Suspend {
public:
// In addition to the normal suspend for yield*, a yield* in an async
// generator has 2 additional suspends:
// - One for awaiting the iterator result of closing the generator when
// resumed with a "throw" completion, and a throw method is not present
// on the delegated iterator (await_iterator_close_suspend_id)
// - One for awaiting the iterator result yielded by the delegated iterator
// (await_delegated_iterator_output_suspend_id)
int await_iterator_close_suspend_id() const {
return await_iterator_close_suspend_id_;
}
void set_await_iterator_close_suspend_id(int id) {
await_iterator_close_suspend_id_ = id;
}
int await_delegated_iterator_output_suspend_id() const {
return await_delegated_iterator_output_suspend_id_;
}
void set_await_delegated_iterator_output_suspend_id(int id) {
await_delegated_iterator_output_suspend_id_ = id;
}
inline int suspend_count() const {
if (await_iterator_close_suspend_id_ != -1) {
DCHECK_NE(-1, await_delegated_iterator_output_suspend_id_);
return 3;
}
return 1;
}
private:
friend class AstNodeFactory;
YieldStar(Expression* expression, int pos)
: Suspend(kYieldStar, expression, pos,
Suspend::OnAbruptResume::kNoControl),
await_iterator_close_suspend_id_(-1),
await_delegated_iterator_output_suspend_id_(-1) {}
int await_iterator_close_suspend_id_;
int await_delegated_iterator_output_suspend_id_;
Suspend::OnAbruptResume::kNoControl) {}
};
class Await final : public Suspend {
......
......@@ -909,8 +909,6 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
IndentedScope indent(this, "DO", node->position());
PrintIndented("SUSPEND COUNT");
Print(" %d\n", node->suspend_count());
PrintLabelsIndented(node->labels());
PrintIndentedVisit("BODY", node->body());
PrintIndentedVisit("COND", node->cond());
......@@ -919,8 +917,6 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
void AstPrinter::VisitWhileStatement(WhileStatement* node) {
IndentedScope indent(this, "WHILE", node->position());
PrintIndented("SUSPEND COUNT");
Print(" %d\n", node->suspend_count());
PrintLabelsIndented(node->labels());
PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body());
......@@ -929,8 +925,6 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) {
void AstPrinter::VisitForStatement(ForStatement* node) {
IndentedScope indent(this, "FOR", node->position());
PrintIndented("SUSPEND COUNT");
Print(" %d\n", node->suspend_count());
PrintLabelsIndented(node->labels());
if (node->init()) PrintIndentedVisit("INIT", node->init());
if (node->cond()) PrintIndentedVisit("COND", node->cond());
......@@ -941,8 +935,6 @@ void AstPrinter::VisitForStatement(ForStatement* node) {
void AstPrinter::VisitForInStatement(ForInStatement* node) {
IndentedScope indent(this, "FOR IN", node->position());
PrintIndented("SUSPEND COUNT");
Print(" %d\n", node->suspend_count());
PrintIndentedVisit("FOR", node->each());
PrintIndentedVisit("IN", node->enumerable());
PrintIndentedVisit("BODY", node->body());
......@@ -951,8 +943,6 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
IndentedScope indent(this, "FOR OF", node->position());
PrintIndented("SUSPEND COUNT");
Print(" %d\n", node->suspend_count());
PrintIndentedVisit("INIT", node->assign_iterator());
PrintIndentedVisit("NEXT", node->next_result());
PrintIndentedVisit("DONE", node->result_done());
......@@ -1208,21 +1198,21 @@ void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
void AstPrinter::VisitYield(Yield* node) {
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "YIELD id %d", node->suspend_id());
SNPrintF(buf, "YIELD");
IndentedScope indent(this, buf.start(), node->position());
Visit(node->expression());
}
void AstPrinter::VisitYieldStar(YieldStar* node) {
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "YIELD_STAR id %d", node->suspend_id());
SNPrintF(buf, "YIELD_STAR");
IndentedScope indent(this, buf.start(), node->position());
Visit(node->expression());
}
void AstPrinter::VisitAwait(Await* node) {
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "AWAIT id %d", node->suspend_id());
SNPrintF(buf, "AWAIT");
IndentedScope indent(this, buf.start(), node->position());
Visit(node->expression());
}
......
......@@ -878,6 +878,7 @@ BytecodeGenerator::BytecodeGenerator(
execution_result_(nullptr),
incoming_new_target_or_generator_(),
generator_jump_table_(nullptr),
suspend_count_(0),
loop_depth_(0),
catch_prediction_(HandlerTable::UNCAUGHT) {
DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
......@@ -1112,18 +1113,6 @@ void BytecodeGenerator::AllocateTopLevelRegisters() {
}
}
void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
LoopBuilder* loop_builder) {
VisitIterationHeader(stmt->first_suspend_id(), stmt->suspend_count(),
loop_builder);
}
void BytecodeGenerator::VisitIterationHeader(int first_suspend_id,
int suspend_count,
LoopBuilder* loop_builder) {
loop_builder->LoopHeader();
}
void BytecodeGenerator::BuildGeneratorPrologue() {
DCHECK_GT(info()->literal()->suspend_count(), 0);
DCHECK(generator_object().is_valid());
......@@ -1467,11 +1456,11 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
if (stmt->cond()->ToBooleanIsFalse()) {
VisitIterationBody(stmt, &loop_builder);
} else if (stmt->cond()->ToBooleanIsTrue()) {
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
VisitIterationBody(stmt, &loop_builder);
loop_builder.JumpToHeader(loop_depth_);
} else {
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
VisitIterationBody(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->cond());
BytecodeLabels loop_backbranch(zone());
......@@ -1490,7 +1479,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
return;
}
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
if (!stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
BytecodeLabels loop_body(zone());
......@@ -1514,7 +1503,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
return;
}
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
BytecodeLabels loop_body(zone());
......@@ -1632,7 +1621,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// The loop
{
LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
builder()->SetExpressionAsStatementPosition(stmt->each());
builder()->ForInContinue(index, cache_length);
loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean);
......@@ -1656,7 +1645,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
VisitForEffect(stmt->assign_iterator());
VisitForEffect(stmt->assign_next());
VisitIterationHeader(stmt, &loop_builder);
loop_builder.LoopHeader();
builder()->SetExpressionAsStatementPosition(stmt->next_result());
VisitForEffect(stmt->next_result());
TypeHint type_hint = VisitForAccumulatorValue(stmt->result_done());
......@@ -2825,11 +2814,12 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
VisitAssignment(expr);
}
// Suspends the generator to resume at |suspend_id|, with output stored in the
// accumulator. When the generator is resumed, the sent value is loaded in the
// accumulator.
void BytecodeGenerator::BuildSuspendPoint(int suspend_id,
Expression* suspend_expr) {
// Suspends the generator to resume at the next suspend_id, with output stored
// in the accumulator. When the generator is resumed, the sent value is loaded
// in the accumulator.
void BytecodeGenerator::BuildSuspendPoint(Expression* suspend_expr) {
const int suspend_id = suspend_count_++;
RegisterList registers = register_allocator()->AllLiveRegisters();
// Save context, registers, and state. This bytecode then returns the value
......@@ -2849,7 +2839,8 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
builder()->SetExpressionPosition(expr);
VisitForAccumulatorValue(expr->expression());
if (!expr->IsInitialYield()) {
// If this is not the first yield
if (suspend_count_ > 0) {
if (IsAsyncGeneratorFunction(function_kind())) {
// AsyncGenerator yields (with the exception of the initial yield)
// delegate work to the AsyncGeneratorYield stub, which Awaits the operand
......@@ -2875,7 +2866,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
}
}
BuildSuspendPoint(expr->suspend_id(), expr);
BuildSuspendPoint(expr);
// At this point, the generator has been resumed, with the received value in
// the accumulator.
......@@ -3014,10 +3005,16 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// visible to the user, and we therefore neither pass the block coverage
// builder nor the expression.
//
// YieldStar in AsyncGenerator functions includes 3 suspend points, rather
// than 1. These are documented in the YieldStar AST node.
// In addition to the normal suspend for yield*, a yield* in an async
// generator has 2 additional suspends:
// - One for awaiting the iterator result of closing the generator when
// resumed with a "throw" completion, and a throw method is not
// present on the delegated iterator
// - One for awaiting the iterator result yielded by the delegated
// iterator
LoopBuilder loop(builder(), nullptr, nullptr);
VisitIterationHeader(expr->suspend_id(), expr->suspend_count(), &loop);
loop.LoopHeader();
{
BytecodeLabels after_switch(zone());
......@@ -3071,8 +3068,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// If there is no "throw" method, perform IteratorClose, and finally
// throw a TypeError.
no_throw_method.Bind(builder());
BuildIteratorClose(iterator, expr->await_iterator_close_suspend_id(),
expr);
BuildIteratorClose(iterator, expr);
builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
}
......@@ -3081,7 +3077,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
if (iterator_type == IteratorType::kAsync) {
// Await the result of the method invocation.
BuildAwait(expr->await_delegated_iterator_output_suspend_id(), expr);
BuildAwait(expr);
}
// Check that output is an object.
......@@ -3121,7 +3117,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
.CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
}
BuildSuspendPoint(expr->suspend_id(), expr);
BuildSuspendPoint(expr);
builder()->StoreAccumulatorInRegister(input);
builder()
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
......@@ -3157,7 +3153,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
builder()->LoadAccumulatorWithRegister(output_value);
}
void BytecodeGenerator::BuildAwait(int suspend_id, Expression* await_expr) {
void BytecodeGenerator::BuildAwait(Expression* await_expr) {
// Rather than HandlerTable::UNCAUGHT, async functions use
// HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are
// transformed into promise rejections. This is necessary to prevent emitting
......@@ -3201,7 +3197,7 @@ void BytecodeGenerator::BuildAwait(int suspend_id, Expression* await_expr) {
builder()->CallJSRuntime(await_builtin_context_index, args);
}
BuildSuspendPoint(suspend_id, await_expr);
BuildSuspendPoint(await_expr);
Register input = register_allocator()->NewRegister();
Register resume_mode = register_allocator()->NewRegister();
......@@ -3229,7 +3225,7 @@ void BytecodeGenerator::BuildAwait(int suspend_id, Expression* await_expr) {
void BytecodeGenerator::VisitAwait(Await* expr) {
builder()->SetExpressionPosition(expr);
VisitForAccumulatorValue(expr->expression());
BuildAwait(expr->suspend_id(), expr);
BuildAwait(expr);
BuildIncrementBlockCoverageCounterIfEnabled(expr,
SourceRangeKind::kContinuation);
}
......@@ -4116,7 +4112,7 @@ void BytecodeGenerator::BuildCallIteratorMethod(Register iterator,
}
void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator,
int suspend_id, Expression* expr) {
Expression* expr) {
RegisterAllocationScope register_scope(this);
BytecodeLabels done(zone());
BytecodeLabel if_called;
......@@ -4127,9 +4123,8 @@ void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator,
builder()->Bind(&if_called);
if (iterator.type() == IteratorType::kAsync) {
DCHECK_GE(suspend_id, 0);
DCHECK_NOT_NULL(expr);
BuildAwait(suspend_id, expr);
BuildAwait(expr);
}
builder()->JumpIfJSReceiver(done.New());
......
......@@ -146,9 +146,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildNewLocalWithContext(Scope* scope);
void BuildGeneratorPrologue();
void BuildSuspendPoint(int suspend_id, Expression* suspend_expr);
void BuildSuspendPoint(Expression* suspend_expr);
void BuildAwait(int suspend_id, Expression* await_expr);
void BuildAwait(Expression* await_expr);
void BuildGetIterator(Expression* iterable, IteratorType hint);
......@@ -164,7 +164,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
IteratorRecord BuildGetIteratorRecord(Expression* iterable,
IteratorType hint);
void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
void BuildIteratorClose(const IteratorRecord& iterator, int suspend_id = -1,
void BuildIteratorClose(const IteratorRecord& iterator,
Expression* expr = nullptr);
void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
RegisterList receiver_and_args,
......@@ -213,11 +213,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
BytecodeLabels* end_labels,
int coverage_slot);
// Visit the header/body of a loop iteration.
void VisitIterationHeader(IterationStatement* stmt,
LoopBuilder* loop_builder);
void VisitIterationHeader(int first_suspend_id, int suspend_count,
LoopBuilder* loop_builder);
// Visit the body of a loop iteration.
void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
// Visit a statement and switch scopes, the context is in the accumulator.
......@@ -345,6 +341,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
Register incoming_new_target_or_generator_;
BytecodeJumpTable* generator_jump_table_;
int suspend_count_;
int loop_depth_;
HandlerTable::CatchPrediction catch_prediction_;
......
......@@ -47,10 +47,6 @@ void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) {
LoopBuilder::~LoopBuilder() {
DCHECK(continue_labels_.empty() || continue_labels_.is_bound());
// Restore the parent jump table.
if (generator_jump_table_location_ != nullptr) {
*generator_jump_table_location_ = parent_generator_jump_table_;
}
}
void LoopBuilder::LoopHeader() {
......@@ -62,26 +58,6 @@ void LoopBuilder::LoopHeader() {
builder()->Bind(&loop_header_);
}
void LoopBuilder::LoopHeaderInGenerator(
BytecodeJumpTable** generator_jump_table, int first_resume_id,
int resume_count) {
// Bind all the resume points that are inside the loop to be at the loop
// header.
for (int id = first_resume_id; id < first_resume_id + resume_count; ++id) {
builder()->Bind(*generator_jump_table, id);
}
// Create the loop header.
LoopHeader();
// Create a new jump table for after the loop header for only these
// resume points.
generator_jump_table_location_ = generator_jump_table;
parent_generator_jump_table_ = *generator_jump_table;
*generator_jump_table =
builder()->AllocateJumpTable(resume_count, first_resume_id);
}
void LoopBuilder::LoopBody() {
if (block_coverage_builder_ != nullptr) {
block_coverage_builder_->IncrementBlockCounter(block_coverage_body_slot_);
......
......@@ -105,9 +105,7 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
LoopBuilder(BytecodeArrayBuilder* builder,
BlockCoverageBuilder* block_coverage_builder, AstNode* node)
: BreakableControlFlowBuilder(builder, block_coverage_builder, node),
continue_labels_(builder->zone()),
generator_jump_table_location_(nullptr),
parent_generator_jump_table_(nullptr) {
continue_labels_(builder->zone()) {
if (block_coverage_builder_ != nullptr) {
set_needs_continuation_counter();
block_coverage_body_slot_ =
......@@ -118,8 +116,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
~LoopBuilder();
void LoopHeader();
void LoopHeaderInGenerator(BytecodeJumpTable** parent_generator_jump_table,
int first_resume_id, int resume_count);
void LoopBody();
void JumpToHeader(int loop_depth);
void BindContinueTarget();
......@@ -138,13 +134,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
// jumps from checking the loop condition to the header for do-while loops.
BytecodeLabels continue_labels_;
// While we're in the loop, we want to have a different jump table for
// generator switch statements. We restore it at the end of the loop.
// TODO(leszeks): Storing a pointer to the BytecodeGenerator's jump table
// field is ugly, figure out a better way to do this.
BytecodeJumpTable** generator_jump_table_location_;
BytecodeJumpTable* parent_generator_jump_table_;
int block_coverage_body_slot_;
};
......
......@@ -398,6 +398,9 @@ class ParserBase {
}
BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
void AddSuspend() { suspend_count_++; }
int suspend_count() const { return suspend_count_; }
FunctionKind kind() const { return scope()->function_kind(); }
FunctionState* outer() const { return outer_function_state_; }
......@@ -481,6 +484,9 @@ class ParserBase {
// A reason, if any, why this function should not be optimized.
BailoutReason dont_optimize_reason_;
// How many suspends are needed for this function.
int suspend_count_;
// Record whether the next (=== immediately following) function literal is
// preceded by a parenthesis / exclamation mark. Also record the previous
// state.
......@@ -1403,6 +1409,7 @@ class ParserBase {
// In async generators, if there is an explicit operand to the return
// statement, await the operand.
expr = factory()->NewAwait(expr, kNoSourcePosition);
function_state_->AddSuspend();
}
if (is_async_function()) {
return factory()->NewAsyncReturnStatement(expr, pos, end_pos);
......@@ -1562,6 +1569,7 @@ ParserBase<Impl>::FunctionState::FunctionState(
non_patterns_to_rewrite_(0, scope->zone()),
reported_errors_(16, scope->zone()),
dont_optimize_reason_(BailoutReason::kNoReason),
suspend_count_(0),
next_function_is_likely_called_(false),
previous_function_was_likely_called_(false),
contains_function_or_eval_(false) {
......@@ -3042,6 +3050,12 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
if (delegating) {
ExpressionT yieldstar = factory()->NewYieldStar(expression, pos);
impl()->RecordSuspendSourceRange(yieldstar, PositionAfterSemicolon());
function_state_->AddSuspend();
if (IsAsyncGeneratorFunction(function_state_->kind())) {
// iterator_close and delegated_iterator_output suspend ids.
function_state_->AddSuspend();
function_state_->AddSuspend();
}
return yieldstar;
}
......@@ -3050,6 +3064,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
ExpressionT yield =
factory()->NewYield(expression, pos, Suspend::kOnExceptionThrow);
impl()->RecordSuspendSourceRange(yield, PositionAfterSemicolon());
function_state_->AddSuspend();
return yield;
}
......@@ -3236,6 +3251,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
MessageTemplate::kInvalidDestructuringTarget);
ExpressionT expr = factory()->NewAwait(value, await_pos);
function_state_->AddSuspend();
impl()->RecordSuspendSourceRange(expr, PositionAfterSemicolon());
return expr;
} else {
......@@ -4351,6 +4367,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
StatementListT body = impl()->NullStatementList();
int expected_property_count = -1;
int suspend_count = 0;
int function_literal_id = GetNextFunctionLiteralId();
FunctionKind kind = formal_parameters.scope->function_kind();
......@@ -4436,6 +4453,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
impl()->RewriteDestructuringAssignments();
suspend_count = function_state.suspend_count();
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
......@@ -4447,6 +4465,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
formal_parameters.scope->start_position(), has_braces,
function_literal_id, produced_preparsed_scope_data);
function_literal->set_suspend_count(suspend_count);
function_literal->set_function_token_position(
formal_parameters.scope->start_position());
......@@ -5649,6 +5668,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// Either a standard for loop
// for (<init>; <cond>; <next>) { ... }
// or a for-each loop
// for (<each> of|in <iterable>) { ... }
//
// We parse a declaration/expression after the 'for (' and then read the first
// expression/declaration before we know if this is a for or a for-each.
int stmt_pos = peek_position();
ForInfo for_info(this);
......
......@@ -742,6 +742,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
result = factory()->NewScriptOrEvalFunctionLiteral(
scope, body, function_state.expected_property_count(),
parameter_count);
result->set_suspend_count(function_state.suspend_count());
}
}
......@@ -1831,6 +1832,8 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
// Don't create iterator result for async generators, as the resume methods
// will create it.
// TODO(leszeks): This will create another suspend point, which is unnecessary
// if there is already an unconditional return in the body.
Statement* final_return = BuildReturnStatement(
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
try_block->statements()->Add(final_return, zone());
......@@ -1900,6 +1903,7 @@ Expression* Parser::BuildIteratorNextResult(VariableProxy* iterator,
Expression* next_call =
factory()->NewCall(next_property, next_arguments, kNoSourcePosition);
if (type == IteratorType::kAsync) {
function_state_->AddSuspend();
next_call = factory()->NewAwait(next_call, pos);
}
Expression* result_proxy = factory()->NewVariableProxy(result);
......@@ -2681,6 +2685,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
ZoneList<Statement*>* body = nullptr;
int expected_property_count = -1;
int suspend_count = -1;
int num_parameters = -1;
int function_length = -1;
bool has_duplicate_parameters = false;
......@@ -2747,10 +2752,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (should_preparse) {
scope->AnalyzePartially(&previous_zone_ast_node_factory);
} else {
body = ParseFunction(function_name, pos, kind, function_type, scope,
&num_parameters, &function_length,
&has_duplicate_parameters, &expected_property_count,
arguments_for_wrapped_function, CHECK_OK);
body = ParseFunction(
function_name, pos, kind, function_type, scope, &num_parameters,
&function_length, &has_duplicate_parameters, &expected_property_count,
&suspend_count, arguments_for_wrapped_function, CHECK_OK);
}
DCHECK_EQ(should_preparse, temp_zoned_);
......@@ -2808,6 +2813,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_length, duplicate_parameters, function_type, eager_compile_hint,
pos, true, function_literal_id, produced_preparsed_scope_data);
function_literal->set_function_token_position(function_token_pos);
function_literal->set_suspend_count(suspend_count);
if (should_infer_name) {
DCHECK_NOT_NULL(fni_);
......@@ -3175,6 +3181,7 @@ Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
// The position of the yield is important for reporting the exception
// caused by calling the .throw method on a generator suspended at the
// initial yield (i.e. right after generator instantiation).
function_state_->AddSuspend();
return factory()->NewYield(yield_result, scope()->start_position(),
Suspend::kOnExceptionThrow);
}
......@@ -3184,6 +3191,7 @@ ZoneList<Statement*>* Parser::ParseFunction(
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters, int* function_length,
bool* has_duplicate_parameters, int* expected_property_count,
int* suspend_count,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok) {
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
......@@ -3268,6 +3276,7 @@ ZoneList<Statement*>* Parser::ParseFunction(
!classifier()->is_valid_formal_parameter_list_without_duplicates();
*expected_property_count = function_state.expected_property_count();
*suspend_count = function_state.suspend_count();
return body;
}
......@@ -4070,6 +4079,7 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
Expression* call =
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
if (type == IteratorType::kAsync) {
function_state_->AddSuspend();
call = factory()->NewAwait(call, nopos);
}
Expression* output_proxy = factory()->NewVariableProxy(var_output);
......@@ -4288,6 +4298,7 @@ void Parser::BuildIteratorCloseForCompletion(ZoneList<Statement*>* statements,
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
if (type == IteratorType::kAsync) {
function_state_->AddSuspend();
call = factory()->NewAwait(call, nopos);
}
......@@ -4315,6 +4326,7 @@ void Parser::BuildIteratorCloseForCompletion(ZoneList<Statement*>* statements,
Expression* call =
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
if (type == IteratorType::kAsync) {
function_state_->AddSuspend();
call = factory()->NewAwait(call, nopos);
}
......
......@@ -506,7 +506,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* expected_property_count,
int* expected_property_count, int* suspend_count,
ZoneList<const AstRawString*>* arguments_for_wrapped_function, bool* ok);
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
......
......@@ -304,6 +304,7 @@ class PreParserExpression {
int position() const { return kNoSourcePosition; }
void set_function_token_position(int position) {}
void set_scope(Scope* scope) {}
void set_suspend_count(int suspend_count) {}
private:
enum Type {
......
......@@ -597,7 +597,7 @@ bytecodes: [
B(Star), R(13),
B(Mov), R(0), R(12),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(12), U8(2),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(2),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(1),
B(ResumeGenerator), R(0), R(0), U8(12),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
......@@ -615,7 +615,7 @@ bytecodes: [
B(Star), R(13),
B(Mov), R(0), R(12),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(12), U8(2),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(3),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(2),
B(ResumeGenerator), R(0), R(0), U8(12),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
......@@ -637,7 +637,7 @@ bytecodes: [
B(Star), R(16),
B(Mov), R(0), R(14),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(14), U8(3),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(1),
/* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(3),
B(ResumeGenerator), R(0), R(0), U8(14),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
......@@ -719,9 +719,9 @@ bytecodes: [
]
constant pool: [
Smi [30],
Smi [310],
Smi [201],
Smi [251],
Smi [310],
Smi [360],
Smi [15],
Smi [7],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment