diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-04-29 22:14:34 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-04-29 22:14:34 +0000 |
commit | 67b68b8139ca4e45c8948642cd6678159ae51311 (patch) | |
tree | e036dccc29cdf8c02ddd02633a88a8f847c150d4 /gcc | |
parent | b693b8792e23b2d9839db05cbd725fbb92789df6 (diff) | |
download | gcc-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.cc | 43 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 5 |
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) |