Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index 6fbb46e722bc3c67896e1e2a9d059747d830f4d8..2eb235df04c701bbbedcca3656b62b6eb6d33b88 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -17,6 +17,47 @@ namespace internal { |
namespace interpreter { |
+// Scoped class tracking context objects created by the visitor. Represents |
+// mutations of the context chain within the function body, allowing pushing and |
+// popping of the current {context_register} during visitation. |
+class BytecodeGenerator::ContextScope BASE_EMBEDDED { |
+ public: |
+ explicit ContextScope(BytecodeGenerator* generator, |
+ bool is_function_context = false) |
+ : 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); |
+ } |
+ |
+ ~ContextScope() { |
+ if (!is_function_context_) { |
+ generator_->builder()->PopContext(outer_); |
+ } |
+ generator_->set_current_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); |
+ } |
+ } |
+ |
+ BytecodeGenerator* generator_; |
+ Register outer_; |
+ bool is_function_context_; |
+}; |
+ |
+ |
// Scoped class for tracking control statements entered by the |
// visitor. The pattern derives AstGraphBuilder::ControlScope. |
class BytecodeGenerator::ControlScope BASE_EMBEDDED { |
@@ -109,21 +150,31 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
builder()->set_parameter_count(info->num_parameters_including_this()); |
builder()->set_locals_count(scope()->num_stack_slots()); |
- |
- // Visit implicit declaration of the function name. |
- if (scope()->is_function_scope() && scope()->function() != NULL) { |
- VisitVariableDeclaration(scope()->function()); |
+ // TODO(rmcilroy): Set correct context count. |
+ builder()->set_context_count(info->num_heap_slots() > 0 ? 1 : 0); |
+ |
+ // Build function context only if there are context allocated variables. |
+ if (info->num_heap_slots() > 0) { |
+ // Push a new inner context scope for the function. |
+ VisitNewLocalFunctionContext(); |
+ ContextScope top_context(this, true); |
+ MakeBytecodeBody(); |
+ } else { |
+ MakeBytecodeBody(); |
} |
+ set_scope(nullptr); |
+ set_info(nullptr); |
+ return builder_.ToBytecodeArray(); |
+} |
+ |
+ |
+void BytecodeGenerator::MakeBytecodeBody() { |
// Visit declarations within the function scope. |
VisitDeclarations(scope()->declarations()); |
// Visit statements in the function body. |
- VisitStatements(info->literal()->body()); |
- |
- set_scope(nullptr); |
- set_info(nullptr); |
- return builder_.ToBytecodeArray(); |
+ VisitStatements(info()->literal()->body()); |
} |
@@ -219,7 +270,7 @@ void BytecodeGenerator::VisitDeclarations( |
DeclareGlobalsNativeFlag::encode(info()->is_native()) | |
DeclareGlobalsLanguageMode::encode(language_mode()); |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register pairs = temporary_register_scope.NewRegister(); |
builder()->LoadLiteral(data); |
builder()->StoreAccumulatorInRegister(pairs); |
@@ -484,7 +535,7 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
break; |
} |
case VariableLocation::UNALLOCATED: { |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register obj = temporary_register_scope.NewRegister(); |
builder()->LoadContextSlot(current_context(), |
Context::GLOBAL_OBJECT_INDEX); |
@@ -526,7 +577,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
break; |
} |
case VariableLocation::UNALLOCATED: { |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register value = temporary_register_scope.NewRegister(); |
Register obj = temporary_register_scope.NewRegister(); |
Register name = temporary_register_scope.NewRegister(); |
@@ -552,7 +603,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
DCHECK(expr->target()->IsValidReferenceExpression()); |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register object, key; |
// Left-hand side can only be a property, a global or a variable slot. |
@@ -646,7 +697,7 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
void BytecodeGenerator::VisitProperty(Property* expr) { |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register obj = temporary_register_scope.NewRegister(); |
Visit(expr->obj()); |
builder()->StoreAccumulatorInRegister(obj); |
@@ -660,7 +711,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
// Prepare the callee and the receiver to the function call. This depends on |
// the semantics of the underlying call type. |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register callee = temporary_register_scope.NewRegister(); |
Register receiver = temporary_register_scope.NewRegister(); |
@@ -724,7 +775,7 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
// Evaluate all arguments to the runtime call. |
ZoneList<Expression*>* args = expr->arguments(); |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
// Ensure we always have a valid first_arg register even if there are no |
// arguments to pass. |
Register first_arg = temporary_register_scope.NewRegister(); |
@@ -805,7 +856,7 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
Expression* left = expr->left(); |
Expression* right = expr->right(); |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register temporary = temporary_register_scope.NewRegister(); |
Visit(left); |
@@ -839,12 +890,47 @@ void BytecodeGenerator::VisitSuperPropertyReference( |
} |
+void BytecodeGenerator::VisitNewLocalFunctionContext() { |
+ Scope* scope = this->scope(); |
+ |
+ // Allocate a new local context. |
+ if (scope->is_script_scope()) { |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
+ Register closure = temporary_register_scope.NewRegister(); |
+ Register scope_info = temporary_register_scope.NewRegister(); |
+ DCHECK_EQ(closure.index() + 1, scope_info.index()); |
+ builder() |
+ ->LoadAccumulatorWithRegister(Register::function_closure()) |
+ .StoreAccumulatorInRegister(closure) |
+ .LoadLiteral(scope->GetScopeInfo(isolate())) |
+ .StoreAccumulatorInRegister(scope_info) |
+ .CallRuntime(Runtime::kNewScriptContext, closure, 2); |
+ } else { |
+ builder()->CallRuntime(Runtime::kNewFunctionContext, |
+ Register::function_closure(), 1); |
+ } |
+ |
+ if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { |
+ UNIMPLEMENTED(); |
+ } |
+ |
+ // Copy parameters into context if necessary. |
+ int num_parameters = scope->num_parameters(); |
+ for (int i = 0; i < num_parameters; i++) { |
+ Variable* variable = scope->parameter(i); |
+ if (variable->IsContextSlot()) { |
+ UNIMPLEMENTED(); |
+ } |
+ } |
+} |
+ |
+ |
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
Token::Value op = binop->op(); |
Expression* left = binop->left(); |
Expression* right = binop->right(); |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
Register temporary = temporary_register_scope.NewRegister(); |
Visit(left); |
@@ -868,9 +954,6 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
return info()->feedback_vector()->GetIndex(slot); |
} |
- |
-Register BytecodeGenerator::current_context() const { return current_context_; } |
- |
} // namespace interpreter |
} // namespace internal |
} // namespace v8 |