Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Unified Diff: src/interpreter/bytecode-generator.cc

Issue 1884183002: First version of the new generators implementation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-register-allocator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/interpreter/bytecode-generator.cc
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index 0dabea2ed31db0db4b2b42282162ce19e958f4ab..b1b8517b1917c3611991b9a95f69ffa70d394df6 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -565,8 +565,10 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
execution_context_(nullptr),
execution_result_(nullptr),
register_allocator_(nullptr),
+ generator_resume_points_(0, zone),
try_catch_nesting_level_(0),
- try_finally_nesting_level_(0) {
+ try_finally_nesting_level_(0),
+ generator_yields_seen_(0) {
InitializeAstVisitor(isolate);
}
@@ -586,6 +588,10 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
// Initialize control scope.
ControlScopeForTopLevel control(this);
+ if (IsGeneratorFunction(info->literal()->kind())) {
+ VisitGeneratorPrologue();
+ }
+
// Build function context only if there are context allocated variables.
if (scope()->NeedsContext()) {
// Push a new inner context scope for the function.
@@ -634,6 +640,40 @@ void BytecodeGenerator::MakeBytecodeBody() {
VisitStatements(info()->literal()->body());
}
+void BytecodeGenerator::VisitGeneratorPrologue() {
+ generator_resume_points_.clear();
+ generator_resume_points_.resize(info()->literal()->yield_count());
+
+ BytecodeLabel regular_call;
+ builder()
+ ->LoadAccumulatorWithRegister(Register::new_target())
+ .JumpIfUndefined(&regular_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()
+ ->CallRuntime(Runtime::kResumeIgnitionGenerator, Register::new_target(),
+ 1)
+ .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()->Bind(&regular_call);
+ // This is a regular call. Fall through to the ordinary function prologue,
+ // after which we will run into the generator object creation and the initial
+ // yield (both inserted by the parser).
+}
void BytecodeGenerator::VisitBlock(Block* stmt) {
// Visit declarations and statements.
@@ -2229,16 +2269,86 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
execution_result()->SetResultInAccumulator();
}
+void BytecodeGenerator::VisitYield(Yield* expr) {
+ int id = generator_yields_seen_++;
+
+ builder()->SetExpressionPosition(expr);
+ Register value = VisitForRegisterValue(expr->expression());
+
+ register_allocator()->PrepareForConsecutiveAllocations(2);
+ Register generator = register_allocator()->NextConsecutiveRegister();
+ Register state = register_allocator()->NextConsecutiveRegister();
+
+ // Save context, registers, and state. Then return.
+ VisitForRegisterValue(expr->generator_object(), generator);
+ builder()
+ ->LoadLiteral(Smi::FromInt(id))
+ .StoreAccumulatorInRegister(state)
+ .CallRuntime(Runtime::kSuspendIgnitionGenerator, generator, 2)
+ .LoadAccumulatorWithRegister(value)
+ .Return(); // Hard return (ignore any finally blocks).
+
+ builder()->Bind(&(generator_resume_points_[id]));
+ // Upon resume, we continue here.
+
+ {
+ RegisterAllocationScope register_scope(this);
+
+ Register input = register_allocator()->NewRegister();
+ builder()
+ ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1)
+ .StoreAccumulatorInRegister(input);
+
+ Register resume_mode = register_allocator()->NewRegister();
+ builder()
+ ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1)
+ .StoreAccumulatorInRegister(resume_mode);
+
+ // Now dispatch on resume mode.
+
+ BytecodeLabel resume_with_next;
+ BytecodeLabel resume_with_return;
+ BytecodeLabel resume_with_throw;
-void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); }
+ builder()
+ ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
+ .CompareOperation(Token::EQ_STRICT, resume_mode)
+ .JumpIfTrue(&resume_with_next)
+ .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
+ .CompareOperation(Token::EQ_STRICT, resume_mode)
+ .JumpIfTrue(&resume_with_throw)
+ .Jump(&resume_with_return);
Jarin 2016/04/18 13:55:06 Out of curiosity, do you even need the Jump?
neis 2016/04/18 14:07:52 Shhh :)
+
+ builder()->Bind(&resume_with_return);
+ {
+ register_allocator()->PrepareForConsecutiveAllocations(2);
+ Register value = register_allocator()->NextConsecutiveRegister();
+ Register done = register_allocator()->NextConsecutiveRegister();
+ builder()
+ ->MoveRegister(input, value)
+ .LoadTrue()
+ .StoreAccumulatorInRegister(done)
+ .CallRuntime(Runtime::kCreateIterResultObject, value, 2);
+ execution_control()->ReturnAccumulator();
+ }
+ builder()->Bind(&resume_with_throw);
+ builder()
+ ->LoadAccumulatorWithRegister(input)
+ .Throw();
+
+ builder()->Bind(&resume_with_next);
+ builder()->LoadAccumulatorWithRegister(input);
+ }
+ execution_result()->SetResultInAccumulator();
+}
void BytecodeGenerator::VisitThrow(Throw* expr) {
VisitForAccumulatorValue(expr->exception());
builder()->SetExpressionPosition(expr);
builder()->Throw();
- // Throw statments are modeled as expression instead of statments. These are
- // converted from assignment statements in Rewriter::ReWrite pass. An
+ // Throw statements are modeled as expressions instead of statements. These
+ // are converted from assignment statements in Rewriter::ReWrite pass. An
// assignment statement expects a value in the accumulator. This is a hack to
// avoid DCHECK fails assert accumulator has been set.
execution_result()->SetResultInAccumulator();
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-register-allocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698