mirror of
https://github.com/golang/go
synced 2024-11-18 14:54:40 -07:00
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/3964 Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
3ad906b208
commit
3a0fbfab57
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user