Index: runtime/vm/flow_graph_builder.cc |
=================================================================== |
--- runtime/vm/flow_graph_builder.cc (revision 41422) |
+++ runtime/vm/flow_graph_builder.cc (working copy) |
@@ -1098,10 +1098,7 @@ |
intptr_t current_context_level = owner()->context_level(); |
ASSERT(current_context_level >= 0); |
- if (owner()->parsed_function()->saved_entry_context_var() != NULL) { |
- // CTX on entry was saved, but not linked as context parent. |
- BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var()); |
- } else { |
+ if (HasContextScope()) { |
UnchainContexts(current_context_level); |
} |
@@ -3653,9 +3650,10 @@ |
} |
-bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { |
- return (node == owner()->parsed_function()->node_sequence()) && |
- (owner()->parsed_function()->saved_entry_context_var() != NULL); |
+bool EffectGraphVisitor::HasContextScope() const { |
+ const ContextScope& context_scope = ContextScope::Handle( |
+ owner()->parsed_function()->function().context_scope()); |
+ return !context_scope.IsNull() && (context_scope.num_variables() > 0); |
} |
@@ -3682,46 +3680,35 @@ |
LocalScope* scope = node->scope(); |
const intptr_t num_context_variables = |
(scope != NULL) ? scope->num_context_variables() : 0; |
+ const bool is_top_level_sequence = |
+ node == owner()->parsed_function()->node_sequence(); |
// The outermost function sequence cannot contain a label. |
- ASSERT((node->label() == NULL) || |
- (node != owner()->parsed_function()->node_sequence())); |
+ ASSERT((node->label() == NULL) || !is_top_level_sequence); |
NestedBlock nested_block(owner(), node); |
if (num_context_variables > 0) { |
- // The loop local scope declares variables that are captured. |
- // Allocate and chain a new context. |
- // Allocate context computation (uses current context) |
+ // The local scope declares variables that are captured. |
+ // Allocate and chain a new context (Except don't chain when at the function |
+ // entry if the function does not capture any variables from outer scopes). |
Value* allocated_context = |
Bind(new(I) AllocateContextInstr(node->token_pos(), |
num_context_variables)); |
{ LocalVariable* tmp_var = EnterTempLocalScope(allocated_context); |
- // If this node_sequence is the body of the function being compiled, and |
- // if this function allocates context variables, but none of its enclosing |
- // functions do, the context on entry is not linked as parent of the |
- // allocated context but saved on entry and restored on exit as to prevent |
- // memory leaks. |
- // In this case, the parser pre-allocates a variable to save the context. |
- Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var)); |
- Value* parent_context = NULL; |
- if (MustSaveRestoreContext(node)) { |
- BuildSaveContext( |
- *owner()->parsed_function()->saved_entry_context_var()); |
- parent_context = Bind( |
- new(I) ConstantInstr(Object::ZoneHandle(I, Object::null()))); |
- } else { |
- parent_context = Bind(BuildCurrentContext()); |
+ if (HasContextScope() || !is_top_level_sequence) { |
+ Value* tmp_val = Bind(new(I) LoadLocalInstr(*tmp_var)); |
+ Value* parent_context = Bind(BuildCurrentContext()); |
+ Do(new(I) StoreInstanceFieldInstr(Context::parent_offset(), |
+ tmp_val, |
+ parent_context, |
+ kEmitStoreBarrier, |
+ Scanner::kNoSourcePos)); |
} |
- Do(new(I) StoreInstanceFieldInstr(Context::parent_offset(), |
- tmp_val, |
- parent_context, |
- kEmitStoreBarrier, |
- Scanner::kNoSourcePos)); |
Do(BuildStoreContext(Bind(ExitTempLocalScope(tmp_var)))); |
} |
// If this node_sequence is the body of the function being compiled, copy |
// the captured parameters from the frame into the context. |
- if (node == owner()->parsed_function()->node_sequence()) { |
+ if (is_top_level_sequence) { |
ASSERT(scope->context_level() == 1); |
const Function& function = owner()->parsed_function()->function(); |
const int num_params = function.NumParameters(); |
@@ -3757,22 +3744,12 @@ |
} |
} |
} |
- } else if (MustSaveRestoreContext(node)) { |
- // Even when the current scope has no context variables, we may |
- // still need to save the current context if, for example, there |
- // are loop scopes below this which will allocate a context |
- // object. |
- BuildSaveContext( |
- *owner()->parsed_function()->saved_entry_context_var()); |
- Do(BuildStoreContext(Bind(new(I) ConstantInstr(Object::ZoneHandle( |
- I, I->object_store()->empty_context()))))); |
} |
// This check may be deleted if the generated code is leaf. |
// Native functions don't need a stack check at entry. |
const Function& function = owner()->parsed_function()->function(); |
- if ((node == owner()->parsed_function()->node_sequence()) && |
- !function.is_native()) { |
+ if (is_top_level_sequence && !function.is_native()) { |
// Always allocate CheckOverflowInstr so that deopt-ids match regardless |
// if we inline or not. |
if (!function.IsImplicitGetterFunction() && |
@@ -3787,8 +3764,7 @@ |
} |
} |
- if (FLAG_enable_type_checks && |
- (node == owner()->parsed_function()->node_sequence())) { |
+ if (FLAG_enable_type_checks && is_top_level_sequence) { |
const Function& function = owner()->parsed_function()->function(); |
const int num_params = function.NumParameters(); |
int pos = 0; |
@@ -3827,7 +3803,7 @@ |
// If this node sequence is the body of an async closure leave room for a |
// preamble. The preamble is generated after visiting the body. |
GotoInstr* preamble_start = NULL; |
- if ((node == owner()->parsed_function()->node_sequence()) && |
+ if (is_top_level_sequence && |
(owner()->parsed_function()->function().is_async_closure())) { |
JoinEntryInstr* preamble_end = new(I) JoinEntryInstr( |
owner()->AllocateBlockId(), owner()->try_index()); |
@@ -3853,7 +3829,7 @@ |
// Continuation part: |
// After generating the CFG for the body we can create the preamble because we |
// know exactly how many continuation states we need. |
- if ((node == owner()->parsed_function()->node_sequence()) && |
+ if (is_top_level_sequence && |
(owner()->parsed_function()->function().is_async_closure())) { |
ASSERT(preamble_start != NULL); |
// We are at the top level. Fetch the corresponding scope. |
@@ -3914,13 +3890,10 @@ |
exit_ = saved_exit; |
} |
- if (is_open()) { |
- if (MustSaveRestoreContext(node)) { |
- BuildRestoreContext( |
- *owner()->parsed_function()->saved_entry_context_var()); |
- } else if (num_context_variables > 0) { |
- UnchainContexts(1); |
- } |
+ if (is_open() && |
+ (num_context_variables > 0) && |
+ (HasContextScope() || !is_top_level_sequence)) { |
+ UnchainContexts(1); |
} |
// If this node sequence is labeled, a break out of the sequence will have |