mirror of
https://github.com/golang/go
synced 2024-11-22 19:54:39 -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:
parent
a411b104f0
commit
1d5dc4fd48
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user