Commit 67b68b81 by Ian Lance Taylor

compiler: Propagate escape info from closures to enclosed variables.

If a closure escapes, the enclosed variables must escape via the
closure.  Reachability analysis had a bug where the enclosed
variables were not considered as reachable from the closure.

From-SVN: r222597
parent b693b879
...@@ -1276,8 +1276,22 @@ Gogo::analyze_reachability() ...@@ -1276,8 +1276,22 @@ Gogo::analyze_reachability()
Node* m = worklist.front(); Node* m = worklist.front();
worklist.pop_front(); worklist.pop_front();
for (std::set<Node*>::iterator n = m->edges().begin(); std::set<Node*> reachable = m->edges();
n != m->edges().end(); if (m->object()->is_function()
&& m->object()->func_value()->needs_closure())
{
// If a closure escapes everything it closes over also escapes.
Function* closure = m->object()->func_value();
for (size_t i = 0; i < closure->closure_field_count(); i++)
{
Named_object* enclosed = closure->enclosing_var(i);
Node* enclosed_node = this->lookup_connection_node(enclosed);
go_assert(enclosed_node != NULL);
reachable.insert(enclosed_node);
}
}
for (std::set<Node*>::iterator n = reachable.begin();
n != reachable.end();
++n) ++n)
{ {
// If an object can be reached from a node with ESCAPE_GLOBAL, // If an object can be reached from a node with ESCAPE_GLOBAL,
...@@ -1296,7 +1310,7 @@ Gogo::analyze_reachability() ...@@ -1296,7 +1310,7 @@ Gogo::analyze_reachability()
p != this->named_connection_nodes_.end(); p != this->named_connection_nodes_.end();
++p) ++p)
{ {
if (p->second->connection_node()->escape_state() == Node::ESCAPE_ARG) if (p->second->connection_node()->escape_state() < Node::ESCAPE_NONE)
worklist.push_back(p->second); worklist.push_back(p->second);
} }
...@@ -1305,15 +1319,30 @@ Gogo::analyze_reachability() ...@@ -1305,15 +1319,30 @@ Gogo::analyze_reachability()
Node* m = worklist.front(); Node* m = worklist.front();
worklist.pop_front(); worklist.pop_front();
for (std::set<Node*>::iterator n = m->edges().begin(); std::set<Node*> reachable = m->edges();
n != m->edges().end(); if (m->object()->is_function()
&& m->object()->func_value()->needs_closure())
{
// If a closure escapes everything it closes over also escapes.
Function* closure = m->object()->func_value();
for (size_t i = 0; i < closure->closure_field_count(); i++)
{
Named_object* enclosed = closure->enclosing_var(i);
Node* enclosed_node = this->lookup_connection_node(enclosed);
go_assert(enclosed_node != NULL);
reachable.insert(enclosed_node);
}
}
for (std::set<Node*>::iterator n = reachable.begin();
n != reachable.end();
++n) ++n)
{ {
// If an object can be reached from a node with ESCAPE_ARG, // If an object can be reached from a node with ESCAPE_ARG,
// it is ESCAPE_ARG or ESCAPE_GLOBAL. // it is ESCAPE_ARG or ESCAPE_GLOBAL.
if ((*n)->connection_node()->escape_state() > Node::ESCAPE_ARG) Node::Escapement_lattice e = m->connection_node()->escape_state();
if ((*n)->connection_node()->escape_state() > e)
{ {
(*n)->connection_node()->set_escape_state(Node::ESCAPE_ARG); (*n)->connection_node()->set_escape_state(e);
worklist.push_back(*n); worklist.push_back(*n);
} }
} }
......
...@@ -1042,6 +1042,11 @@ class Function ...@@ -1042,6 +1042,11 @@ class Function
this->is_unnamed_type_stub_method_ = true; this->is_unnamed_type_stub_method_ = true;
} }
// Return the amount of enclosed variables in this closure.
size_t
closure_field_count() const
{ return this->closure_fields_.size(); }
// Add a new field to the closure variable. // Add a new field to the closure variable.
void void
add_closure_field(Named_object* var, Location loc) add_closure_field(Named_object* var, Location loc)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment