]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: fix escape analysis + inlining + closure bug
authorRuss Cox <rsc@golang.org>
Fri, 24 Feb 2012 04:09:53 +0000 (23:09 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 24 Feb 2012 04:09:53 +0000 (23:09 -0500)
R=ken2
CC=golang-dev, lvd
https://golang.org/cl/5693056

src/cmd/gc/esc.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
test/escape2.go
test/escape4.go [new file with mode: 0644]

index 7e20457d9aea6dc3c0fce21ff6273c6084470447..2614b5f3567ed685957365431600490e439be482 100644 (file)
@@ -59,7 +59,7 @@ static int    dstcount, edgecount;    // diagnostic
 static NodeList*       noesc;  // list of possible non-escaping nodes, for printing
 
 void
-escapes(void)
+escapes(NodeList *all)
 {
        NodeList *l;
 
@@ -70,9 +70,10 @@ escapes(void)
        theSink.escloopdepth = -1;
 
        safetag = strlit("noescape");
+       noesc = nil;
 
-       // flow-analyze top level functions
-       for(l=xtop; l; l=l->next)
+       // flow-analyze functions
+       for(l=all; l; l=l->next)
                if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE)
                        escfunc(l->n);
 
@@ -84,7 +85,7 @@ escapes(void)
                escflood(l->n);
 
        // 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)
                        esctag(l->n);
 
index fcbea2cd90c70247bc0ddd695c2a48f6b2673190..81be4d25b1624197d32535888a2108d73f5aaebd 100644 (file)
@@ -955,7 +955,7 @@ NodeList*   variter(NodeList *vl, Node *t, NodeList *el);
 /*
  *     esc.c
  */
-void   escapes(void);
+void   escapes(NodeList*);
 
 /*
  *     export.c
index e880b2f34ceb035c1e29dfdd52cd61cc9b0d725b..924865b939e565ee7d4b17499a009d86ec4e8e03 100644 (file)
@@ -186,7 +186,7 @@ int
 main(int argc, char *argv[])
 {
        int i, c;
-       NodeList *l;
+       NodeList *l, *batch;
        char *p;
 
 #ifdef SIGBUS  
@@ -390,7 +390,7 @@ main(int argc, char *argv[])
 
        // Phase 5: escape analysis.
        if(!debug['N'])
-               escapes();
+               escapes(xtop);
 
        // Phase 6: Compile top level functions.
        for(l=xtop; l; l=l->next)
@@ -401,14 +401,17 @@ main(int argc, char *argv[])
                fninit(xtop);
 
        // Phase 6b: Compile all closures.
+       // Can generate more closures, so run in batches.
        while(closures) {
-               l = closures;
+               batch = closures;
                closures = nil;
-               for(; l; l=l->next) {
-                       if (debug['l'])
+               if(debug['l'])
+                       for(l=batch; l; l=l->next)
                                inlcalls(l->n);
+               if(!debug['N'])
+                       escapes(batch);
+               for(l=batch; l; l=l->next)
                        funccompile(l->n, 1);
-               }
        }
 
        // Phase 7: check external declarations.
index dde96bcc1e27a3a55919d9403f2185c9b81c205f..624ea80b55f8a78bca4e694fe5f50df5f2a96908 100644 (file)
@@ -5,7 +5,7 @@
 // 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.
+// Compiles but does not run.  Inlining is disabled.
 
 package foo
 
diff --git a/test/escape4.go b/test/escape4.go
new file mode 100644 (file)
index 0000000..ab3aee2
--- /dev/null
@@ -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()
+}