| Index: src/interpreter/bytecode-generator.cc
|
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
| index a81e1726179a27c1ccd10b70fdee885961cb2c21..c7264eac851dcbc2a30d71c15ffe95630ab120a1 100644
|
| --- a/src/interpreter/bytecode-generator.cc
|
| +++ b/src/interpreter/bytecode-generator.cc
|
| @@ -569,9 +569,10 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
|
| execution_result_(nullptr),
|
| register_allocator_(nullptr),
|
| generator_resume_points_(info->literal()->yield_count(), info->zone()),
|
| + generator_state_(),
|
| + generator_yields_seen_(0),
|
| try_catch_nesting_level_(0),
|
| - try_finally_nesting_level_(0),
|
| - generator_yields_seen_(0) {
|
| + try_finally_nesting_level_(0) {
|
| InitializeAstVisitor(isolate());
|
| }
|
|
|
| @@ -582,7 +583,10 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() {
|
| // Initialize control scope.
|
| ControlScopeForTopLevel control(this);
|
|
|
| + RegisterAllocationScope register_scope(this);
|
| +
|
| if (IsGeneratorFunction(info()->literal()->kind())) {
|
| + generator_state_ = register_allocator()->NewRegister();
|
| VisitGeneratorPrologue();
|
| }
|
|
|
| @@ -632,30 +636,71 @@ void BytecodeGenerator::MakeBytecodeBody() {
|
| VisitStatements(info()->literal()->body());
|
| }
|
|
|
| +void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index,
|
| + size_t size,
|
| + ZoneVector<BytecodeLabel>& targets) {
|
| + // TODO(neis): Optimize this by using a proper jump table.
|
| + for (size_t i = start_index; i < start_index + size; i++) {
|
| + DCHECK(0 <= i && i < targets.size());
|
| + builder()
|
| + ->LoadLiteral(Smi::FromInt(static_cast<int>(i)))
|
| + .CompareOperation(Token::Value::EQ_STRICT, index)
|
| + .JumpIfTrue(&(targets[i]));
|
| + }
|
| + builder()->Illegal(); // Should never get here.
|
| +}
|
| +
|
| +void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
|
| + LoopBuilder* loop_builder) {
|
| + // Recall that stmt->yield_count() is always zero inside ordinary
|
| + // (i.e. non-generator) functions.
|
| +
|
| + // Collect all labels for generator resume points within the loop (if any) so
|
| + // that they can be bound to the loop header below. Also create fresh labels
|
| + // for these resume points, to be used inside the loop.
|
| + ZoneVector<BytecodeLabel> resume_points_in_loop(zone());
|
| + for (size_t id = generator_yields_seen_;
|
| + id < generator_yields_seen_ + stmt->yield_count(); id++) {
|
| + DCHECK(0 <= id && id < generator_resume_points_.size());
|
| + auto& label = generator_resume_points_[id];
|
| + resume_points_in_loop.push_back(label);
|
| + generator_resume_points_[id] = BytecodeLabel();
|
| + }
|
| +
|
| + loop_builder->LoopHeader(&resume_points_in_loop);
|
| +
|
| + if (stmt->yield_count() > 0) {
|
| + // If we are not resuming, fall through to loop body.
|
| + // If we are resuming, perform state dispatch.
|
| + BytecodeLabel not_resuming;
|
| + builder()
|
| + ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
|
| + .CompareOperation(Token::Value::EQ, generator_state_)
|
| + .JumpIfTrue(¬_resuming);
|
| + BuildIndexedJump(generator_state_, generator_yields_seen_,
|
| + stmt->yield_count(), generator_resume_points_);
|
| + builder()->Bind(¬_resuming);
|
| + }
|
| +}
|
| +
|
| void BytecodeGenerator::VisitGeneratorPrologue() {
|
| + // The generator resume trampoline abuses the new.target register both to
|
| + // indicate that this is a resume call and to pass in the generator object.
|
| + // In ordinary calls, new.target is always undefined because generator
|
| + // functions are non-constructable.
|
| + Register generator_object = Register::new_target();
|
| BytecodeLabel regular_call;
|
| builder()
|
| - ->LoadAccumulatorWithRegister(Register::new_target())
|
| + ->LoadAccumulatorWithRegister(generator_object)
|
| .JumpIfUndefined(®ular_call);
|
|
|
| // This is a resume call. Restore registers and perform state dispatch.
|
| // (The current context has already been restored by the trampoline.)
|
| - {
|
| - RegisterAllocationScope register_scope(this);
|
| - Register state = register_allocator()->NewRegister();
|
| - builder()
|
| - ->ResumeGenerator(Register::new_target())
|
| - .StoreAccumulatorInRegister(state);
|
| -
|
| - // TODO(neis): Optimize this by using a proper jump table.
|
| - for (size_t i = 0; i < generator_resume_points_.size(); ++i) {
|
| - builder()
|
| - ->LoadLiteral(Smi::FromInt(static_cast<int>(i)))
|
| - .CompareOperation(Token::Value::EQ_STRICT, state)
|
| - .JumpIfTrue(&(generator_resume_points_[i]));
|
| - }
|
| - builder()->Illegal(); // Should never get here.
|
| - }
|
| + builder()
|
| + ->ResumeGenerator(generator_object)
|
| + .StoreAccumulatorInRegister(generator_state_);
|
| + BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(),
|
| + generator_resume_points_);
|
|
|
| builder()->Bind(®ular_call);
|
| // This is a regular call. Fall through to the ordinary function prologue,
|
| @@ -989,7 +1034,7 @@ void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
|
|
|
| void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| LoopBuilder loop_builder(builder());
|
| - loop_builder.LoopHeader();
|
| + VisitIterationHeader(stmt, &loop_builder);
|
| if (stmt->cond()->ToBooleanIsFalse()) {
|
| VisitIterationBody(stmt, &loop_builder);
|
| loop_builder.Condition();
|
| @@ -1014,7 +1059,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
| }
|
|
|
| LoopBuilder loop_builder(builder());
|
| - loop_builder.LoopHeader();
|
| + VisitIterationHeader(stmt, &loop_builder);
|
| loop_builder.Condition();
|
| if (!stmt->cond()->ToBooleanIsTrue()) {
|
| builder()->SetExpressionAsStatementPosition(stmt->cond());
|
| @@ -1038,7 +1083,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| }
|
|
|
| LoopBuilder loop_builder(builder());
|
| - loop_builder.LoopHeader();
|
| + VisitIterationHeader(stmt, &loop_builder);
|
| loop_builder.Condition();
|
| if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
|
| builder()->SetExpressionAsStatementPosition(stmt->cond());
|
| @@ -1163,7 +1208,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| builder()->StoreAccumulatorInRegister(index);
|
|
|
| // The loop
|
| - loop_builder.LoopHeader();
|
| + VisitIterationHeader(stmt, &loop_builder);
|
| builder()->SetExpressionAsStatementPosition(stmt->each());
|
| loop_builder.Condition();
|
| builder()->ForInDone(index, cache_length);
|
| @@ -1191,7 +1236,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
| builder()->SetExpressionAsStatementPosition(stmt->assign_iterator());
|
| VisitForEffect(stmt->assign_iterator());
|
|
|
| - loop_builder.LoopHeader();
|
| + VisitIterationHeader(stmt, &loop_builder);
|
| loop_builder.Next();
|
| builder()->SetExpressionAsStatementPosition(stmt->next_result());
|
| VisitForEffect(stmt->next_result());
|
| @@ -2213,7 +2258,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
|
| }
|
|
|
| void BytecodeGenerator::VisitYield(Yield* expr) {
|
| - int id = generator_yields_seen_++;
|
| + size_t id = generator_yields_seen_++;
|
|
|
| builder()->SetExpressionPosition(expr);
|
| Register value = VisitForRegisterValue(expr->expression());
|
| @@ -2222,7 +2267,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
|
|
|
| // Save context, registers, and state. Then return.
|
| builder()
|
| - ->LoadLiteral(Smi::FromInt(id))
|
| + ->LoadLiteral(Smi::FromInt(static_cast<int>(id)))
|
| .SuspendGenerator(generator)
|
| .LoadAccumulatorWithRegister(value)
|
| .Return(); // Hard return (ignore any finally blocks).
|
| @@ -2233,6 +2278,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
|
| {
|
| RegisterAllocationScope register_scope(this);
|
|
|
| + // Update state to indicate that we have finished resuming. Loop headers
|
| + // rely on this.
|
| + builder()
|
| + ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
|
| + .StoreAccumulatorInRegister(generator_state_);
|
| +
|
| Register input = register_allocator()->NewRegister();
|
| builder()
|
| ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1)
|
|
|