Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index b7ff5d3f310c81f8fc370e5355f23ee06a856994..7ce8a8be2305f9596a15fc24c30555f922b096f4 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -167,21 +167,29 @@ void ParsedFunction::AllocateVariables() { |
// Allocate parameters and local variables, either in the local frame or |
// in the context(s). |
LocalScope* context_owner = NULL; // No context needed yet. |
+ bool found_captured_variables = false; |
int next_free_frame_index = |
scope->AllocateVariables(first_parameter_index_, |
num_params, |
first_stack_local_index_, |
scope, |
- &context_owner); |
- |
- // 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. |
- // Add and allocate a local variable to this purpose. |
- if (context_owner != NULL) { |
+ &context_owner, |
+ &found_captured_variables); |
+ |
+ // We save the entry context for a function when... |
+ // |
+ // - some variable in the function is captured by nested functions, and |
+ // - the function does not capture any variables from parent functions. |
+ // |
+ // We used to link to the parent context in these cases, but this |
+ // had the effect of unintentionally retaining parent contexts which |
+ // would never be accessed. By breaking the context chain at this |
+ // point, we allow these outer contexts to be collected. |
+ if (found_captured_variables) { |
const ContextScope& context_scope = |
ContextScope::Handle(function().context_scope()); |
if (context_scope.IsNull() || (context_scope.num_variables() == 0)) { |
+ // Allocate a local variable for saving the entry context. |
LocalVariable* context_var = |
new LocalVariable(function().token_pos(), |
Symbols::SavedEntryContextVar(), |