]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: generate simpler names for closures
authorDmitry Vyukov <dvyukov@google.com>
Thu, 5 Feb 2015 13:08:29 +0000 (16:08 +0300)
committerDmitry Vyukov <dvyukov@google.com>
Wed, 18 Feb 2015 07:09:50 +0000 (07:09 +0000)
Fixes #8291

There were several complaints about closure names in the issue tracker.
The first problem is that you see names like net/http.func·001
in profiles, traces, etc. And there is no way to figure out what
is that function.
Another issue is non-US-ascii symbols. All programs out there
should accept UTF-8. But unfortunately it is not true in reality.
For example, less does not render middle dot properly.

This change prepends outer function name to closure name and
replaces middle dot with dot. Now names look like:

main.glob.func1
main.glob.func2
main.glob.func2.1
main.init.1
main.init.1.func1
main.init.1.func1.1
main.main.func1
main.main.func1.1

Change-Id: I725726af88f2ad3ced2e3450f0f06bf459fd91c0
Reviewed-on: https://go-review.googlesource.com/3964
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/gc/closure.c
src/cmd/gc/go.h
src/cmd/gc/init.c
src/cmd/gc/pgen.c

index 0391ece3791e7fd083a74a8325c2aec546f6c575..9aeac8aba4c47c9e53610dc48edfcb9f170a20fa 100644 (file)
@@ -19,6 +19,7 @@ closurehdr(Node *ntype)
        n = nod(OCLOSURE, N, N);
        n->ntype = ntype;
        n->funcdepth = funcdepth;
+       n->outerfunc = curfn;
 
        funchdr(n);
 
@@ -124,11 +125,55 @@ typecheckclosure(Node *func, int top)
        xtop = list(xtop, makeclosure(func));
 }
 
