Index: src/compiler/ast-graph-builder.cc |
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
index 9791f6f1a1b4b6920c04d3c0664d5664a67bc156..89c8339c2a12b1ee3e48538ca7202018c26ee5ff 100644 |
--- a/src/compiler/ast-graph-builder.cc |
+++ b/src/compiler/ast-graph-builder.cc |
@@ -109,24 +109,25 @@ class AstGraphBuilder::ContextScope BASE_EMBEDDED { |
: builder_(builder), |
outer_(builder->execution_context()), |
scope_(scope), |
- context_(context) { |
- builder_->set_execution_context(this); // Push. |
+ depth_(builder_->environment()->ContextStackDepth()) { |
+ builder_->environment()->PushContext(context); // Push. |
+ builder_->set_execution_context(this); |
} |
~ContextScope() { |
builder_->set_execution_context(outer_); // Pop. |
+ builder_->environment()->PopContext(); |
+ CHECK_EQ(depth_, builder_->environment()->ContextStackDepth()); |
} |
// Current scope during visitation. |
Scope* scope() const { return scope_; } |
- // Current context node during visitation. |
- Node* context() const { return context_; } |
private: |
AstGraphBuilder* builder_; |
ContextScope* outer_; |
Scope* scope_; |
- Node* context_; |
+ int depth_; |
}; |
@@ -378,6 +379,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, |
globals_(0, local_zone), |
execution_control_(nullptr), |
execution_context_(nullptr), |
+ function_context_(nullptr), |
input_buffer_size_(0), |
input_buffer_(nullptr), |
exit_control_(nullptr), |
@@ -398,13 +400,23 @@ Node* AstGraphBuilder::GetFunctionClosure() { |
Node* AstGraphBuilder::GetFunctionContext() { |
- if (!function_context_.is_set()) { |
- // Parameter (arity + 1) is special for the outer context of the function |
- const Operator* op = common()->Parameter(info()->num_parameters() + 1); |
- Node* node = NewNode(op, graph()->start()); |
- function_context_.set(node); |
- } |
- return function_context_.get(); |
+ DCHECK(function_context_ != nullptr); |
+ return function_context_; |
+} |
+ |
+ |
+Node* AstGraphBuilder::NewOuterContextParam() { |
+ // Parameter (arity + 1) is special for the outer context of the function |
+ const Operator* op = common()->Parameter(info()->num_parameters() + 1); |
+ return NewNode(op, graph()->start()); |
+} |
+ |
+ |
+Node* AstGraphBuilder::NewCurrentContextOsrValue() { |
+ // TODO(titzer): use a real OSR value here; a parameter works by accident. |
+ // Parameter (arity + 1) is special for the outer context of the function |
+ const Operator* op = common()->Parameter(info()->num_parameters() + 1); |
+ return NewNode(op, graph()->start()); |
} |
@@ -430,8 +442,8 @@ bool AstGraphBuilder::CreateGraph() { |
} |
// Initialize the incoming context. |
- Node* incoming_context = GetFunctionContext(); |
- ContextScope incoming(this, scope, incoming_context); |
+ function_context_ = NewOuterContextParam(); |
+ ContextScope incoming(this, scope, function_context_); |
// Build receiver check for sloppy mode if necessary. |
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC? |
@@ -439,13 +451,31 @@ bool AstGraphBuilder::CreateGraph() { |
Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver); |
env.Bind(scope->receiver(), patched_receiver); |
- // Build node to initialize local function context. |
- Node* closure = GetFunctionClosure(); |
- Node* inner_context = BuildLocalFunctionContext(incoming_context, closure); |
+ bool ok; |
+ int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
+ if (heap_slots > 0) { |
+ // Push a new inner context scope for the function. |
+ Node* closure = GetFunctionClosure(); |
+ Node* inner_context = BuildLocalFunctionContext(function_context_, closure); |
+ ContextScope top_context(this, scope, inner_context); |
+ ok = CreateGraphBody(); |
+ } else { |
+ // Simply use the outer function context in building the graph. |
+ ok = CreateGraphBody(); |
+ } |
+ |
+ // Finish the basic structure of the graph. |
+ if (ok) { |
+ environment()->UpdateControlDependency(exit_control()); |
+ graph()->SetEnd(NewNode(common()->End())); |
+ } |
+ |
+ return ok; |
+} |
- // Push top-level function context for the function body. |
- ContextScope top_context(this, scope, inner_context); |
+bool AstGraphBuilder::CreateGraphBody() { |
+ Scope* scope = info()->scope(); |
// Build the arguments object if it is used. |
BuildArgumentsObject(scope->arguments()); |
@@ -485,10 +515,6 @@ bool AstGraphBuilder::CreateGraph() { |
// Return 'undefined' in case we can fall off the end. |
BuildReturn(jsgraph()->UndefinedConstant()); |
- // Finish the basic structure of the graph. |
- environment()->UpdateControlDependency(exit_control()); |
- graph()->SetEnd(NewNode(common()->End())); |
- |
return true; |
} |
@@ -516,6 +542,7 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, |
parameters_count_(scope->num_parameters() + 1), |
locals_count_(scope->num_stack_slots()), |
values_(builder_->local_zone()), |
+ contexts_(builder_->local_zone()), |
control_dependency_(control_dependency), |
effect_dependency_(control_dependency), |
parameters_node_(nullptr), |
@@ -548,6 +575,7 @@ AstGraphBuilder::Environment::Environment( |
parameters_count_(copy->parameters_count_), |
locals_count_(copy->locals_count_), |
values_(copy->zone()), |
+ contexts_(copy->zone()), |
control_dependency_(copy->control_dependency_), |
effect_dependency_(copy->effect_dependency_), |
parameters_node_(copy->parameters_node_), |
@@ -556,6 +584,9 @@ AstGraphBuilder::Environment::Environment( |
const size_t kStackEstimate = 7; // optimum from experimentation! |
values_.reserve(copy->values_.size() + kStackEstimate); |
values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); |
+ contexts_.reserve(copy->contexts_.size()); |
+ contexts_.insert(contexts_.begin(), copy->contexts_.begin(), |
+ copy->contexts_.end()); |
} |
@@ -660,7 +691,7 @@ Scope* AstGraphBuilder::current_scope() const { |
Node* AstGraphBuilder::current_context() const { |
- return execution_context_->context(); |
+ return environment()->Context(); |
} |
@@ -1203,11 +1234,12 @@ void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
const Operator* op = javascript()->CreateCatchContext(name); |
Node* context = NewNode(op, exception, GetFunctionClosure()); |
PrepareFrameState(context, BailoutId::None()); |
- ContextScope scope(this, stmt->scope(), context); |
- DCHECK(stmt->scope()->declarations()->is_empty()); |
- |
- // Evaluate the catch-block. |
- Visit(stmt->catch_block()); |
+ { |
+ ContextScope scope(this, stmt->scope(), context); |
+ DCHECK(stmt->scope()->declarations()->is_empty()); |
+ // Evaluate the catch-block. |
+ Visit(stmt->catch_block()); |
+ } |
try_control.EndCatch(); |
// TODO(mstarzinger): Remove bailout once everything works. |
@@ -2416,9 +2448,6 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) { |
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) { |
- int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
- if (heap_slots <= 0) return context; |
- |
// Allocate a new local context. |
const Operator* op = javascript()->CreateFunctionContext(); |
Node* local_context = NewNode(op, closure); |
@@ -3003,6 +3032,7 @@ void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) { |
void AstGraphBuilder::Environment::Merge(Environment* other) { |
DCHECK(values_.size() == other->values_.size()); |
+ DCHECK(contexts_.size() <= other->contexts_.size()); |
// Nothing to do if the other environment is dead. |
if (other->IsMarkedAsUnreachable()) return; |
@@ -3036,6 +3066,10 @@ void AstGraphBuilder::Environment::Merge(Environment* other) { |
for (int i = 0; i < static_cast<int>(values_.size()); ++i) { |
values_[i] = builder_->MergeValue(values_[i], other->values_[i], control); |
} |
+ for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) { |
+ contexts_[i] = |
+ builder_->MergeValue(contexts_[i], other->contexts_[i], control); |
+ } |
} |
@@ -3047,8 +3081,7 @@ void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned, |
if (assigned == nullptr) { |
// Assume that everything is updated in the loop. |
for (int i = 0; i < size; ++i) { |
- Node* phi = builder_->NewPhi(1, values()->at(i), control); |
- values()->at(i) = phi; |
+ values()->at(i) = builder_->NewPhi(1, values()->at(i), control); |
} |
} else { |
// Only build phis for those locals assigned in this loop. |
@@ -3061,6 +3094,16 @@ void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned, |
Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control); |
UpdateEffectDependency(effect); |
+ if (builder_->info()->is_osr()) { |
+ // Introduce phis for all context values in the case of an OSR graph. |
+ for (int i = 0; i < static_cast<int>(contexts()->size()); ++i) { |
+ Node* val = contexts()->at(i); |
+ if (!IrOpcode::IsConstantOpcode(val->opcode())) { |
+ contexts()->at(i) = builder_->NewPhi(1, val, control); |
+ } |
+ } |
+ } |
+ |
if (is_osr) { |
// Merge OSR values as inputs to the phis of the loop. |
Graph* graph = builder_->graph(); |
@@ -3078,6 +3121,25 @@ void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned, |
values()->at(i) = builder_->MergeValue(val, osr_value, control); |
} |
} |
+ |
+ // Rename all the contexts in the environment. |
+ // The innermost context is the OSR value, and the outer contexts are |
+ // reconstructed by dynamically walking up the context chain. |
+ Node* osr_context = nullptr; |
+ const Operator* op = |
+ builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true); |
+ int last = static_cast<int>(contexts()->size() - 1); |
+ for (int i = last; i >= 0; i--) { |
+ Node* val = contexts()->at(i); |
+ if (!IrOpcode::IsConstantOpcode(val->opcode())) { |
+ osr_context = (i == last) ? builder_->NewCurrentContextOsrValue() |
+ : graph->NewNode(op, osr_context, osr_context, |
+ osr_loop_entry); |
+ contexts()->at(i) = builder_->MergeValue(val, osr_context, control); |
+ } else { |
+ osr_context = val; |
+ } |
+ } |
} |
} |