From 1b87f01239de499654b390a41a7f8e2b453789dc Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 19 Jan 2015 23:46:22 +0300 Subject: [PATCH] cmd/gc: improve escape analysis for &T{...} Currently all PTRLIT element initializers escape. There is no reason for that. This change links STRUCTLIT to PTRLIT; STRUCTLIT element initializers are already linked to the STRUCTLIT. As the result, PTRLIT element initializers escape when PTRLIT itself escapes. Change-Id: I89ecd8677cbf81addcfd469cd2fd461c0e9bf7dd Reviewed-on: https://go-review.googlesource.com/3031 Reviewed-by: Russ Cox --- src/cmd/gc/esc.c | 9 +++++---- test/escape2.go | 27 +++++++++++++++++++++++++++ test/escape2n.go | 27 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index 7c7095c8209..2fdbd998702 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -615,15 +615,15 @@ esc(EscState *e, Node *n, Node *up) for(ll=n->list; ll; ll=ll->next) escassign(e, n, ll->n->right); break; - + case OPTRLIT: n->esc = EscNone; // until proven otherwise e->noesc = list(e->noesc, n); n->escloopdepth = e->loopdepth; - // Contents make it to memory, lose track. - escassign(e, &e->theSink, n->left); + // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. + escassign(e, n, n->left); break; - + case OCALLPART: n->esc = EscNone; // until proven otherwise e->noesc = list(e->noesc, n); @@ -730,6 +730,7 @@ escassign(EscState *e, Node *dst, Node *src) case OCONVNOP: case OMAPLIT: case OSTRUCTLIT: + case OPTRLIT: case OCALLPART: break; diff --git a/test/escape2.go b/test/escape2.go index 6a46ce86abd..357ce4a8a85 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1492,3 +1492,30 @@ func g() (x interface{}) { // ERROR "moved to heap: x" x = &x // ERROR "&x escapes to heap" return } + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i" + x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap" + sink = *x +} + +func ptrlitEscape() { + // Both literal and element escape. + i := 0 // ERROR "moved to heap: i" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap" + sink = x +} diff --git a/test/escape2n.go b/test/escape2n.go index 002a78ea50d..3e9bb709c9a 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -1492,3 +1492,30 @@ func g() (x interface{}) { // ERROR "moved to heap: x" x = &x // ERROR "&x escapes to heap" return } + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i does not escape" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i" + x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap" + sink = *x +} + +func ptrlitEscape() { + // Both literal and element escape. + i := 0 // ERROR "moved to heap: i" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap" + sink = x +}