+// closurename returns name for OCLOSURE n.
+// It is not as simple as it ought to be, because we typecheck nested closures
+// starting from the innermost one. So when we check the inner closure,
+// we don't yet have name for the outer closure. This function uses recursion
+// to generate names all the way up if necessary.
+static Sym*
+closurename(Node *n)
+{
+       static int closgen;
+       char *outer, *prefix;
+       int gen;
+
+       if(n->sym != S)
+               return n->sym;
+       gen = 0;
+       outer = NULL;
+       prefix = NULL;
+       if(n->outerfunc == N) {
+               // Global closure.
+               outer = "glob";
+               prefix = "func";
+               gen = ++closgen;
+       } else if(n->outerfunc->op == ODCLFUNC) {
+               // The outermost closure inside of a named function.
+               outer = n->outerfunc->nname->sym->name;
+               prefix = "func";
+               // Yes, functions can be named _.
+               // Can't use function closgen in such case,
+               // because it would lead to name clashes.
+               if(!isblank(n->outerfunc->nname))
+                       gen = ++n->outerfunc->closgen;
+               else
+                       gen = ++closgen;
+       } else if(n->outerfunc->op == OCLOSURE) {
+               // Nested closure, recurse.
+               outer = closurename(n->outerfunc)->name;
+               prefix = "";
+               gen = ++n->outerfunc->closgen;
+       } else
+               fatal("closurename called for %hN", n);
+       snprint(namebuf, sizeof namebuf, "%s.%s%d", outer, prefix, gen);
+       n->sym = lookup(namebuf);
+       return n->sym;
+}
+
 static Node*
 makeclosure(Node *func)
 {
        Node *xtype, *xfunc;
-       static int closgen;
 
        /*
         * wrap body in external function
@@ -140,8 +185,7 @@ makeclosure(Node *func)
 
        // create the function
        xfunc = nod(ODCLFUNC, N, N);
-       snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen);
-       xfunc->nname = newname(lookup(namebuf));
+       xfunc->nname = newname(closurename(func));
        xfunc->nname->sym->flags |= SymExported; // disable export
        xfunc->nname->ntype = xtype;
        xfunc->nname->defn = xfunc;
@@ -158,7 +202,7 @@ makeclosure(Node *func)
 
        xfunc->closure = func;
        func->closure = xfunc;
-       
+
        func->nbody = nil;
        func->list = nil;
        func->rlist = nil;
@@ -368,7 +412,7 @@ walkclosure(Node *func, NodeList **init)
        // and has one float64 argument and no results,
        // the generated code looks like:
        //
-       //      clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s}
+       //      clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
        //
        // The use of the struct provides type information to the garbage
        // collector so that it can walk the closure. We could use (in this case)
@@ -378,7 +422,7 @@ walkclosure(Node *func, NodeList **init)
        // same struct type can share the descriptor.
 
        typ = nod(OTSTRUCT, N, N);
-       typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
+       typ->list = list1(nod(ODCLFIELD, newname(lookup(".F")), typenod(types[TUINTPTR])));
        for(l=func->cvars; l; l=l->next) {
                v = l->n;
                if(v->op == OXXX)
@@ -447,12 +491,11 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
        static Pkg* gopkg;
        int i, ddd;
 
-       // TODO: names are not right
        rcvrtype = fn->left->type;
        if(exportname(meth->sym->name))
-               p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
+               p = smprint("(%-hT).%s-fm", rcvrtype, meth->sym->name);
        else
-               p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
+               p = smprint("(%-hT).(%-S)-fm", rcvrtype, meth->sym);
        basetype = rcvrtype;
        if(isptr[rcvrtype->etype])
                basetype = basetype->type;
index c5ef74586d0224e828be50030e8fce6c6d831232..92584f6c58ae649c2d8510e8a60c4ed9c5f8b6be 100644 (file)
@@ -310,6 +310,8 @@ struct      Node
        NodeList*       dcl;    // autodcl for this func/closure
        NodeList*       inl;    // copy of the body for use in inlining
        NodeList*       inldcl; // copy of dcl for use in inlining
+       int     closgen;
+       Node*   outerfunc;
 
        // OLITERAL/OREGISTER
        Val     val;
index c769ec27f06ce9f95ffa7338c4d414f41c9457b7..f1484ea1a69ee09ce8b0f12c19988f60bb76f089 100644 (file)
  * it is called by the initialization before
  * main is run. to make it unique within a
  * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init·1".
+ * normally "pkg.init", is altered to "pkg.init.1".
  */
 Sym*
 renameinit(void)
 {
        static int initgen;
 
-       snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
+       snprint(namebuf, sizeof(namebuf), "init.%d", ++initgen);
        return lookup(namebuf);
 }
 
@@ -35,7 +35,7 @@ renameinit(void)
  *             // over all matching imported symbols
  *                     <pkg>.init()                    (7)
  *             { <init stmts> }                        (8)
- *             init·<n>() // if any                   (9)
+ *             init.<n>() // if any                    (9)
  *             initdone· = 2;                         (10)
  *             return                                  (11)
  *     }
@@ -69,8 +69,7 @@ anyinit(NodeList *n)
                return 1;
 
        // is there an explicit init function
-       snprint(namebuf, sizeof(namebuf), "init·1");
-       s = lookup(namebuf);
+       s = lookup("init.1");
        if(s->def != N)
                return 1;
 
@@ -167,7 +166,7 @@ fninit(NodeList *n)
        // (9)
        // could check that it is fn of no args/returns
        for(i=1;; i++) {
-               snprint(namebuf, sizeof(namebuf), "init·%d", i);
+               snprint(namebuf, sizeof(namebuf), "init.%d", i);
                s = lookup(namebuf);
                if(s->def == N)
                        break;
index 3df78e7f9a2d917eb9eb2fcf771bfe2569f33811..16a869181d08e01ab2330a17172b3e26b4a13f21 100644 (file)
@@ -180,7 +180,7 @@ compile(Node *fn)
        dowidth(curfn->type);
 
        if(fn->nbody == nil) {
-               if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
+               if(pure_go || strncmp(fn->nname->sym->name, "init.", 5) == 0) {
                        yyerror("missing function body", fn);
                        goto ret;
                }