mirror of https://github.com/golang/go.git
runtime: use funcdata to supply garbage collection information
This CL introduces a FUNCDATA number for runtime-specific garbage collection metadata, changes the C and Go compilers to emit that metadata, and changes the runtime to expect it. The old pseudo-instructions that carried this information are gone, as is the linker code to process them. R=golang-dev, dvyukov, cshapiro CC=golang-dev https://golang.org/cl/11406044
This commit is contained in:
parent
5d340de1f6
commit
48769bf546
|
|
@ -112,6 +112,7 @@ regopt(Prog *p)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
|
case AFUNCDATA:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,7 @@ peep(void)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
p = p->link;
|
p = p->link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1196,10 +1193,8 @@ copyu(Prog *p, Adr *v, Adr *s)
|
||||||
return 3;
|
return 3;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case ALOCALS: /* funny */
|
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
case APCDATA:
|
case APCDATA:
|
||||||
|
case AFUNCDATA:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,10 +248,7 @@ regopt(Prog *firstp)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
|
||||||
|
|
@ -201,11 +201,6 @@ enum as
|
||||||
AFUNCDATA,
|
AFUNCDATA,
|
||||||
APCDATA,
|
APCDATA,
|
||||||
|
|
||||||
// TODO: Remove these.
|
|
||||||
ALOCALS,
|
|
||||||
ANPTRS,
|
|
||||||
APTRS,
|
|
||||||
|
|
||||||
ALAST,
|
ALAST,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,6 @@ struct Sym
|
||||||
int32 elfsym;
|
int32 elfsym;
|
||||||
int32 locals; // size of stack frame locals area
|
int32 locals; // size of stack frame locals area
|
||||||
int32 args; // size of stack frame incoming arguments area
|
int32 args; // size of stack frame incoming arguments area
|
||||||
int32 nptrs; // number of bits in the pointer map
|
|
||||||
uint32* ptrs; // pointer map data
|
|
||||||
uchar special;
|
uchar special;
|
||||||
uchar fnptr; // used as fn ptr
|
uchar fnptr; // used as fn ptr
|
||||||
uchar stkcheck;
|
uchar stkcheck;
|
||||||
|
|
@ -436,7 +434,6 @@ int32 immaddr(int32);
|
||||||
int32 opbra(int, int);
|
int32 opbra(int, int);
|
||||||
int brextra(Prog*);
|
int brextra(Prog*);
|
||||||
int isbranch(Prog*);
|
int isbranch(Prog*);
|
||||||
void fnptrs(void);
|
|
||||||
void doelf(void);
|
void doelf(void);
|
||||||
void dozerostk(void); // used by -Z
|
void dozerostk(void); // used by -Z
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -615,51 +615,12 @@ loop:
|
||||||
pc++;
|
pc++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALOCALS:
|
|
||||||
if(skip)
|
|
||||||
goto casedef;
|
|
||||||
cursym->locals = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
if(skip)
|
if(skip)
|
||||||
goto casedef;
|
goto casedef;
|
||||||
pc++;
|
pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case ANPTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casedef;
|
|
||||||
if(cursym->nptrs != -1) {
|
|
||||||
diag("ldobj1: multiple pointer maps defined for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->to.offset > cursym->args/PtrSize) {
|
|
||||||
diag("ldobj1: pointer map definition for %s exceeds its argument size", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->nptrs = p->to.offset;
|
|
||||||
if(cursym->nptrs != 0)
|
|
||||||
cursym->ptrs = mal((rnd(cursym->nptrs, 32) / 32) * sizeof(*cursym->ptrs));
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case APTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casedef;
|
|
||||||
if(cursym->nptrs == -1 || cursym->ptrs == nil) {
|
|
||||||
diag("ldobj1: pointer map data provided for %s without a definition", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->from.offset*32 >= rnd(cursym->nptrs, 32)) {
|
|
||||||
diag("ldobj1: excessive pointer map data provided for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->ptrs[p->from.offset] = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case ATEXT:
|
case ATEXT:
|
||||||
if(cursym != nil && cursym->text) {
|
if(cursym != nil && cursym->text) {
|
||||||
histtoauto();
|
histtoauto();
|
||||||
|
|
@ -704,7 +665,6 @@ loop:
|
||||||
s->text = p;
|
s->text = p;
|
||||||
s->value = pc;
|
s->value = pc;
|
||||||
s->args = p->to.offset2;
|
s->args = p->to.offset2;
|
||||||
s->nptrs = -1;
|
|
||||||
lastp = p;
|
lastp = p;
|
||||||
p->pc = pc;
|
p->pc = pc;
|
||||||
pc++;
|
pc++;
|
||||||
|
|
|
||||||
|
|
@ -830,7 +830,6 @@ buildop(void)
|
||||||
case ARFE:
|
case ARFE:
|
||||||
case ATEXT:
|
case ATEXT:
|
||||||
case AUSEFIELD:
|
case AUSEFIELD:
|
||||||
case ALOCALS:
|
|
||||||
case ACASE:
|
case ACASE:
|
||||||
case ABCASE:
|
case ABCASE:
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ regopt(Prog *p)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
|
case AFUNCDATA:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
@ -645,6 +646,7 @@ brk:
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
|
case AFUNCDATA:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,10 +132,7 @@ peep(void)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
p = p->link;
|
p = p->link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -223,10 +223,7 @@ regopt(Prog *firstp)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
|
||||||
|
|
@ -766,11 +766,6 @@ enum as
|
||||||
AFUNCDATA,
|
AFUNCDATA,
|
||||||
APCDATA,
|
APCDATA,
|
||||||
|
|
||||||
// TODO: Remove these.
|
|
||||||
ALOCALS,
|
|
||||||
ANPTRS,
|
|
||||||
APTRS,
|
|
||||||
|
|
||||||
ALAST
|
ALAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,10 +159,7 @@ struct Sym
|
||||||
int32 got;
|
int32 got;
|
||||||
int32 align; // if non-zero, required alignment in bytes
|
int32 align; // if non-zero, required alignment in bytes
|
||||||
int32 elfsym;
|
int32 elfsym;
|
||||||
int32 locals; // size of stack frame locals area
|
|
||||||
int32 args; // size of stack frame incoming arguments area
|
int32 args; // size of stack frame incoming arguments area
|
||||||
int32 nptrs; // number of bits in the pointer map
|
|
||||||
uint32* ptrs; // pointer map data
|
|
||||||
Sym* hash; // in hash table
|
Sym* hash; // in hash table
|
||||||
Sym* allsym; // in all symbol list
|
Sym* allsym; // in all symbol list
|
||||||
Sym* next; // in text or data list
|
Sym* next; // in text or data list
|
||||||
|
|
|
||||||
|
|
@ -604,51 +604,12 @@ loop:
|
||||||
pc++;
|
pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case ALOCALS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
cursym->locals = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
if(skip)
|
if(skip)
|
||||||
goto casdef;
|
goto casdef;
|
||||||
pc++;
|
pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case ANPTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
if(cursym->nptrs != -1) {
|
|
||||||
diag("ldobj1: multiple pointer maps defined for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->to.offset > cursym->args/PtrSize) {
|
|
||||||
diag("ldobj1: pointer map definition for %s exceeds its argument size", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->nptrs = p->to.offset;
|
|
||||||
if(cursym->nptrs != 0)
|
|
||||||
cursym->ptrs = mal((rnd(cursym->nptrs, 32) / 32) * sizeof(*cursym->ptrs));
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case APTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
if(cursym->nptrs == -1 || cursym->ptrs == nil) {
|
|
||||||
diag("ldobj1: pointer map data provided for %s without a definition", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->from.offset*32 >= rnd(cursym->nptrs, 32)) {
|
|
||||||
diag("ldobj1: excessive pointer map data provided for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->ptrs[p->from.offset] = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case ATEXT:
|
case ATEXT:
|
||||||
s = p->from.sym;
|
s = p->from.sym;
|
||||||
if(s->text != nil) {
|
if(s->text != nil) {
|
||||||
|
|
@ -694,7 +655,6 @@ loop:
|
||||||
s->hist = gethist();
|
s->hist = gethist();
|
||||||
s->value = pc;
|
s->value = pc;
|
||||||
s->args = p->to.offset >> 32;
|
s->args = p->to.offset >> 32;
|
||||||
s->nptrs = -1;
|
|
||||||
lastp = p;
|
lastp = p;
|
||||||
p->pc = pc++;
|
p->pc = pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ regopt(Prog *p)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
|
case AFUNCDATA:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
@ -584,6 +585,7 @@ brk:
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
|
case AFUNCDATA:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,7 @@ peep(void)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
p = p->link;
|
p = p->link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,10 +195,7 @@ regopt(Prog *firstp)
|
||||||
case AGLOBL:
|
case AGLOBL:
|
||||||
case ANAME:
|
case ANAME:
|
||||||
case ASIGNAME:
|
case ASIGNAME:
|
||||||
case ALOCALS:
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
case ANPTRS:
|
|
||||||
case APTRS:
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
r = rega();
|
r = rega();
|
||||||
|
|
|
||||||
|
|
@ -582,11 +582,6 @@ enum as
|
||||||
AFUNCDATA,
|
AFUNCDATA,
|
||||||
APCDATA,
|
APCDATA,
|
||||||
|
|
||||||
// TODO: Remove these.
|
|
||||||
ALOCALS,
|
|
||||||
ANPTRS,
|
|
||||||
APTRS,
|
|
||||||
|
|
||||||
ALAST
|
ALAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,7 @@ struct Sym
|
||||||
int32 got;
|
int32 got;
|
||||||
int32 align; // if non-zero, required alignment in bytes
|
int32 align; // if non-zero, required alignment in bytes
|
||||||
int32 elfsym;
|
int32 elfsym;
|
||||||
int32 locals; // size of stack frame locals area
|
|
||||||
int32 args; // size of stack frame incoming arguments area
|
int32 args; // size of stack frame incoming arguments area
|
||||||
int32 nptrs; // number of bits in the pointer map
|
|
||||||
uint32* ptrs; // pointer map data
|
|
||||||
Sym* hash; // in hash table
|
Sym* hash; // in hash table
|
||||||
Sym* allsym; // in all symbol list
|
Sym* allsym; // in all symbol list
|
||||||
Sym* next; // in text or data list
|
Sym* next; // in text or data list
|
||||||
|
|
|
||||||
|
|
@ -614,51 +614,12 @@ loop:
|
||||||
pc++;
|
pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case ALOCALS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
cursym->locals = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case ATYPE:
|
case ATYPE:
|
||||||
if(skip)
|
if(skip)
|
||||||
goto casdef;
|
goto casdef;
|
||||||
pc++;
|
pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case ANPTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
if(cursym->nptrs != -1) {
|
|
||||||
diag("ldobj1: multiple pointer maps defined for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->to.offset > cursym->args/PtrSize) {
|
|
||||||
diag("ldobj1: pointer map definition for %s exceeds its argument size", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->nptrs = p->to.offset;
|
|
||||||
if(cursym->nptrs != 0)
|
|
||||||
cursym->ptrs = mal((rnd(cursym->nptrs, 32) / 32) * sizeof(*cursym->ptrs));
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case APTRS:
|
|
||||||
if(skip)
|
|
||||||
goto casdef;
|
|
||||||
if(cursym->nptrs == -1 || cursym->ptrs == nil) {
|
|
||||||
diag("ldobj1: pointer map data provided for %s without a definition", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
if(p->from.offset*32 >= rnd(cursym->nptrs, 32)) {
|
|
||||||
diag("ldobj1: excessive pointer map data provided for %s", cursym->name);
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
cursym->ptrs[p->from.offset] = p->to.offset;
|
|
||||||
pc++;
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
case ATEXT:
|
case ATEXT:
|
||||||
s = p->from.sym;
|
s = p->from.sym;
|
||||||
if(s->text != nil) {
|
if(s->text != nil) {
|
||||||
|
|
@ -699,7 +660,6 @@ loop:
|
||||||
s->hist = gethist();
|
s->hist = gethist();
|
||||||
s->value = pc;
|
s->value = pc;
|
||||||
s->args = p->to.offset2;
|
s->args = p->to.offset2;
|
||||||
s->nptrs = -1;
|
|
||||||
lastp = p;
|
lastp = p;
|
||||||
p->pc = pc++;
|
p->pc = pc++;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,10 @@ codgen(Node *n, Node *nn)
|
||||||
{
|
{
|
||||||
Prog *sp;
|
Prog *sp;
|
||||||
Node *n1, nod, nod1;
|
Node *n1, nod, nod1;
|
||||||
|
Sym *gcsym;
|
||||||
|
static int ngcsym;
|
||||||
|
static char namebuf[40];
|
||||||
|
int32 off;
|
||||||
|
|
||||||
cursafe = 0;
|
cursafe = 0;
|
||||||
curarg = 0;
|
curarg = 0;
|
||||||
|
|
@ -97,8 +101,7 @@ codgen(Node *n, Node *nn)
|
||||||
|
|
||||||
p = gtext(n1->sym, stkoff);
|
p = gtext(n1->sym, stkoff);
|
||||||
sp = p;
|
sp = p;
|
||||||
gins(ALOCALS, Z, nodconst(stkoff));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* isolate first argument
|
* isolate first argument
|
||||||
*/
|
*/
|
||||||
|
|
@ -135,6 +138,34 @@ codgen(Node *n, Node *nn)
|
||||||
if(thechar=='6' || thechar=='7') /* [sic] */
|
if(thechar=='6' || thechar=='7') /* [sic] */
|
||||||
maxargsafe = xround(maxargsafe, 8);
|
maxargsafe = xround(maxargsafe, 8);
|
||||||
sp->to.offset += maxargsafe;
|
sp->to.offset += maxargsafe;
|
||||||
|
|
||||||
|
snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
|
||||||
|
gcsym = slookup(namebuf);
|
||||||
|
gcsym->class = CSTATIC;
|
||||||
|
|
||||||
|
memset(&nod, 0, sizeof nod);
|
||||||
|
nod.op = ONAME;
|
||||||
|
nod.sym = gcsym;
|
||||||
|
nod.class = CSTATIC;
|
||||||
|
|
||||||
|
gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod);
|
||||||
|
|
||||||
|
// TODO(rsc): "stkoff" is not right. It does not account for
|
||||||
|
// the possibility of data stored in .safe variables.
|
||||||
|
// Unfortunately those move up and down just like
|
||||||
|
// the argument frame (and in fact dovetail with it)
|
||||||
|
// so the number we need is not available or even
|
||||||
|
// well-defined. Probably we need to make the safe
|
||||||
|
// area its own section.
|
||||||
|
// That said, we've been using stkoff for months
|
||||||
|
// and nothing too terrible has happened.
|
||||||
|
off = 0;
|
||||||
|
gextern(gcsym, nodconst(stkoff), off, 4); // locals
|
||||||
|
off += 4;
|
||||||
|
gextern(gcsym, nodconst(0), off, 4); // nptrs
|
||||||
|
off += 4;
|
||||||
|
gcsym->type = typ(0, T);
|
||||||
|
gcsym->type->width = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,25 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "gg.h"
|
#include "gg.h"
|
||||||
#include "opt.h"
|
#include "opt.h"
|
||||||
|
#include "../../pkg/runtime/funcdata.h"
|
||||||
|
|
||||||
static void allocauto(Prog* p);
|
static void allocauto(Prog* p);
|
||||||
static void pointermap(Node* fn);
|
static int pointermap(Sym*, int, Node*);
|
||||||
|
static void gcsymbol(Sym*, Node*);
|
||||||
|
|
||||||
void
|
void
|
||||||
compile(Node *fn)
|
compile(Node *fn)
|
||||||
{
|
{
|
||||||
Plist *pl;
|
Plist *pl;
|
||||||
Node nod1, *n;
|
Node nod1, *n, *gcnod;
|
||||||
Prog *plocals, *ptxt, *p, *p1;
|
Prog *pfuncdata, *ptxt, *p, *p1;
|
||||||
int32 lno;
|
int32 lno;
|
||||||
Type *t;
|
Type *t;
|
||||||
Iter save;
|
Iter save;
|
||||||
vlong oldstksize;
|
vlong oldstksize;
|
||||||
NodeList *l;
|
NodeList *l;
|
||||||
|
Sym *gcsym;
|
||||||
|
static int ngcsym;
|
||||||
|
|
||||||
if(newproc == N) {
|
if(newproc == N) {
|
||||||
newproc = sysfunc("newproc");
|
newproc = sysfunc("newproc");
|
||||||
|
|
@ -89,7 +93,13 @@ compile(Node *fn)
|
||||||
|
|
||||||
ginit();
|
ginit();
|
||||||
|
|
||||||
plocals = gins(ALOCALS, N, N);
|
snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
|
||||||
|
gcsym = lookup(namebuf);
|
||||||
|
gcnod = newname(gcsym);
|
||||||
|
gcnod->class = PEXTERN;
|
||||||
|
|
||||||
|
nodconst(&nod1, types[TINT32], FUNCDATA_GC);
|
||||||
|
pfuncdata = gins(AFUNCDATA, &nod1, gcnod);
|
||||||
|
|
||||||
for(t=curfn->paramfld; t; t=t->down)
|
for(t=curfn->paramfld; t; t=t->down)
|
||||||
gtrack(tracksym(t->type));
|
gtrack(tracksym(t->type));
|
||||||
|
|
@ -109,8 +119,6 @@ compile(Node *fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pointermap(fn);
|
|
||||||
|
|
||||||
genlist(curfn->enter);
|
genlist(curfn->enter);
|
||||||
|
|
||||||
retpc = nil;
|
retpc = nil;
|
||||||
|
|
@ -151,9 +159,9 @@ compile(Node *fn)
|
||||||
|
|
||||||
oldstksize = stksize;
|
oldstksize = stksize;
|
||||||
allocauto(ptxt);
|
allocauto(ptxt);
|
||||||
|
|
||||||
plocals->to.type = D_CONST;
|
// Emit garbage collection symbol.
|
||||||
plocals->to.offset = stksize;
|
gcsymbol(gcsym, fn);
|
||||||
|
|
||||||
if(0)
|
if(0)
|
||||||
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
|
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
|
||||||
|
|
@ -171,6 +179,17 @@ ret:
|
||||||
lineno = lno;
|
lineno = lno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gcsymbol(Sym *gcsym, Node *fn)
|
||||||
|
{
|
||||||
|
int off;
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
off = duint32(gcsym, off, stksize); // size of local block
|
||||||
|
off = pointermap(gcsym, off, fn); // pointer bitmap for args (must be last)
|
||||||
|
ggloblsym(gcsym, off, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
walktype1(Type *t, vlong *xoffset, Bvec *bv)
|
walktype1(Type *t, vlong *xoffset, Bvec *bv)
|
||||||
{
|
{
|
||||||
|
|
@ -278,12 +297,11 @@ walktype(Type *type, Bvec *bv)
|
||||||
|
|
||||||
// Compute a bit vector to describes the pointer containing locations
|
// Compute a bit vector to describes the pointer containing locations
|
||||||
// in the argument list.
|
// in the argument list.
|
||||||
static void
|
static int
|
||||||
pointermap(Node *fn)
|
pointermap(Sym *gcsym, int off, Node *fn)
|
||||||
{
|
{
|
||||||
Type *thistype, *inargtype, *outargtype;
|
Type *thistype, *inargtype, *outargtype;
|
||||||
Bvec *bv;
|
Bvec *bv;
|
||||||
Prog *prog;
|
|
||||||
int32 i;
|
int32 i;
|
||||||
|
|
||||||
thistype = getthisx(fn->type);
|
thistype = getthisx(fn->type);
|
||||||
|
|
@ -296,17 +314,11 @@ pointermap(Node *fn)
|
||||||
walktype(inargtype, bv);
|
walktype(inargtype, bv);
|
||||||
if(outargtype != nil)
|
if(outargtype != nil)
|
||||||
walktype(outargtype, bv);
|
walktype(outargtype, bv);
|
||||||
prog = gins(ANPTRS, N, N);
|
off = duint32(gcsym, off, bv->n);
|
||||||
prog->to.type = D_CONST;
|
for(i = 0; i < bv->n; i += 32)
|
||||||
prog->to.offset = bv->n;
|
off = duint32(gcsym, off, bv->b[i/32]);
|
||||||
for(i = 0; i < bv->n; i += 32) {
|
|
||||||
prog = gins(APTRS, N, N);
|
|
||||||
prog->from.type = D_CONST;
|
|
||||||
prog->from.offset = i / 32;
|
|
||||||
prog->to.type = D_CONST;
|
|
||||||
prog->to.offset = bv->b[i / 32];
|
|
||||||
}
|
|
||||||
free(bv);
|
free(bv);
|
||||||
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the list of stack variables. autos after anything else,
|
// Sort the list of stack variables. autos after anything else,
|
||||||
|
|
|
||||||
|
|
@ -2354,7 +2354,7 @@ void
|
||||||
pclntab(void)
|
pclntab(void)
|
||||||
{
|
{
|
||||||
Prog *p;
|
Prog *p;
|
||||||
int32 i, n, nfunc, start, funcstart, nameoff;
|
int32 i, n, nfunc, start, funcstart;
|
||||||
uint32 *havepc, *havefunc;
|
uint32 *havepc, *havefunc;
|
||||||
Sym *ftab, *s;
|
Sym *ftab, *s;
|
||||||
int32 npcdata, nfuncdata, off, end;
|
int32 npcdata, nfuncdata, off, end;
|
||||||
|
|
@ -2409,9 +2409,7 @@ pclntab(void)
|
||||||
off = setaddr(ftab, off, cursym);
|
off = setaddr(ftab, off, cursym);
|
||||||
|
|
||||||
// name int32
|
// name int32
|
||||||
// Filled in below, after we emit the ptrs.
|
off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name));
|
||||||
nameoff = off;
|
|
||||||
off += 4;
|
|
||||||
|
|
||||||
// args int32
|
// args int32
|
||||||
// TODO: Move into funcinfo.
|
// TODO: Move into funcinfo.
|
||||||
|
|
@ -2420,9 +2418,8 @@ pclntab(void)
|
||||||
else
|
else
|
||||||
off = setuint32(ftab, off, cursym->args);
|
off = setuint32(ftab, off, cursym->args);
|
||||||
|
|
||||||
// locals int32
|
// Dead space. TODO: Delete (and update all parsers).
|
||||||
// TODO: Move into funcinfo.
|
off = setuint32(ftab, off, 0);
|
||||||
off = setuint32(ftab, off, cursym->locals);
|
|
||||||
|
|
||||||
// frame int32
|
// frame int32
|
||||||
// TODO: Remove entirely. The pcsp table is more precise.
|
// TODO: Remove entirely. The pcsp table is more precise.
|
||||||
|
|
@ -2435,23 +2432,9 @@ pclntab(void)
|
||||||
else
|
else
|
||||||
off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize);
|
off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize);
|
||||||
|
|
||||||
// TODO: Move into funcinfo.
|
// Dead space. TODO: Delete (and update all parsers).
|
||||||
// ptrsoff, ptrslen int32
|
off = setuint32(ftab, off, 0);
|
||||||
start = ftab->np;
|
off = setuint32(ftab, off, 0);
|
||||||
if(start&3) {
|
|
||||||
diag("bad math in functab: ptrs misaligned");
|
|
||||||
errorexit();
|
|
||||||
}
|
|
||||||
ftab->size = ftab->np; // for adduint32
|
|
||||||
for(i = 0; i < cursym->nptrs; i += 32)
|
|
||||||
adduint32(ftab, cursym->ptrs[i/32]);
|
|
||||||
off = setuint32(ftab, off, start);
|
|
||||||
off = setuint32(ftab, off, i/32);
|
|
||||||
|
|
||||||
// Now that ptrs are emitted, can fill in function name.
|
|
||||||
// The string is appended to ftab; we waited until now
|
|
||||||
// to avoid misaligning the ptrs data.
|
|
||||||
setuint32(ftab, nameoff, ftabaddstring(ftab, cursym->name));
|
|
||||||
|
|
||||||
// pcsp table (offset int32)
|
// pcsp table (offset int32)
|
||||||
off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0);
|
off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
// be written using #defines. It is included by the runtime package
|
// be written using #defines. It is included by the runtime package
|
||||||
// as well as the compilers.
|
// as well as the compilers.
|
||||||
|
|
||||||
#define PCDATA_ArgSize 0
|
#define PCDATA_ArgSize 0 /* argument size at CALL instruction */
|
||||||
|
|
||||||
|
#define FUNCDATA_GC 0 /* garbage collector block */
|
||||||
|
|
||||||
// To be used in assembly.
|
// To be used in assembly.
|
||||||
#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
|
#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "typekind.h"
|
#include "typekind.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
#include "funcdata.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Debug = 0,
|
Debug = 0,
|
||||||
|
|
@ -1385,6 +1386,14 @@ addroot(Obj obj)
|
||||||
|
|
||||||
extern byte pclntab[]; // base for f->ptrsoff
|
extern byte pclntab[]; // base for f->ptrsoff
|
||||||
|
|
||||||
|
typedef struct GCFunc GCFunc;
|
||||||
|
struct GCFunc
|
||||||
|
{
|
||||||
|
uint32 locals; // size of local variables in bytes
|
||||||
|
uint32 nptrs; // number of words that follow
|
||||||
|
uint32 ptrs[1]; // bitmap of pointers in arguments
|
||||||
|
};
|
||||||
|
|
||||||
// Scan a stack frame: local variables and function arguments/results.
|
// Scan a stack frame: local variables and function arguments/results.
|
||||||
static void
|
static void
|
||||||
addframeroots(Stkframe *frame, void*)
|
addframeroots(Stkframe *frame, void*)
|
||||||
|
|
@ -1392,21 +1401,28 @@ addframeroots(Stkframe *frame, void*)
|
||||||
Func *f;
|
Func *f;
|
||||||
byte *ap;
|
byte *ap;
|
||||||
int32 i, j, nuintptr;
|
int32 i, j, nuintptr;
|
||||||
uint32 w, b, *ptrs;
|
uint32 w, b;
|
||||||
|
GCFunc *gcf;
|
||||||
|
|
||||||
|
f = frame->fn;
|
||||||
|
gcf = runtime·funcdata(f, FUNCDATA_GC);
|
||||||
|
|
||||||
// Scan local variables if stack frame has been allocated.
|
// Scan local variables if stack frame has been allocated.
|
||||||
if(frame->varlen > 0)
|
i = frame->varp - (byte*)frame->sp;
|
||||||
addroot((Obj){frame->varp, frame->varlen, 0});
|
if(i > 0) {
|
||||||
|
if(gcf == nil)
|
||||||
|
addroot((Obj){frame->varp - i, i, 0});
|
||||||
|
else if(i >= gcf->locals)
|
||||||
|
addroot((Obj){frame->varp - gcf->locals, gcf->locals, 0});
|
||||||
|
}
|
||||||
|
|
||||||
// Scan arguments.
|
// Scan arguments.
|
||||||
// Use pointer information if known.
|
// Use pointer information if known.
|
||||||
f = frame->fn;
|
if(f->args > 0 && gcf != nil && gcf->nptrs > 0) {
|
||||||
if(f->args > 0 && f->ptrslen > 0) {
|
|
||||||
ap = frame->argp;
|
ap = frame->argp;
|
||||||
nuintptr = f->args / sizeof(uintptr);
|
nuintptr = f->args / sizeof(uintptr);
|
||||||
ptrs = (uint32*)(pclntab + f->ptrsoff);
|
for(i = 0; i < gcf->nptrs; i++) {
|
||||||
for(i = 0; i < f->ptrslen; i++) {
|
w = gcf->ptrs[i];
|
||||||
w = ptrs[i];
|
|
||||||
b = 1;
|
b = 1;
|
||||||
j = nuintptr;
|
j = nuintptr;
|
||||||
if(j > 32)
|
if(j > 32)
|
||||||
|
|
@ -2017,8 +2033,10 @@ runtime·gc(int32 force)
|
||||||
|
|
||||||
// all done
|
// all done
|
||||||
m->gcing = 0;
|
m->gcing = 0;
|
||||||
|
m->locks++;
|
||||||
runtime·semrelease(&runtime·worldsema);
|
runtime·semrelease(&runtime·worldsema);
|
||||||
runtime·starttheworld();
|
runtime·starttheworld();
|
||||||
|
m->locks--;
|
||||||
|
|
||||||
// now that gc is done and we're back on g stack, kick off finalizer thread if needed
|
// now that gc is done and we're back on g stack, kick off finalizer thread if needed
|
||||||
if(finq != nil) {
|
if(finq != nil) {
|
||||||
|
|
@ -2185,8 +2203,10 @@ runtime·ReadMemStats(MStats *stats)
|
||||||
updatememstats(nil);
|
updatememstats(nil);
|
||||||
*stats = mstats;
|
*stats = mstats;
|
||||||
m->gcing = 0;
|
m->gcing = 0;
|
||||||
|
m->locks++;
|
||||||
runtime·semrelease(&runtime·worldsema);
|
runtime·semrelease(&runtime·worldsema);
|
||||||
runtime·starttheworld();
|
runtime·starttheworld();
|
||||||
|
m->locks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -407,10 +407,10 @@ struct Func
|
||||||
|
|
||||||
// TODO: Remove these fields.
|
// TODO: Remove these fields.
|
||||||
int32 args; // in/out args size
|
int32 args; // in/out args size
|
||||||
int32 locals; // locals size
|
int32 x1; // locals size
|
||||||
int32 frame; // legacy frame size; use pcsp if possible
|
int32 frame; // legacy frame size; use pcsp if possible
|
||||||
int32 ptrsoff;
|
int32 x2;
|
||||||
int32 ptrslen;
|
int32 x3;
|
||||||
|
|
||||||
int32 pcsp;
|
int32 pcsp;
|
||||||
int32 pcfile;
|
int32 pcfile;
|
||||||
|
|
@ -677,10 +677,9 @@ struct Stkframe
|
||||||
uintptr lr; // program counter at caller aka link register
|
uintptr lr; // program counter at caller aka link register
|
||||||
uintptr sp; // stack pointer at pc
|
uintptr sp; // stack pointer at pc
|
||||||
uintptr fp; // stack pointer at caller aka frame pointer
|
uintptr fp; // stack pointer at caller aka frame pointer
|
||||||
|
byte* varp; // top of local variables
|
||||||
byte* argp; // pointer to function arguments
|
byte* argp; // pointer to function arguments
|
||||||
uintptr arglen; // number of bytes at argp
|
uintptr arglen; // number of bytes at argp
|
||||||
byte* varp; // pointer to local variables
|
|
||||||
uintptr varlen; // number of bytes at varp
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
|
int32 runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
|
||||||
|
|
@ -856,6 +855,7 @@ void runtime·netpollready(G**, PollDesc*, int32);
|
||||||
void runtime·crash(void);
|
void runtime·crash(void);
|
||||||
void runtime·parsedebugvars(void);
|
void runtime·parsedebugvars(void);
|
||||||
void _rt0_go(void);
|
void _rt0_go(void);
|
||||||
|
void* runtime·funcdata(Func*, int32);
|
||||||
|
|
||||||
#pragma varargck argpos runtime·printf 1
|
#pragma varargck argpos runtime·printf 1
|
||||||
#pragma varargck type "c" int32
|
#pragma varargck type "c" int32
|
||||||
|
|
|
||||||
|
|
@ -78,17 +78,17 @@ readvarint(byte **pp)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr
|
void*
|
||||||
funcdata(Func *f, int32 i)
|
runtime·funcdata(Func *f, int32 i)
|
||||||
{
|
{
|
||||||
byte *p;
|
byte *p;
|
||||||
|
|
||||||
if(i < 0 || i >= f->nfuncdata)
|
if(i < 0 || i >= f->nfuncdata)
|
||||||
return 0;
|
return nil;
|
||||||
p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
|
p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
|
||||||
if(sizeof(void*) == 8 && ((uintptr)p & 4))
|
if(sizeof(void*) == 8 && ((uintptr)p & 4))
|
||||||
p += 4;
|
p += 4;
|
||||||
return ((uintptr*)p)[i];
|
return ((void**)p)[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,9 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||||
runtime·throw("unknown caller pc");
|
runtime·throw("unknown caller pc");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.varp = (byte*)frame.fp;
|
||||||
|
|
||||||
// Derive size of arguments.
|
// Derive size of arguments.
|
||||||
// Most functions have a fixed-size argument block,
|
// Most functions have a fixed-size argument block,
|
||||||
// so we can use metadata about the function f.
|
// so we can use metadata about the function f.
|
||||||
|
|
@ -121,27 +123,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive location and size of local variables.
|
|
||||||
if(frame.fp == frame.sp) {
|
|
||||||
// Function has not created a frame for itself yet.
|
|
||||||
frame.varp = nil;
|
|
||||||
frame.varlen = 0;
|
|
||||||
} else if(f->locals == 0) {
|
|
||||||
// Assume no information, so use whole frame.
|
|
||||||
// TODO: Distinguish local==0 from local==unknown.
|
|
||||||
frame.varp = (byte*)frame.sp;
|
|
||||||
frame.varlen = frame.fp - frame.sp;
|
|
||||||
} else {
|
|
||||||
if(f->locals > frame.fp - frame.sp) {
|
|
||||||
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f));
|
|
||||||
if(callback != nil)
|
|
||||||
runtime·throw("invalid stack");
|
|
||||||
}
|
|
||||||
frame.varp = (byte*)frame.fp - f->locals;
|
|
||||||
frame.varlen = f->locals;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(skip > 0) {
|
if(skip > 0) {
|
||||||
skip--;
|
skip--;
|
||||||
goto skipped;
|
goto skipped;
|
||||||
|
|
@ -203,7 +184,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||||
frame.fn = f = runtime·findfunc(frame.pc);
|
frame.fn = f = runtime·findfunc(frame.pc);
|
||||||
if(f == nil)
|
if(f == nil)
|
||||||
frame.pc = x;
|
frame.pc = x;
|
||||||
else if (f->frame == 0)
|
else if(f->frame == 0)
|
||||||
frame.lr = x;
|
frame.lr = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||||
runtime·throw("unknown caller pc");
|
runtime·throw("unknown caller pc");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame.varp = (byte*)frame.fp - sizeof(uintptr);
|
||||||
|
|
||||||
// Derive size of arguments.
|
// Derive size of arguments.
|
||||||
// Most functions have a fixed-size argument block,
|
// Most functions have a fixed-size argument block,
|
||||||
|
|
@ -137,26 +139,6 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive location and size of local variables.
|
|
||||||
if(frame.fp == frame.sp + sizeof(uintptr)) {
|
|
||||||
// Function has not created a frame for itself yet.
|
|
||||||
frame.varp = nil;
|
|
||||||
frame.varlen = 0;
|
|
||||||
} else if(f->locals == 0) {
|
|
||||||
// Assume no information, so use whole frame.
|
|
||||||
// TODO: Distinguish local==0 from local==unknown.
|
|
||||||
frame.varp = (byte*)frame.sp;
|
|
||||||
frame.varlen = frame.fp - sizeof(uintptr) - frame.sp;
|
|
||||||
} else {
|
|
||||||
if(f->locals > frame.fp - sizeof(uintptr) - frame.sp) {
|
|
||||||
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %s\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, runtime·funcname(f));
|
|
||||||
if(callback != nil)
|
|
||||||
runtime·throw("invalid stack");
|
|
||||||
}
|
|
||||||
frame.varp = (byte*)frame.fp - sizeof(uintptr) - f->locals;
|
|
||||||
frame.varlen = f->locals;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(skip > 0) {
|
if(skip > 0) {
|
||||||
skip--;
|
skip--;
|
||||||
goto skipped;
|
goto skipped;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue