Commit 3a0fbfab authored by Dmitry Vyukov's avatar Dmitry Vyukov

cmd/gc: generate simpler names for closures

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/3964Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 3ad906b2
......@@ -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;
......
......@@ -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;
......
......@@ -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
* <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;
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment