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

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

Issue 1403943004: [Interpreter] Add support for local context loads and stores. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@int_contextchain
Patch Set: Add back outer_ &&] Created 5 years, 2 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/bytecodes.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 a4efcce1da5666fd827a87ad739051af6deeef5e..713fa4401d0e82326d1fb6203d84444fdb6c9383 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -23,39 +23,54 @@ namespace interpreter {
// popping of the current {context_register} during visitation.
class BytecodeGenerator::ContextScope BASE_EMBEDDED {
public:
- explicit ContextScope(BytecodeGenerator* generator,
- bool is_function_context = false)
+ ContextScope(BytecodeGenerator* generator, Scope* scope,
+ bool should_pop_context = true)
: generator_(generator),
- outer_(generator_->current_context()),
- is_function_context_(is_function_context) {
- DCHECK(!is_function_context ||
- outer_.index() == Register::function_context().index());
- Register new_context_reg = NewContextRegister();
- generator_->builder()->PushContext(new_context_reg);
- generator_->set_current_context(new_context_reg);
+ scope_(scope),
+ outer_(generator_->execution_context()),
+ register_(generator_->NextContextRegister()),
+ depth_(0),
+ should_pop_context_(should_pop_context) {
+ if (outer_) {
+ depth_ = outer_->depth_ + 1;
+ generator_->builder()->PushContext(register_);
+ }
+ generator_->set_execution_context(this);
}
~ContextScope() {
- if (!is_function_context_) {
- generator_->builder()->PopContext(outer_);
+ if (outer_ && should_pop_context_) {
+ generator_->builder()->PopContext(outer_->reg());
}
- generator_->set_current_context(outer_);
+ generator_->set_execution_context(outer_);
}
- private:
- Register NewContextRegister() const {
- if (outer_.index() == Register::function_context().index()) {
- return generator_->builder()->first_context_register();
- } else {
- DCHECK_LT(outer_.index(),
- generator_->builder()->last_context_register().index());
- return Register(outer_.index() + 1);
+ // Returns the execution context for the given |scope| if it is a function
+ // local execution context, otherwise returns nullptr.
+ ContextScope* Previous(Scope* scope) {
+ int depth = scope_->ContextChainLength(scope);
+ if (depth > depth_) {
+ return nullptr;
+ }
+
+ ContextScope* previous = this;
+ for (int i = depth; i > 0; --i) {
+ previous = previous->outer_;
}
+ DCHECK_EQ(previous->scope_, scope);
+ return previous;
}
+ Scope* scope() const { return scope_; }
+ Register reg() const { return register_; }
+
+ private:
BytecodeGenerator* generator_;
- Register outer_;
- bool is_function_context_;
+ Scope* scope_;
+ ContextScope* outer_;
+ Register register_;
+ int depth_;
+ bool should_pop_context_;
};
@@ -64,10 +79,10 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED {
class BytecodeGenerator::ControlScope BASE_EMBEDDED {
public:
explicit ControlScope(BytecodeGenerator* generator)
- : generator_(generator), outer_(generator->control_scope()) {
- generator_->set_control_scope(this);
+ : generator_(generator), outer_(generator->execution_control()) {
+ generator_->set_execution_control(this);
}
- virtual ~ControlScope() { generator_->set_control_scope(outer()); }
+ virtual ~ControlScope() { generator_->set_execution_control(outer()); }
void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); }
void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); }
@@ -138,8 +153,8 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
info_(nullptr),
scope_(nullptr),
globals_(0, zone),
- control_scope_(nullptr),
- current_context_(Register::function_context()) {
+ execution_control_(nullptr),
+ execution_context_(nullptr) {
InitializeAstVisitor(isolate);
}
@@ -151,6 +166,9 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
set_info(info);
set_scope(info->scope());
+ // Initialize the incoming context.
+ ContextScope incoming_context(this, scope(), false);
+
builder()->set_parameter_count(info->num_parameters_including_this());
builder()->set_locals_count(scope()->num_stack_slots());
builder()->set_context_count(scope()->MaxNestedContextChainLength());
@@ -159,7 +177,8 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
if (scope()->NeedsContext()) {
// Push a new inner context scope for the function.
VisitNewLocalFunctionContext();
- ContextScope top_context(this, true);
+ ContextScope local_function_context(this, scope(), false);
+ VisitBuildLocalActivationContext();
MakeBytecodeBody();
} else {
MakeBytecodeBody();
@@ -180,18 +199,21 @@ void BytecodeGenerator::MakeBytecodeBody() {
}
-void BytecodeGenerator::VisitBlock(Block* node) {
+void BytecodeGenerator::VisitBlock(Block* stmt) {
builder()->EnterBlock();
- if (node->scope() == NULL) {
+ if (stmt->scope() == NULL) {
// Visit statements in the same scope, no declarations.
- VisitStatements(node->statements());
+ VisitStatements(stmt->statements());
} else {
// Visit declarations and statements in a block scope.
- if (node->scope()->ContextLocalCount() > 0) {
- UNIMPLEMENTED();
+ if (stmt->scope()->NeedsContext()) {
+ VisitNewLocalBlockContext(stmt->scope());
+ ContextScope scope(this, stmt->scope());
+ VisitDeclarations(stmt->scope()->declarations());
+ VisitStatements(stmt->statements());
} else {
- VisitDeclarations(node->scope()->declarations());
- VisitStatements(node->statements());
+ VisitDeclarations(stmt->scope()->declarations());
+ VisitStatements(stmt->statements());
}
}
builder()->LeaveBlock();
@@ -201,10 +223,9 @@ void BytecodeGenerator::VisitBlock(Block* node) {
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
Variable* variable = decl->proxy()->var();
VariableMode mode = decl->mode();
+ // Const and let variables are initialized with the hole so that we can
+ // check that they are only assigned once.
bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
- if (hole_init) {
- UNIMPLEMENTED();
- }
switch (variable->location()) {
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
@@ -215,11 +236,26 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
globals()->push_back(value);
break;
}
- case VariableLocation::PARAMETER:
case VariableLocation::LOCAL:
- // Details stored in scope, i.e. variable index.
+ if (hole_init) {
+ Register destination(variable->index());
+ builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
+ }
+ break;
+ case VariableLocation::PARAMETER:
+ if (hole_init) {
+ // The parameter indices are shifted by 1 (receiver is variable
+ // index -1 but is parameter index 0 in BytecodeArrayBuilder).
+ Register destination(builder()->Parameter(variable->index() + 1));
+ builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
+ }
break;
case VariableLocation::CONTEXT:
+ if (hole_init) {
+ builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
+ variable->index());
+ }
+ break;
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
break;
@@ -326,12 +362,12 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
- control_scope()->Continue(stmt->target());
+ execution_control()->Continue(stmt->target());
}
void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
- control_scope()->Break(stmt->target());
+ execution_control()->Break(stmt->target());
}
@@ -356,7 +392,7 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
LoopBuilder loop_builder(builder());
- ControlScopeForIteration control_scope(this, stmt, &loop_builder);
+ ControlScopeForIteration execution_control(this, stmt, &loop_builder);
BytecodeLabel body_label, condition_label, done_label;
builder()->Bind(&body_label);
@@ -373,7 +409,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
LoopBuilder loop_builder(builder());
- ControlScopeForIteration control_scope(this, stmt, &loop_builder);
+ ControlScopeForIteration execution_control(this, stmt, &loop_builder);
BytecodeLabel body_label, condition_label, done_label;
builder()->Jump(&condition_label);
@@ -391,7 +427,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
LoopBuilder loop_builder(builder());
- ControlScopeForIteration control_scope(this, stmt, &loop_builder);
+ ControlScopeForIteration execution_control(this, stmt, &loop_builder);
if (stmt->init() != nullptr) {
Visit(stmt->init());
@@ -595,8 +631,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
}
- // Create nodes to define accessors, using only a single call to the runtime
- // for each pair of corresponding getters and setters.
+ // Define accessors, using only a single call to the runtime for each pair of
+ // corresponding getters and setters.
for (AccessorTable::Iterator it = accessor_table.begin();
it != accessor_table.end(); ++it) {
TemporaryRegisterScope inner_temporary_register_scope(builder());
@@ -698,8 +734,8 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
TemporaryRegisterScope temporary_register_scope(builder());
Register index, literal;
- // Create nodes to evaluate all the non-constant subexpressions and to store
- // them into the newly cloned array.
+ // Evaluate all the non-constant subexpressions and store them into the
+ // newly cloned array.
bool literal_in_accumulator = true;
for (int array_index = 0; array_index < expr->values()->length();
array_index++) {
@@ -744,6 +780,8 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
case VariableLocation::LOCAL: {
Register source(variable->index());
builder()->LoadAccumulatorWithRegister(source);
+ // TODO(rmcilroy): Perform check for uninitialized legacy const, const and
+ // let variables.
break;
}
case VariableLocation::PARAMETER: {
@@ -765,14 +803,24 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
case VariableLocation::UNALLOCATED: {
TemporaryRegisterScope temporary_register_scope(builder());
Register obj = temporary_register_scope.NewRegister();
- builder()->LoadContextSlot(current_context(),
+ builder()->LoadContextSlot(execution_context()->reg(),
Context::GLOBAL_OBJECT_INDEX);
builder()->StoreAccumulatorInRegister(obj);
builder()->LoadLiteral(variable->name());
builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode());
break;
}
- case VariableLocation::CONTEXT:
+ case VariableLocation::CONTEXT: {
+ ContextScope* context = execution_context()->Previous(variable->scope());
+ if (context) {
+ builder()->LoadContextSlot(context->reg(), variable->index());
+ } else {
+ UNIMPLEMENTED();
+ }
+ // TODO(rmcilroy): Perform check for uninitialized legacy const, const and
+ // let variables.
+ break;
+ }
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
@@ -812,7 +860,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
// TODO(rmcilroy): Investigate whether we can avoid having to stash the
// value in a register.
builder()->StoreAccumulatorInRegister(value);
- builder()->LoadContextSlot(current_context(),
+ builder()->LoadContextSlot(execution_context()->reg(),
Context::GLOBAL_OBJECT_INDEX);
builder()->StoreAccumulatorInRegister(obj);
builder()->LoadLiteral(variable->name());
@@ -822,7 +870,16 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
language_mode());
break;
}
- case VariableLocation::CONTEXT:
+ case VariableLocation::CONTEXT: {
+ // TODO(rmcilroy): support const mode initialization.
+ ContextScope* context = execution_context()->Previous(variable->scope());
+ if (context) {
+ builder()->StoreContextSlot(context->reg(), variable->index());
+ } else {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
@@ -1141,6 +1198,11 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
builder()->CallRuntime(Runtime::kNewFunctionContext,
Register::function_closure(), 1);
}
+}
+
+
+void BytecodeGenerator::VisitBuildLocalActivationContext() {
+ Scope* scope = this->scope();
if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
UNIMPLEMENTED();
@@ -1150,13 +1212,37 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
int num_parameters = scope->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Variable* variable = scope->parameter(i);
- if (variable->IsContextSlot()) {
- UNIMPLEMENTED();
- }
+ if (!variable->IsContextSlot()) continue;
+
+ // The parameter indices are shifted by 1 (receiver is variable
+ // index -1 but is parameter index 0 in BytecodeArrayBuilder).
+ Register parameter(builder()->Parameter(i + 1));
+ // Context variable (at bottom of the context chain).
+ DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
+ builder()->LoadAccumulatorWithRegister(parameter)
+ .StoreContextSlot(execution_context()->reg(), variable->index());
}
}
+void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
+ DCHECK(scope->is_block_scope());
+
+ // Allocate a new local block context.
+ TemporaryRegisterScope temporary_register_scope(builder());
+ Register scope_info = temporary_register_scope.NewRegister();
+ Register closure = temporary_register_scope.NewRegister();
+ DCHECK(Register::AreContiguous(scope_info, closure));
+ builder()
+ ->LoadLiteral(scope->GetScopeInfo(isolate()))
+ .StoreAccumulatorInRegister(scope_info);
+ VisitFunctionClosureForContext();
+ builder()
+ ->StoreAccumulatorInRegister(closure)
+ .CallRuntime(Runtime::kPushBlockContext, scope_info, 2);
+}
+
+
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
Token::Value op = binop->op();
Expression* left = binop->left();
@@ -1172,41 +1258,6 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
}
-void BytecodeGenerator::VisitObjectLiteralAccessor(
- Register home_object, ObjectLiteralProperty* property, Register value_out) {
- // TODO(rmcilroy): Replace value_out with VisitForRegister();
- if (property == nullptr) {
- builder()->LoadNull().StoreAccumulatorInRegister(value_out);
- } else {
- Visit(property->value());
- builder()->StoreAccumulatorInRegister(value_out);
- VisitSetHomeObject(value_out, home_object, property);
- }
-}
-
-
-void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
- ObjectLiteralProperty* property,
- int slot_number) {
- Expression* expr = property->value();
- if (!FunctionLiteral::NeedsHomeObject(expr)) return;
-
- // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the
- // home object.
- UNIMPLEMENTED();
-
- TemporaryRegisterScope temporary_register_scope(builder());
- Register name = temporary_register_scope.NewRegister();
- isolate()->factory()->home_object_symbol();
- builder()
- ->LoadLiteral(isolate()->factory()->home_object_symbol())
- .StoreAccumulatorInRegister(name)
- .StoreNamedProperty(home_object, name,
- feedback_index(property->GetSlot(slot_number)),
- language_mode());
-}
-
-
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
@@ -1254,6 +1305,74 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
}
+void BytecodeGenerator::VisitObjectLiteralAccessor(
+ Register home_object, ObjectLiteralProperty* property, Register value_out) {
+ // TODO(rmcilroy): Replace value_out with VisitForRegister();
+ if (property == nullptr) {
+ builder()->LoadNull().StoreAccumulatorInRegister(value_out);
+ } else {
+ Visit(property->value());
+ builder()->StoreAccumulatorInRegister(value_out);
+ VisitSetHomeObject(value_out, home_object, property);
+ }
+}
+
+
+void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
+ ObjectLiteralProperty* property,
+ int slot_number) {
+ Expression* expr = property->value();
+ if (!FunctionLiteral::NeedsHomeObject(expr)) return;
+
+ // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the
+ // home object.
+ UNIMPLEMENTED();
+
+ TemporaryRegisterScope temporary_register_scope(builder());
+ Register name = temporary_register_scope.NewRegister();
+ isolate()->factory()->home_object_symbol();
+ builder()
+ ->LoadLiteral(isolate()->factory()->home_object_symbol())
+ .StoreAccumulatorInRegister(name)
+ .StoreNamedProperty(home_object, name,
+ feedback_index(property->GetSlot(slot_number)),
+ language_mode());
+}
+
+
+void BytecodeGenerator::VisitFunctionClosureForContext() {
+ Scope* closure_scope = execution_context()->scope()->ClosureScope();
+ if (closure_scope->is_script_scope() ||
+ closure_scope->is_module_scope()) {
+ // Contexts nested in the native context have a canonical empty function as
+ // their closure, not the anonymous closure containing the global code.
+ // Pass a SMI sentinel and let the runtime look up the empty function.
+ builder()->LoadLiteral(Smi::FromInt(0));
+ } else {
+ DCHECK(closure_scope->is_function_scope());
+ builder()->LoadAccumulatorWithRegister(Register::function_closure());
+ }
+}
+
+
+Register BytecodeGenerator::NextContextRegister() const {
+ if (execution_context() == nullptr) {
+ // Return the incoming function context for the outermost execution context.
+ return Register::function_context();
+ }
+ Register previous = execution_context()->reg();
+ if (previous == Register::function_context()) {
+ // If the previous context was the incoming function context, then the next
+ // context register is the first local context register.
+ return builder_.first_context_register();
+ } else {
+ // Otherwise use the next local context register.
+ DCHECK_LT(previous.index(), builder_.last_context_register().index());
+ return Register(previous.index() + 1);
+ }
+}
+
+
LanguageMode BytecodeGenerator::language_mode() const {
return info()->language_mode();
}
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698