aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-04-29 22:14:34 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-04-29 22:14:34 +0000
commit67b68b8139ca4e45c8948642cd6678159ae51311 (patch)
treee036dccc29cdf8c02ddd02633a88a8f847c150d4 /gcc
parentb693b8792e23b2d9839db05cbd725fbb92789df6 (diff)
downloadgcc-67b68b8139ca4e45c8948642cd6678159ae51311.zip
gcc-67b68b8139ca4e45c8948642cd6678159ae51311.tar.gz
gcc-67b68b8139ca4e45c8948642cd6678159ae51311.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/escape.cc43
-rw-r--r--gcc/go/gofrontend/gogo.h5
2 files changed, 41 insertions, 7 deletions
diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc
index 7c8955b..d2e7ae1 100644
--- a/gcc/go/gofrontend/escape.cc
+++ b/gcc/go/gofrontend/escape.cc
@@ -1276,8 +1276,22 @@ Gogo::analyze_reachability()
Node* m = worklist.front();
worklist.pop_front();
- for (std::set<Node*>::iterator n = m->edges().begin();
- n != m->edges().end();
+ std::set<Node*> reachable = m->edges();
+ 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)
{
// If an object can be reached from a node with ESCAPE_GLOBAL,
@@ -1296,7 +1310,7 @@ Gogo::analyze_reachability()
p != this->named_connection_nodes_.end();
++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);
}
@@ -1305,15 +1319,30 @@ Gogo::analyze_reachability()
Node* m = worklist.front();
worklist.pop_front();
- for (std::set<Node*>::iterator n = m->edges().begin();
- n != m->edges().end();
+ std::set<Node*> reachable = m->edges();
+ 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)
{
// If an object can be reached from a node with ESCAPE_ARG,
// 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);
}
}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index e30178d..ffc2440 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -1042,6 +1042,11 @@ class Function
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.
void
add_closure_field(Named_object* var, Location loc)