From 3a0fbfab57b133f4703cc7693a2af745570785ba Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 5 Feb 2015 16:08:29 +0300 Subject: [PATCH] cmd/gc: generate simpler names for closures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/cmd/gc/closure.c | 61 +++++++++++++++++++++++++++++++++++++------- src/cmd/gc/go.h | 2 ++ src/cmd/gc/init.c | 11 ++++---- src/cmd/gc/pgen.c | 2 +- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 0391ece379..9aeac8aba4 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -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; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index c5ef74586d..92584f6c58 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -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; diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index c769ec27f0..f1484ea1a6 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -11,14 +11,14 @@ * 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 * .init() (7) * { } (8) - * init·() // if any (9) + * init.() // 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; diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 3df78e7f9a..16a869181d 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -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; }