This patch to the Go frontend by Cherry Zhang enables escape analysis
for the runtime package in the Go frontend. The runtime package was
hard-coded non-escape, and the escape analysis was not run for the
runtime package. This patch removes the hard-code, and lets the
escape analysis decide. It is not allowed for local variables and
closures in the runtime to be heap allocated. This patch adds the
check that make sure that they indeed do not escape.
The escape analysis is always run when compiling the runtime now.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed
to mainline.
I'm almost done. I promise.
Ian
Index: gcc/go/gofrontend/MERGE
===
--- gcc/go/gofrontend/MERGE (revision 256810)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-3ea7fc3b918210e7248dbc51d90af20639dc4167
+1072286ca9249bd6f75628aead325a66286bcf5b
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
Index: gcc/go/gofrontend/escape.cc
===
--- gcc/go/gofrontend/escape.cc (revision 256707)
+++ gcc/go/gofrontend/escape.cc (working copy)
@@ -873,13 +873,12 @@ escape_hash_match(std::string suffix, st
void
Gogo::analyze_escape()
{
- if (!optimize_allocation_flag.is_enabled() || saw_errors())
+ if (saw_errors())
return;
- // Currently runtime is hard-coded to non-escape in various places.
- // Don't run escape analysis for runtime.
- // TODO: remove this once it works for runtime.
- if (this->compiling_runtime() && this->package_name() == "runtime")
+ if (!optimize_allocation_flag.is_enabled()
+ && !this->compiling_runtime())
+// We always run escape analysis when compiling runtime.
return;
// Discover strongly connected groups of functions to analyze for escape
@@ -1473,6 +1472,35 @@ Escape_analysis_assign::statement(Block*
return TRAVERSE_SKIP_COMPONENTS;
}
+// Helper function to emit moved-to-heap diagnostics.
+
+static void
+move_to_heap(Gogo* gogo, Expression *expr)
+{
+ Named_object* no;
+ if (expr->var_expression() != NULL)
+no = expr->var_expression()->named_object();
+ else if (expr->enclosed_var_expression() != NULL)
+no = expr->enclosed_var_expression()->variable();
+ else
+return;
+
+ if ((no->is_variable()
+ && !no->var_value()->is_global())
+ || no->is_result_variable())
+{
+ Node* n = Node::make_node(expr);
+ if (gogo->debug_escape_level() != 0)
+go_inform(n->definition_location(),
+ "moved to heap: %s",
+ n->ast_format(gogo).c_str());
+ if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
+go_error_at(expr->location(),
+"%s escapes to heap, not allowed in runtime",
+n->ast_format(gogo).c_str());
+}
+}
+
// Model expressions within a function as assignments and flows between nodes.
int
@@ -1489,13 +1517,7 @@ Escape_analysis_assign::expression(Expre
if (debug_level > 1)
go_inform((*pexpr)->location(), "%s too large for stack",
n->ast_format(gogo).c_str());
- if (debug_level != 0
- && ((*pexpr)->var_expression() != NULL
- || (*pexpr)->enclosed_var_expression() != NULL))
-go_inform(n->definition_location(),
- "moved to heap: %s",
- n->ast_format(gogo).c_str());
-
+ move_to_heap(gogo, *pexpr);
n->set_encoding(Node::ESCAPE_HEAP);
(*pexpr)->address_taken(true);
this->assign(this->context_->sink(), n);
@@ -2968,25 +2990,20 @@ Escape_analysis_flood::flood(Level level
if (src_leaks)
{
src->set_encoding(Node::ESCAPE_HEAP);
- if (debug_level != 0 && osrcesc != src->encoding())
- {
- if (underlying->var_expression() != NULL
- || underlying->enclosed_var_expression() != NULL)
-go_inform(underlying_node->definition_location(),
- "moved to heap: %s",
- underlying_node->ast_format(gogo).c_str());
-
- if (debug_level > 1)
- go_inform(src->location(),
- "%s escapes to heap, level={%d %d}, "
- "dst.eld=%d, src.eld=%d",
- src->ast_format(gogo).c_str(), level.value(),
- level.suffix_value(), dst_state->loop_depth,
- mod_loop_depth);
- else
- go_inform(src->location(), "%s escapes to heap",
- src->ast_format(gogo).c_str());
- }
+ if (osrcesc != src->encoding())
+{
+ move_to_heap(gogo, underlying);
+ if (debug_lev