1
0
mirror of https://github.com/golang/go synced 2024-11-26 16:46:58 -07:00

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
This commit is contained in:
Russ Cox 2013-02-25 12:13:47 -05:00
parent a411b104f0
commit 1d5dc4fd48
33 changed files with 132 additions and 41 deletions

View File

@ -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;
}
}

View File

@ -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))

View File

@ -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

View File

@ -76,6 +76,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}

View File

@ -248,6 +248,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();

View File

@ -198,6 +198,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST,
};

View File

@ -578,6 +578,10 @@ loop:
pc++;
break;
case ATYPE:
pc++;
goto loop;
case ATEXT:
if(cursym != nil && cursym->text) {
histtoauto();

View File

@ -833,6 +833,7 @@ buildop(void)
case ALOCALS:
case ACASE:
case ABCASE:
case ATYPE:
break;
case AADDF:
oprange[AADDD] = oprange[r];

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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[] =

View File

@ -132,6 +132,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}

View File

@ -224,6 +224,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();

View File

@ -759,6 +759,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST
};

View File

@ -591,6 +591,10 @@ loop:
pc++;
goto loop;
case ATYPE:
pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {

View File

@ -1318,6 +1318,7 @@ Optab optab[] =
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
{ AEND },
0

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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[] =

View File

@ -126,6 +126,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}

View File

@ -195,6 +195,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();

View File

@ -569,6 +569,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST
};

View File

@ -600,6 +600,10 @@ loop:
pc++;
goto loop;
case ATYPE:
pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {

View File

@ -963,6 +963,7 @@ Optab optab[] =
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
0
};

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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*);

View File

@ -59,7 +59,7 @@ dumpglobls(void)
continue;
dowidth(n->type);
ggloblnod(n, n->type->width);
ggloblnod(n);
}
for(l=funcsyms; l; l=l->next) {

View File

@ -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);

View File

@ -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;
}

View File

@ -296,7 +296,6 @@ typecheck1(Node **np, int top)
}
typecheckdef(n);
n->realtype = n->type;
if(n->op == ONONAME)
goto error;
}

View File

@ -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.