Commit 787732cd by Ian Lance Taylor

compiler: improve escape analysis

    
    This CL ports recent enhancements of the escape analysis in the
    gc compiler to gofrontend.
    
    - CL 99335: unnamed receiver should not escape.
    
    - CL 105257: propagate loop depth to field. This prevents it
      from escaping when a field's address is taken inside a loop
      (but not otherwise escape).
    
    - CL 107597: use element type for "indirection" of slice/string.
      This prevents the slice/string from escaping when only the
      element, in case that it is pointerless, flows to outer scope.
    
    Reviewed-on: https://go-review.googlesource.com/120760

From-SVN: r262120
parent 4fdb6fb6
7008302f1f0eaa9508b2857185505d4dc7baac1e baaaf1e0f1e9a54ea2dfe475154c85c83ec03740
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -43,6 +43,12 @@ Node::type() const ...@@ -43,6 +43,12 @@ Node::type() const
// which may also be pointer. We model it as another void*, so // which may also be pointer. We model it as another void*, so
// we don't lose pointer-ness. // we don't lose pointer-ness.
return this->child()->type(); return this->child()->type();
else if (this->child()->type()->is_slice_type())
// We model "indirect" of a slice as dereferencing its pointer
// field (to get element). Use element type here.
return this->child()->type()->array_type()->element_type();
else if (this->child()->type()->is_string_type())
return Type::lookup_integer_type("uint8");
else else
return this->child()->type()->deref(); return this->child()->type()->deref();
} }
...@@ -1811,60 +1817,77 @@ Escape_analysis_assign::expression(Expression** pexpr) ...@@ -1811,60 +1817,77 @@ Escape_analysis_assign::expression(Expression** pexpr)
case Expression::EXPRESSION_UNARY: case Expression::EXPRESSION_UNARY:
{ {
if ((*pexpr)->unary_expression()->op() != OPERATOR_AND) Expression* operand = (*pexpr)->unary_expression()->operand();
break;
Node* addr_node = Node::make_node(*pexpr); if ((*pexpr)->unary_expression()->op() == OPERATOR_AND)
this->context_->track(addr_node); {
this->context_->track(n);
Expression* operand = (*pexpr)->unary_expression()->operand();
Named_object* var = NULL; Named_object* var = NULL;
if (operand->var_expression() != NULL) if (operand->var_expression() != NULL)
var = operand->var_expression()->named_object(); var = operand->var_expression()->named_object();
else if (operand->enclosed_var_expression() != NULL) else if (operand->enclosed_var_expression() != NULL)
var = operand->enclosed_var_expression()->variable(); var = operand->enclosed_var_expression()->variable();
if (var == NULL) if (var != NULL
&& ((var->is_variable() && var->var_value()->is_parameter())
|| var->is_result_variable()))
{
Node::Escape_state* addr_state = n->state(this->context_, NULL);
addr_state->loop_depth = 1;
break; break;
}
}
if (var->is_variable() if ((*pexpr)->unary_expression()->op() != OPERATOR_AND
&& !var->var_value()->is_parameter()) && (*pexpr)->unary_expression()->op() != OPERATOR_MULT)
{ break;
// For &x, use the loop depth of x if known.
Node::Escape_state* addr_state = // For &x and *x, use the loop depth of x if known.
addr_node->state(this->context_, NULL); Node::Escape_state* expr_state = n->state(this->context_, NULL);
Node* operand_node = Node::make_node(operand); Node* operand_node = Node::make_node(operand);
Node::Escape_state* operand_state = Node::Escape_state* operand_state = operand_node->state(this->context_, NULL);
operand_node->state(this->context_, NULL);
if (operand_state->loop_depth != 0) if (operand_state->loop_depth != 0)
addr_state->loop_depth = operand_state->loop_depth; expr_state->loop_depth = operand_state->loop_depth;
}
else if ((var->is_variable()
&& var->var_value()->is_parameter())
|| var->is_result_variable())
{
Node::Escape_state* addr_state =
addr_node->state(this->context_, NULL);
addr_state->loop_depth = 1;
}
} }
break; break;
case Expression::EXPRESSION_ARRAY_INDEX: case Expression::EXPRESSION_ARRAY_INDEX:
{ {
Array_index_expression* aie = (*pexpr)->array_index_expression(); Array_index_expression* aie = (*pexpr)->array_index_expression();
// Propagate the loopdepth to element.
Node* array_node = Node::make_node(aie->array());
Node::Escape_state* elem_state = n->state(this->context_, NULL);
Node::Escape_state* array_state = array_node->state(this->context_, NULL);
elem_state->loop_depth = array_state->loop_depth;
if (aie->end() != NULL && !aie->array()->type()->is_slice_type()) if (aie->end() != NULL && !aie->array()->type()->is_slice_type())
{ {
// Slicing an array. // Slicing an array. This effectively takes the address of the array.
Expression* addr = Expression::make_unary(OPERATOR_AND, aie->array(), Expression* addr = Expression::make_unary(OPERATOR_AND, aie->array(),
aie->location()); aie->location());
Node* addr_node = Node::make_node(addr); Node* addr_node = Node::make_node(addr);
n->set_child(addr_node); n->set_child(addr_node);
this->context_->track(addr_node); this->context_->track(addr_node);
Node::Escape_state* addr_state = addr_node->state(this->context_, NULL);
addr_state->loop_depth = array_state->loop_depth;
} }
} }
break; break;
case Expression::EXPRESSION_FIELD_REFERENCE:
{
// Propagate the loopdepth to field.
Node* struct_node =
Node::make_node((*pexpr)->field_reference_expression()->expr());
Node::Escape_state* field_state = n->state(this->context_, NULL);
Node::Escape_state* struct_state = struct_node->state(this->context_, NULL);
field_state->loop_depth = struct_state->loop_depth;
}
break;
default: default:
break; break;
} }
...@@ -3288,9 +3311,13 @@ Escape_analysis_tag::tag(Named_object* fn) ...@@ -3288,9 +3311,13 @@ Escape_analysis_tag::tag(Named_object* fn)
Function_type* fntype = fn->func_value()->type(); Function_type* fntype = fn->func_value()->type();
Bindings* bindings = fn->func_value()->block()->bindings(); Bindings* bindings = fn->func_value()->block()->bindings();
if (fntype->is_method() if (fntype->is_method())
&& !fntype->receiver()->name().empty() {
&& !Gogo::is_sink_name(fntype->receiver()->name())) if (fntype->receiver()->name().empty()
|| Gogo::is_sink_name(fntype->receiver()->name()))
// Unnamed receiver is not used in the function body, does not escape.
fntype->add_receiver_note(Node::ESCAPE_NONE);
else
{ {
Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name()); Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name());
go_assert(rcvr_no != NULL); go_assert(rcvr_no != NULL);
...@@ -3311,6 +3338,7 @@ Escape_analysis_tag::tag(Named_object* fn) ...@@ -3311,6 +3338,7 @@ Escape_analysis_tag::tag(Named_object* fn)
break; break;
} }
} }
}
int i = 0; int i = 0;
if (fntype->parameters() != NULL) if (fntype->parameters() != NULL)
......
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