From 1d5dc4fd481ae5ccebe1be0091a88b9343fe0904 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 25 Feb 2013 12:13:47 -0500 Subject: [PATCH] cmd/gc: emit explicit type information for local variables The type information is (and for years has been) included as an extra field in the address chunk of an instruction. Unfortunately, suppose there is a string at a+24(FP) and we have an instruction reading its length. It will say: MOVQ x+32(FP), AX and the type of *that* argument is int (not slice), because it is the length being read. This confuses the picture seen by debuggers and now, worse, by the garbage collector. Instead of attaching the type information to all uses, emit an explicit list of TYPE instructions with the information. The TYPE instructions are no-ops whose only role is to provide an address to attach type information to. For example, this function: func f(x, y, z int) (a, b string) { return } now compiles into: --- prog list "f" --- 0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56 0001 (/Users/rsc/x.go:3) LOCALS , 0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8 0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8 0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8 0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16 0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16 0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP) 0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP) 0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP) 0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP) 0011 (/Users/rsc/x.go:4) RET , The { } show the formerly hidden type information. The { } syntax is used when printing from within the gc compiler. It is not accepted by the assemblers. The same type information is now included on global variables: 0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0) This more accurate type information fixes a bug in the garbage collector's precise heap collection. The linker only cares about globals right now, but having the local information should make things a little nicer for Carl in the future. Fixes #4907. R=ken2 CC=golang-dev https://golang.org/cl/7395056 --- src/cmd/5g/ggen.c | 14 +++++++++++++- src/cmd/5g/gsubr.c | 5 +++-- src/cmd/5g/list.c | 5 ++++- src/cmd/5g/peep.c | 2 ++ src/cmd/5g/reg.c | 2 ++ src/cmd/5l/5.out.h | 1 + src/cmd/5l/obj.c | 4 ++++ src/cmd/5l/span.c | 1 + src/cmd/6g/ggen.c | 15 +++++++++++++-- src/cmd/6g/gsubr.c | 9 ++++----- src/cmd/6g/list.c | 5 ++++- src/cmd/6g/peep.c | 2 ++ src/cmd/6g/reg.c | 2 ++ src/cmd/6l/6.out.h | 1 + src/cmd/6l/obj.c | 4 ++++ src/cmd/6l/optab.c | 1 + src/cmd/8g/ggen.c | 14 +++++++++++++- src/cmd/8g/gsubr.c | 6 +++--- src/cmd/8g/list.c | 5 ++++- src/cmd/8g/peep.c | 2 ++ src/cmd/8g/reg.c | 2 ++ src/cmd/8l/8.out.h | 1 + src/cmd/8l/obj.c | 4 ++++ src/cmd/8l/optab.c | 1 + src/cmd/gc/closure.c | 7 ++----- src/cmd/gc/dcl.c | 13 +++++++++---- src/cmd/gc/fmt.c | 11 +++++++---- src/cmd/gc/go.h | 3 +-- src/cmd/gc/obj.c | 2 +- src/cmd/gc/pgen.c | 20 +++++++++++++++++--- src/cmd/gc/subr.c | 6 ++---- src/cmd/gc/typecheck.c | 1 - src/cmd/gc/walk.c | 2 ++ 33 files changed, 132 insertions(+), 41 deletions(-) diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 679354da9af..de1671bb6fe 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -28,6 +28,9 @@ void markautoused(Prog* p) { for (; p; p = p->link) { + if (p->as == ATYPE) + continue; + if (p->from.name == D_AUTO && p->from.node) p->from.node->used = 1; @@ -40,12 +43,21 @@ markautoused(Prog* p) void fixautoused(Prog* p) { - for (; p; p = p->link) { + Prog **lp; + + for (lp=&p; (p=*lp) != P; ) { + if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) { + *lp = p->link; + continue; + } + if (p->from.name == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; if (p->to.name == D_AUTO && p->to.node) p->to.offset += p->to.node->stkdelta; + + lp = &p->link; } } diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index ce5ae422e06..38c4a920064 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -192,15 +192,16 @@ gjmp(Prog *to) } void -ggloblnod(Node *nam, int32 width) +ggloblnod(Node *nam) { Prog *p; p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; + p->from.gotype = ngotype(nam); p->to.sym = S; p->to.type = D_CONST; - p->to.offset = width; + p->to.offset = nam->type->width; if(nam->readonly) p->reg = RODATA; if(nam->type != T && !haspointers(nam->type)) diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c index 9f67f79f432..6c3f1d74493 100644 --- a/src/cmd/5g/list.c +++ b/src/cmd/5g/list.c @@ -196,7 +196,10 @@ Dconv(Fmt *fp) // goto conv; } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); + if(a->gotype) + fmtprint(fp, "{%s}", a->gotype->name); + return 0; } int diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index c729a64661a..b6202a882cf 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -76,6 +76,8 @@ peep(void) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: p = p->link; } } diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index da80f32a4b6..0667531ebf3 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -248,6 +248,8 @@ regopt(Prog *firstp) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: continue; } r = rega(); diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index 1ffe9dc85e1..4aef8a27f4e 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -198,6 +198,7 @@ enum as AUSEFIELD, ALOCALS, + ATYPE, ALAST, }; diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index c9e38dc3894..14b1ea7aaeb 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -578,6 +578,10 @@ loop: pc++; break; + case ATYPE: + pc++; + goto loop; + case ATEXT: if(cursym != nil && cursym->text) { histtoauto(); diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c index fd30e91a523..a5afa02e79a 100644 --- a/src/cmd/5l/span.c +++ b/src/cmd/5l/span.c @@ -833,6 +833,7 @@ buildop(void) case ALOCALS: case ACASE: case ABCASE: + case ATYPE: break; case AADDF: oprange[AADDD] = oprange[r]; diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 10c116d6237..23bb5093f04 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -25,6 +25,9 @@ void markautoused(Prog* p) { for (; p; p = p->link) { + if (p->as == ATYPE) + continue; + if (p->from.type == D_AUTO && p->from.node) p->from.node->used = 1; @@ -35,14 +38,22 @@ markautoused(Prog* p) // Fixup instructions after compactframe has moved all autos around. void -fixautoused(Prog* p) +fixautoused(Prog *p) { - for (; p; p = p->link) { + Prog **lp; + + for (lp=&p; (p=*lp) != P; ) { + if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) { + *lp = p->link; + continue; + } if (p->from.type == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; if (p->to.type == D_AUTO && p->to.node) p->to.offset += p->to.node->stkdelta; + + lp = &p->link; } } diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 34965126e8f..fc5407a1f37 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -190,15 +190,16 @@ gjmp(Prog *to) } void -ggloblnod(Node *nam, int32 width) +ggloblnod(Node *nam) { Prog *p; p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; + p->from.gotype = ngotype(nam); p->to.sym = S; p->to.type = D_CONST; - p->to.offset = width; + p->to.offset = nam->type->width; if(nam->readonly) p->from.scale = RODATA; if(nam->type != T && !haspointers(nam->type)) @@ -1179,10 +1180,8 @@ naddr(Node *n, Addr *a, int canemitcode) case ONAME: a->etype = 0; - if(n->type != T) { + if(n->type != T) a->etype = simtype[n->type->etype]; - a->gotype = ngotype(n); - } a->offset = n->xoffset; a->sym = n->sym; a->node = n->orig; diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c index d84cceffb84..9d27a6a097b 100644 --- a/src/cmd/6g/list.c +++ b/src/cmd/6g/list.c @@ -161,7 +161,10 @@ brk: strcat(str, s); } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); + if(a->gotype) + fmtprint(fp, "{%s}", a->gotype->name); + return 0; } static char* regstr[] = diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c index 070077f1053..569655786ac 100644 --- a/src/cmd/6g/peep.c +++ b/src/cmd/6g/peep.c @@ -132,6 +132,8 @@ peep(void) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: p = p->link; } } diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index bb8e09c6423..e1188a2353a 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -224,6 +224,8 @@ regopt(Prog *firstp) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: continue; } r = rega(); diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index d348c1304e0..805b3fc6f2d 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -759,6 +759,7 @@ enum as AUSEFIELD, ALOCALS, + ATYPE, ALAST }; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index e90a66e5dc9..10e4a986019 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -590,6 +590,10 @@ loop: cursym->locals = p->to.offset; pc++; goto loop; + + case ATYPE: + pc++; + goto loop; case ATEXT: s = p->from.sym; diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c index 21b4784353f..a163e6faab4 100644 --- a/src/cmd/6l/optab.c +++ b/src/cmd/6l/optab.c @@ -1318,6 +1318,7 @@ Optab optab[] = { AUSEFIELD, ynop, Px, 0,0 }, { ALOCALS }, + { ATYPE }, { AEND }, 0 diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index e8d6747c4ab..70148106c40 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -27,6 +27,9 @@ void markautoused(Prog* p) { for (; p; p = p->link) { + if (p->as == ATYPE) + continue; + if (p->from.type == D_AUTO && p->from.node) p->from.node->used = 1; @@ -39,12 +42,21 @@ markautoused(Prog* p) void fixautoused(Prog* p) { - for (; p; p = p->link) { + Prog **lp; + + for (lp=&p; (p=*lp) != P; ) { + if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) { + *lp = p->link; + continue; + } + if (p->from.type == D_AUTO && p->from.node) p->from.offset += p->from.node->stkdelta; if (p->to.type == D_AUTO && p->to.node) p->to.offset += p->to.node->stkdelta; + + lp = &p->link; } } diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 3650d34a05b..c4c184bb9a8 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -191,15 +191,16 @@ gjmp(Prog *to) } void -ggloblnod(Node *nam, int32 width) +ggloblnod(Node *nam) { Prog *p; p = gins(AGLOBL, nam, N); p->lineno = nam->lineno; + p->from.gotype = ngotype(nam); p->to.sym = S; p->to.type = D_CONST; - p->to.offset = width; + p->to.offset = nam->type->width; if(nam->readonly) p->from.scale = RODATA; if(nam->type != T && !haspointers(nam->type)) @@ -2260,7 +2261,6 @@ naddr(Node *n, Addr *a, int canemitcode) a->etype = simtype[n->type->etype]; dowidth(n->type); a->width = n->type->width; - a->gotype = ngotype(n); } a->offset = n->xoffset; a->sym = n->sym; diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c index 7ed1c119d51..ec02ba5c5c0 100644 --- a/src/cmd/8g/list.c +++ b/src/cmd/8g/list.c @@ -158,7 +158,10 @@ brk: strcat(str, s); } conv: - return fmtstrcpy(fp, str); + fmtstrcpy(fp, str); + if(a->gotype) + fmtprint(fp, "{%s}", a->gotype->name); + return 0; } static char* regstr[] = diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index ccf7dcd3398..e5a3149cf1a 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -126,6 +126,8 @@ peep(void) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: p = p->link; } } diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index e96336b702e..c1f51c0a413 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -195,6 +195,8 @@ regopt(Prog *firstp) case AGLOBL: case ANAME: case ASIGNAME: + case ALOCALS: + case ATYPE: continue; } r = rega(); diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index ae1397dd8d3..38688995600 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -569,6 +569,7 @@ enum as AUSEFIELD, ALOCALS, + ATYPE, ALAST }; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index bd5684a3508..dcb8390b979 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -600,6 +600,10 @@ loop: pc++; goto loop; + case ATYPE: + pc++; + goto loop; + case ATEXT: s = p->from.sym; if(s->text != nil) { diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c index 3ccdbfd2260..79d7b39f005 100644 --- a/src/cmd/8l/optab.c +++ b/src/cmd/8l/optab.c @@ -963,6 +963,7 @@ Optab optab[] = { AUSEFIELD, ynop, Px, 0,0 }, { ALOCALS }, + { ATYPE }, 0 }; diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 3e65e0dd2cc..78b73d847ca 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -13,7 +13,7 @@ void closurehdr(Node *ntype) { - Node *n, *name, *a, *orig; + Node *n, *name, *a; NodeList *l; n = nod(OCLOSURE, N, N); @@ -43,11 +43,8 @@ closurehdr(Node *ntype) } for(l=n->rlist; l; l=l->next) { name = l->n->left; - if(name) { - orig = name->orig; // preserve the meaning of orig == N (anonymous PPARAMOUT) + if(name) name = newname(name->sym); - name->orig = orig; - } ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right)); } } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index c4990df072d..aa2489d9a10 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -640,8 +640,7 @@ funcargs(Node *nt) // give it a name so escape analysis has nodes to work with snprint(namebuf, sizeof(namebuf), "~anon%d", gen++); n->left = newname(lookup(namebuf)); - n->left->orig = N; // signal that the original was absent - + // TODO: n->left->missing = 1; } n->left->op = ONAME; @@ -815,7 +814,7 @@ structfield(Node *n) break; } - if(n->left && n->left->op == ONAME && n->left->orig != N) { + if(n->left && n->left->op == ONAME) { f->nname = n->left; f->embedded = n->embedded; f->sym = f->nname->sym; @@ -1177,6 +1176,7 @@ functype(Node *this, NodeList *in, NodeList *out) { Type *t; NodeList *rcvr; + Sym *s; t = typ(TFUNC); @@ -1194,7 +1194,12 @@ functype(Node *this, NodeList *in, NodeList *out) t->thistuple = 1; t->outtuple = count(out); t->intuple = count(in); - t->outnamed = t->outtuple > 0 && out->n->left != N && out->n->left->orig != N; + t->outnamed = 0; + if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) { + s = out->n->left->orig->sym; + if(s != S && s->name[0] != '~') + t->outnamed = 1; + } return t; } diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index bae66e07728..5d37ac0fd52 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -723,12 +723,15 @@ typefmt(Fmt *fp, Type *t) if(!(fp->flags&FmtShort)) { s = t->sym; - // Take the name from the original, lest we substituted it with .anon%d - if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) - if(t->nname->orig != N) + // Take the name from the original, lest we substituted it with ~anon%d + if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) { + if(t->nname->orig != N) { s = t->nname->orig->sym; - else + if(s != S && s->name[0] == '~') + s = S; + } else s = S; + } if(s != S && !t->embedded) { if(t->funarg) diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 68a0563aac3..05d942b4192 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -271,7 +271,6 @@ struct Node // most nodes Type* type; - Type* realtype; // as determined by typecheck Node* orig; // original form, for printing, and tracking copies of ONAMEs // func @@ -1438,7 +1437,7 @@ void gdata(Node*, Node*, int); void gdatacomplex(Node*, Mpcplx*); void gdatastring(Node*, Strlit*); void genembedtramp(Type*, Type*, Sym*, int iface); -void ggloblnod(Node *nam, int32 width); +void ggloblnod(Node *nam); void ggloblsym(Sym *s, int32 width, int dupok, int rodata); Prog* gjmp(Prog*); void gused(Node*); diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 94f1c65c969..b87d35b7bdc 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -59,7 +59,7 @@ dumpglobls(void) continue; dowidth(n->type); - ggloblnod(n, n->type->width); + ggloblnod(n); } for(l=funcsyms; l; l=l->next) { diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index f4894e468e6..6f732b991eb 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -14,11 +14,12 @@ compile(Node *fn) { Plist *pl; Node nod1, *n; - Prog *plocals, *ptxt; + Prog *plocals, *ptxt, *p, *p1; int32 lno; Type *t; Iter save; vlong oldstksize; + NodeList *l; if(newproc == N) { newproc = sysfunc("newproc"); @@ -92,12 +93,25 @@ compile(Node *fn) for(t=curfn->paramfld; t; t=t->down) gtrack(tracksym(t->type)); + for(l=fn->dcl; l; l=l->next) { + n = l->n; + if(n->op != ONAME) // might be OTYPE or OLITERAL + continue; + switch(n->class) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + nodconst(&nod1, types[TUINTPTR], l->n->type->width); + p = gins(ATYPE, l->n, &nod1); + p->from.gotype = ngotype(l->n); + break; + } + } + genlist(curfn->enter); retpc = nil; if(hasdefer || curfn->exit) { - Prog *p1; - p1 = gjmp(nil); retpc = gjmp(nil); patch(p1, pc); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 323d4f39228..db8b1701456 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3555,10 +3555,8 @@ umagic(Magic *m) Sym* ngotype(Node *n) { - if(n->sym != S && n->realtype != T) - if(strncmp(n->sym->name, "autotmp_", 8) != 0) - return typenamesym(n->realtype); - + if(n->type != T) + return typenamesym(n->type); return S; } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 6b750384c09..ac90baafd29 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -296,7 +296,6 @@ typecheck1(Node **np, int top) } typecheckdef(n); - n->realtype = n->type; if(n->op == ONONAME) goto error; } diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index c79339ca771..de2105ed39e 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2217,6 +2217,8 @@ paramstoheap(Type **argin, int out) nn = nil; for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { v = t->nname; + if(v && v->sym && v->sym->name[0] == '~') + v = N; if(v == N && out && hasdefer) { // Defer might stop a panic and show the // return values as they exist at the time of panic.