1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:44:39 -07:00

gc: fix escape analysis + inlining + closure bug

R=ken2
CC=golang-dev, lvd
https://golang.org/cl/5693056
This commit is contained in:
Russ Cox 2012-02-23 23:09:53 -05:00
parent d45ee4cb5f
commit 075eef4018
5 changed files with 49 additions and 12 deletions

View File

@ -59,7 +59,7 @@ static int dstcount, edgecount; // diagnostic
static NodeList* noesc; // list of possible non-escaping nodes, for printing static NodeList* noesc; // list of possible non-escaping nodes, for printing
void void
escapes(void) escapes(NodeList *all)
{ {
NodeList *l; NodeList *l;
@ -70,9 +70,10 @@ escapes(void)
theSink.escloopdepth = -1; theSink.escloopdepth = -1;
safetag = strlit("noescape"); safetag = strlit("noescape");
noesc = nil;
// flow-analyze top level functions // flow-analyze functions
for(l=xtop; l; l=l->next) for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE)
escfunc(l->n); escfunc(l->n);
@ -84,7 +85,7 @@ escapes(void)
escflood(l->n); escflood(l->n);
// for all top level functions, tag the typenodes corresponding to the param nodes // for all top level functions, tag the typenodes corresponding to the param nodes
for(l=xtop; l; l=l->next) for(l=all; l; l=l->next)
if(l->n->op == ODCLFUNC) if(l->n->op == ODCLFUNC)
esctag(l->n); esctag(l->n);

View File

@ -955,7 +955,7 @@ NodeList* variter(NodeList *vl, Node *t, NodeList *el);
/* /*
* esc.c * esc.c
*/ */
void escapes(void); void escapes(NodeList*);
/* /*
* export.c * export.c

View File

@ -186,7 +186,7 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int i, c; int i, c;
NodeList *l; NodeList *l, *batch;
char *p; char *p;
#ifdef SIGBUS #ifdef SIGBUS
@ -390,7 +390,7 @@ main(int argc, char *argv[])
// Phase 5: escape analysis. // Phase 5: escape analysis.
if(!debug['N']) if(!debug['N'])
escapes(); escapes(xtop);
// Phase 6: Compile top level functions. // Phase 6: Compile top level functions.
for(l=xtop; l; l=l->next) for(l=xtop; l; l=l->next)
@ -401,14 +401,17 @@ main(int argc, char *argv[])
fninit(xtop); fninit(xtop);
// Phase 6b: Compile all closures. // Phase 6b: Compile all closures.
// Can generate more closures, so run in batches.
while(closures) { while(closures) {
l = closures; batch = closures;
closures = nil; closures = nil;
for(; l; l=l->next) { if(debug['l'])
if (debug['l']) for(l=batch; l; l=l->next)
inlcalls(l->n); inlcalls(l->n);
if(!debug['N'])
escapes(batch);
for(l=batch; l; l=l->next)
funccompile(l->n, 1); funccompile(l->n, 1);
}
} }
// Phase 7: check external declarations. // Phase 7: check external declarations.

View File

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Test, using compiler diagnostic flags, that the escape analysis is working. // Test, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run. // Compiles but does not run. Inlining is disabled.
package foo package foo

33
test/escape4.go Normal file
View File

@ -0,0 +1,33 @@
// errchk -0 $G -m $D/$F.go
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test, using compiler diagnostic flags, that the escape analysis is working.
// Compiles but does not run. Inlining is enabled.
package foo
var p *int
func alloc(x int) *int { // ERROR "can inline alloc" "moved to heap: x"
return &x // ERROR "&x escapes to heap"
}
var f func()
func f1() {
p = alloc(2) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
// Escape analysis used to miss inlined code in closures.
func() { // ERROR "func literal does not escape"
p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
}()
f = func() { // ERROR "func literal escapes to heap"
p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
}
f()
}