Commit 1d5dc4fd authored by Russ Cox's avatar Russ Cox

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
parent a411b104
......@@ -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;
}
}
......
......@@ -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))
......
......@@ -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
......
......@@ -76,6 +76,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}
......
......@@ -248,6 +248,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();
......
......@@ -198,6 +198,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST,
};
......
......@@ -578,6 +578,10 @@ loop:
pc++;
break;
case ATYPE:
pc++;
goto loop;
case ATEXT:
if(cursym != nil && cursym->text) {
histtoauto();
......
......@@ -833,6 +833,7 @@ buildop(void)
case ALOCALS:
case ACASE:
case ABCASE:
case ATYPE:
break;
case AADDF:
oprange[AADDD] = oprange[r];
......
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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[] =
......
......@@ -132,6 +132,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}
......
......@@ -224,6 +224,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();
......
......@@ -759,6 +759,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST
};
......
......@@ -590,6 +590,10 @@ loop:
cursym->locals = p->to.offset;
pc++;
goto loop;
case ATYPE:
pc++;
goto loop;
case ATEXT:
s = p->from.sym;
......
......@@ -1318,6 +1318,7 @@ Optab optab[] =
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
{ AEND },
0
......
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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[] =
......
......@@ -126,6 +126,8 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
p = p->link;
}
}
......
......@@ -195,6 +195,8 @@ regopt(Prog *firstp)
case AGLOBL:
case ANAME:
case ASIGNAME:
case ALOCALS:
case ATYPE:
continue;
}
r = rega();
......
......@@ -569,6 +569,7 @@ enum as
AUSEFIELD,
ALOCALS,
ATYPE,
ALAST
};
......
......@@ -600,6 +600,10 @@ loop:
pc++;
goto loop;
case ATYPE:
pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
......
......@@ -963,6 +963,7 @@ Optab optab[] =
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
0
};
......@@ -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));
}
}
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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*);
......
......@@ -59,7 +59,7 @@ dumpglobls(void)
continue;
dowidth(n->type);
ggloblnod(n, n->type->width);
ggloblnod(n);
}
for(l=funcsyms; l; l=l->next) {
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -296,7 +296,6 @@ typecheck1(Node **np, int top)
}
typecheckdef(n);
n->realtype = n->type;
if(n->op == ONONAME)
goto error;
}
......
......@@ -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.
......
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