1
0
mirror of https://github.com/golang/go synced 2024-11-26 06:57:56 -07:00

move portable object routines (especially

signature generation) into gc.

R=ken
OCL=26933
CL=26933
This commit is contained in:
Russ Cox 2009-03-30 21:31:29 -07:00
parent 941ed00b1d
commit 5e792b6c09
10 changed files with 890 additions and 840 deletions

View File

@ -15,11 +15,11 @@ HFILES=\
OFILES=\
list.$O\
obj.$O\
align.$O\
gen.$O\
cgen.$O\
gsubr.$O\
obj.$O\
peep.$O\
reg.$O\
../6l/enam.$O\

View File

@ -4,6 +4,10 @@
#include "gg.h"
int thechar = '6';
char* thestring = "amd64";
/*
* go declares several platform-specific type aliases:
* int, uint, float, and uintptr

View File

@ -41,18 +41,6 @@ struct Prog
void* reg; // pointer to containing Reg struct
};
typedef struct Plist Plist;
struct Plist
{
Node* name;
Dcl* locals;
Prog* firstpc;
int recur;
Plist* link;
};
EXTERN Plist* plist;
EXTERN Plist* plast;
EXTERN Biobuf* bout;
EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
@ -146,18 +134,5 @@ int Rconv(Fmt*);
int Yconv(Fmt*);
void listinit(void);
/*
* obj
*/
void zname(Biobuf*, Sym*, int);
void zaddr(Biobuf*, Addr*, int);
void ieeedtod(Ieee*, double);
void dumpstrings(void);
void dumpsignatures(void);
void outhist(Biobuf*);
/*
* align
*/
void dowidth(Type*);
uint32 rnd(uint32, uint32);

View File

@ -1938,10 +1938,39 @@ Prog*
gjmp(Prog *to)
{
Prog *p;
p = gbranch(AJMP, T);
if(to != P)
patch(p, to);
return p;
}
void
ggloblnod(Node *nam, int32 width)
{
Prog *p;
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
}
void
ggloblsym(Sym *s, int32 width, int dupok)
{
Prog *p;
p = gins(AGLOBL, N, N);
p->from.type = D_EXTERN;
if(s == symstringo)
p->from.type = D_STATIC;
p->from.index = D_NONE;
p->from.sym = s;
p->to.type = D_CONST;
p->to.index = D_NONE;
p->to.offset = width;
if(dupok)
p->from.scale = DUPOK;
}

View File

@ -31,58 +31,148 @@
#include "gg.h"
void
dumpobj(void)
zname(Biobuf *b, Sym *s, int t)
{
char *n;
Bputc(b, ANAME); /* as */
Bputc(b, ANAME>>8); /* as */
Bputc(b, t); /* type */
Bputc(b, s->sym); /* sym */
for(n=s->opackage; *n; n++)
Bputc(b, *n);
Bputdot(b);
for(n=s->name; *n; n++)
Bputc(b, *n);
Bputc(b, 0);
}
void
zfile(Biobuf *b, char *p, int n)
{
Bputc(b, ANAME);
Bputc(b, ANAME>>8);
Bputc(b, D_FILE);
Bputc(b, 1);
Bputc(b, '<');
Bwrite(b, p, n);
Bputc(b, 0);
}
void
zhist(Biobuf *b, int line, vlong offset)
{
Addr a;
Bputc(b, AHISTORY);
Bputc(b, AHISTORY>>8);
Bputc(b, line);
Bputc(b, line>>8);
Bputc(b, line>>16);
Bputc(b, line>>24);
zaddr(b, &zprog.from, 0);
a = zprog.to;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
zaddr(b, &a, 0);
}
void
zaddr(Biobuf *b, Addr *a, int s)
{
int32 l;
uint64 e;
int i, t;
char *n;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
switch(a->type) {
case D_BRANCH:
a->offset = a->branch->loc;
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0) {
t |= T_OFFSET;
l = a->offset;
if((vlong)l != a->offset)
t |= T_64;
}
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
Bputc(b, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(b, a->index);
Bputc(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
if(t & T_64) {
l = a->offset>>32;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
}
}
if(t & T_SYM) /* implies sym */
Bputc(b, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
l = e >> 32;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(b, a->type);
}
void
dumpfuncs(void)
{
Plist *pl;
Prog *p;
Dcl *d;
Sym *s;
Node *n;
struct { Sym *sym; short type; } h[NSYM];
int sf, st, t, sym;
Node n1;
// add nil plist w AEND
newplist();
bout = Bopen(outfile, OWRITE);
if(bout == nil)
fatal("cant open %s", outfile);
Bprint(bout, "amd64\n");
Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, package);
dumpexport();
Bprint(bout, "\n!\n");
outhist(bout);
// add globals
nodconst(&n1, types[TINT32], 0);
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
s = d->dsym;
if(s == S)
fatal("external nil");
n = d->dnode;
if(n == N || n->type == T)
fatal("external %S nil\n", s);
if(n->class == PFUNC)
continue;
dowidth(n->type);
mpmovecfix(n1.val.u.xval, n->type->width);
p = pc;
gins(AGLOBL, s->oname, &n1);
p->lineno = s->oname->lineno;
}
dumpstrings();
dumpsignatures();
struct { Sym *sym; short type; } h[NSYM];
Sym *s;
Prog *p;
for(sym=0; sym<NSYM; sym++) {
h[sym].sym = S;
@ -169,210 +259,6 @@ dumpobj(void)
zaddr(bout, &p->to, st);
}
}
Bterm(bout);
}
void
Bputdot(Biobuf *b)
{
// put out middle dot ·
Bputc(b, 0xc2);
Bputc(b, 0xb7);
}
void
zname(Biobuf *b, Sym *s, int t)
{
char *n;
Bputc(b, ANAME); /* as */
Bputc(b, ANAME>>8); /* as */
Bputc(b, t); /* type */
Bputc(b, s->sym); /* sym */
for(n=s->opackage; *n; n++)
Bputc(b, *n);
Bputdot(b);
for(n=s->name; *n; n++)
Bputc(b, *n);
Bputc(b, 0);
}
void
zaddr(Biobuf *b, Addr *a, int s)
{
int32 l;
int i, t;
char *n;
Ieee e;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
switch(a->type) {
case D_BRANCH:
a->offset = a->branch->loc;
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0) {
t |= T_OFFSET;
l = a->offset;
if((vlong)l != a->offset)
t |= T_64;
}
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
Bputc(b, t);
if(t & T_INDEX) { /* implies index, scale */
Bputc(b, a->index);
Bputc(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
if(t & T_64) {
l = a->offset>>32;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
}
}
if(t & T_SYM) /* implies sym */
Bputc(b, s);
if(t & T_FCONST) {
ieeedtod(&e, a->dval);
l = e.l;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
l = e.h;
Bputc(b, l);
Bputc(b, l>>8);
Bputc(b, l>>16);
Bputc(b, l>>24);
return;
}
if(t & T_SCONST) {
n = a->sval;
for(i=0; i<NSNAME; i++) {
Bputc(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
Bputc(b, a->type);
}
void
outhist(Biobuf *b)
{
Hist *h;
char *p, *q, *op;
Prog pg;
int n;
pg = zprog;
pg.as = AHISTORY;
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') {
op = p;
p = pathname;
}
while(p) {
q = utfrune(p, '/');
if(q) {
n = q-p;
if(n == 0)
n = 1; // leading "/"
q++;
} else {
n = strlen(p);
q = 0;
}
if(n) {
Bputc(b, ANAME);
Bputc(b, ANAME>>8);
Bputc(b, D_FILE);
Bputc(b, 1);
Bputc(b, '<');
Bwrite(b, p, n);
Bputc(b, 0);
}
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
pg.lineno = h->line;
pg.to.type = zprog.to.type;
pg.to.offset = h->offset;
if(h->offset)
pg.to.type = D_CONST;
Bputc(b, pg.as);
Bputc(b, pg.as>>8);
Bputc(b, pg.lineno);
Bputc(b, pg.lineno>>8);
Bputc(b, pg.lineno>>16);
Bputc(b, pg.lineno>>24);
zaddr(b, &pg.from, 0);
zaddr(b, &pg.to, 0);
}
}
void
ieeedtod(Ieee *ieee, double native)
{
double fr, ho, f;
int exp;
if(native < 0) {
ieeedtod(ieee, -native);
ieee->h |= 0x80000000L;
return;
}
if(native == 0) {
ieee->l = 0;
ieee->h = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
ieee->h = ho;
ieee->h &= 0xfffffL;
ieee->h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
ieee->l = ho;
ieee->l <<= 16;
ieee->l |= (int32)(fr*f);
}
void
@ -463,66 +349,91 @@ dumpstrings(void)
}
}
static int
sigcmp(Sig *a, Sig *b)
{
return strcmp(a->name, b->name);
}
static Addr at, ao, ac, ad;
static int wi, ws, ot;
void
ginsatoa(int fscale, int toffset)
int
dstringptr(Sym *s, int off, char *str)
{
Prog *p;
p = pc;
ot = rnd(ot, fscale);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = fscale;
p->to = ao;
p->to.offset = toffset;
ot += fscale;
}
void
gensatac(int fscale, int toffset)
{
Prog *p;
p = pc;
ot = rnd(ot, fscale);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = fscale;
p->to = ac;
p->to.offset = toffset;
ot += fscale;
}
void
gensatad(Sym *s)
{
Prog *p;
p = pc;
ot = rnd(ot, widthptr);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
off = rnd(off, widthptr);
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
p->from.offset = off;
p->from.scale = widthptr;
p->to = ad;
p->to.sym = s;
ot += widthptr;
p->to.type = D_ADDR;
p->to.index = D_STATIC;
p->to.etype = TINT32;
p->to.sym = symstringo;
p->to.offset = stringo;
off += widthptr;
datastring(str, strlen(str)+1);
return off;
}
int
duintxx(Sym *s, int off, uint64 v, int wid)
{
Prog *p;
off = rnd(off, wid);
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
p->from.offset = off;
p->from.scale = wid;
p->to.type = D_CONST;
p->to.index = D_NONE;
p->to.offset = v;
off += wid;
return off;
}
int
duint32(Sym *s, int off, uint32 v)
{
return duintxx(s, off, v, 4);
}
int
duint16(Sym *s, int off, uint32 v)
{
return duintxx(s, off, v, 2);
}
int
duintptr(Sym *s, int off, uint32 v)
{
return duintxx(s, off, v, 8);
}
int
dsymptr(Sym *s, int off, Sym *x)
{
Prog *p;
off = rnd(off, widthptr);
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
p->from.offset = off;
p->from.scale = widthptr;
p->to.type = D_ADDR;
p->to.index = D_EXTERN;
p->to.sym = x;
p->to.offset = 0;
off += widthptr;
return off;
}
void
genembedtramp(Type *t, Sig *b)
{
@ -615,405 +526,9 @@ out:
pc->as = ARET; // overwrite AEND
}
/*
* Add DATA for signature s.
* progt - type in program
* ifacet - type stored in interface (==progt if small, ==ptrto(progt) if large)
* rcvrt - type used as method interface. eqtype(ifacet, rcvrt) is always true,
* but ifacet might have a name that rcvrt does not.
* methodt - type with methods hanging off it (progt==*methodt sometimes)
*
* memory layout is Sigt struct from iface.c:
* struct Sigt
* {
* byte* name; // name of basic type
* Sigt* link; // for linking into hash tables
* uint32 thash; // hash of type
* uint32 mhash; // hash of methods
* uint16 width; // width of base type in bytes
* uint16 alg; // algorithm
* uint32 pad;
* struct {
* byte* fname;
* uint32 fhash; // hash of type
* uint32 offset; // offset of substruct
* void (*fun)(void);
* } meth[1]; // one or more - last name is nil
* };
*/
void
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
nopout(Prog *p)
{
Type *f;
int o;
Sig *a, *b;
Prog *p;
char buf[NSYMB];
Type *this;
Iter savet;
Prog *oldlist;
Sym *method;
uint32 sighash;
at.sym = s;
a = nil;
o = 0;
oldlist = nil;
sighash = typehash(progt, 1, 0);
for(f=methodt->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
method = f->sym;
if(method == nil)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = method->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(method, rcvrt);
sighash = sighash*100003 + a->hash;
if(!a->sym->siggen) {
a->sym->siggen = 1;
// TODO(rsc): This test is still not quite right.
this = structfirst(&savet, getthis(f->type))->type;
if(isptr[this->etype] != isptr[ifacet->etype]) {
if(oldlist == nil)
oldlist = pc;
// indirect vs direct mismatch
Sym *oldname, *newname;
Type *oldthis, *newthis;
newthis = ifacet;
if(isptr[newthis->etype])
oldthis = ifacet->type;
else
oldthis = ptrto(ifacet);
newname = a->sym;
oldname = methodsym(method, oldthis);
genptrtramp(method, oldname, oldthis, f->type, newname, newthis);
} else
if(f->embedded) {
// TODO(rsc): only works for pointer receivers
if(oldlist == nil)
oldlist = pc;
genembedtramp(ifacet, a);
}
}
o++;
}
// restore data output
if(oldlist) {
// old list ended with AEND; change to ANOP
// so that the trampolines that follow can be found.
oldlist->as = ANOP;
// start new data list
newplist();
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// base of type signature contains parameters
ginsatoa(widthptr, stringo); // name
ot = rnd(ot, widthptr)+widthptr; // skip link
gensatac(wi, typehash(progt, 1, 0)); // thash
gensatac(wi, sighash); // mhash
gensatac(ws, progt->width); // width
gensatac(ws, algtype(progt)); // algorithm
snprint(buf, sizeof buf, "%#T", progt);
datastring(buf, strlen(buf)+1);
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base of substructure
ginsatoa(widthptr, stringo); // field name
gensatac(wi, b->hash); // hash
gensatac(wi, 0); // offset
gensatad(b->sym); // &method
datastring(b->name, strlen(b->name)+1);
}
// nil field name at end
ot = rnd(ot, maxround);
gensatac(widthptr, 0);
// set DUPOK to allow other .6s to contain
// the same signature. only one will be chosen.
// should only happen for empty signatures
p = pc;
gins(AGLOBL, N, N);
p->from = at;
if(a == nil)
p->from.scale = DUPOK;
p->to = ac;
p->to.offset = ot;
p->as = ANOP;
}
/*
* memory layout is Sigi struct from iface.c:
* struct Sigi
* {
* byte* name;
* uint32 hash;
* uint32 size; // number of methods
* struct {
* byte* fname;
* uint32 fhash;
* uint32 perm; // location of fun in Sigt
* } meth[1]; // [size+1] - last name is nil
* };
*/
void
dumpsigi(Type *t, Sym *s)
{
Type *f;
Sym *s1;
int o;
Sig *a, *b;
Prog *p;
char buf[NSYMB];
uint32 sighash;
at.sym = s;
a = nil;
o = 0;
sighash = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = s1->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
sighash = sighash*100003 + a->hash;
o++;
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
snprint(buf, sizeof buf, "%#T", t);
datastring(buf, strlen(buf)+1);
// first field of an interface signature
// contains the count and is not a real entry
// sigi[0].hash = sighash
gensatac(wi, sighash);
// sigi[0].offset = count
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
gensatac(wi, o);
for(b=a; b!=nil; b=b->link) {
//print(" %s\n", b->name);
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode
gensatac(wi, b->hash);
// sigi[++].perm = mapped offset of method
gensatac(wi, b->perm);
datastring(b->name, strlen(b->name)+1);
}
// nil field name at end
ot = rnd(ot, maxround);
gensatac(widthptr, 0);
p = pc;
gins(AGLOBL, N, N);
p->from = at;
p->from.scale = DUPOK;
p->to = ac;
p->to.offset = ot;
}
void
dumpsignatures(void)
{
int et;
Dcl *d, *x;
Type *t, *progt, *methodt, *ifacet, *rcvrt;
Sym *s;
Prog *p;
memset(&at, 0, sizeof(at));
memset(&ao, 0, sizeof(ao));
memset(&ac, 0, sizeof(ac));
memset(&ad, 0, sizeof(ad));
wi = types[TINT32]->width;
ws = types[TINT16]->width;
// sig structure
at.type = D_EXTERN;
at.index = D_NONE;
at.sym = S; // fill in
at.offset = 0; // fill in
// $string
ao.type = D_ADDR;
ao.index = D_STATIC;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
// constant
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
// $method
ad.type = D_ADDR;
ad.index = D_EXTERN;
ad.sym = S; // fill in
ad.offset = 0;
// copy externdcl list to signatlist
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
if(t == T)
continue;
s = signame(t);
if(s == S)
continue;
x = mal(sizeof(*d));
x->op = OTYPE;
if(t->etype == TINTER)
x->dtype = t;
else
x->dtype = ptrto(t);
x->forw = signatlist;
x->block = 0;
signatlist = x;
//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
}
// process signatlist
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
s = signame(t);
if(s == S)
continue;
// only emit one
if(s->siggen)
continue;
s->siggen = 1;
// interface is easy
if(et == TINTER || et == TDDD) {
if(t->sym && !t->local)
continue;
dumpsigi(t, s);
continue;
}
// non-interface is more complex
progt = t;
methodt = t;
ifacet = t;
rcvrt = t;
// if there's a pointer, methods are on base.
if(isptr[methodt->etype] && methodt->type->sym != S) {
methodt = methodt->type;
expandmeth(methodt->sym, methodt);
// if methodt had a name, we don't want to see
// it in the method names that go into the sigt.
// e.g., if
// type item *rat
// then item needs its own sigt distinct from *rat,
// but it needs to have all of *rat's methods, using
// the *rat (not item) in the method names.
if(rcvrt->sym != S)
rcvrt = ptrto(methodt);
}
// and if ifacet is too wide, the methods
// will see a pointer anyway.
if(ifacet->width > 8) {
ifacet = ptrto(progt);
rcvrt = ptrto(progt);
}
// don't emit non-trivial signatures for types defined outside this file.
// non-trivial signatures might also drag in generated trampolines,
// and ar can't handle duplicates of the trampolines.
// only pay attention to types with symbols, because
// the ... structs and maybe other internal structs
// don't get marked as local.
if(methodt->method && methodt->sym && !methodt->local)
continue;
//print("s=%S\n", s);
dumpsigt(progt, ifacet, rcvrt, methodt, s);
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
}

View File

@ -31,6 +31,7 @@ OFILES=\
bits.$O\
align.$O\
gen.$O\
obj.$O\
$(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES)

View File

@ -592,8 +592,8 @@ EXTERN Node* typeswvar;
EXTERN char* context;
EXTERN char* pkgcontext;
EXTERN int thechar;
EXTERN char* thestring;
extern int thechar;
extern char* thestring;
EXTERN char* hunk;
EXTERN int32 nhunk;
EXTERN int32 thunk;
@ -979,6 +979,19 @@ struct Label
EXTERN Label* labellist;
EXTERN Label* findlab(Sym*);
typedef struct Plist Plist;
struct Plist
{
Node* name;
Dcl* locals;
Prog* firstpc;
int recur;
Plist* link;
};
EXTERN Plist* plist;
EXTERN Plist* plast;
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
@ -994,10 +1007,20 @@ Label* findlab(Sym *s);
void gen(Node *n);
void newlab(int op, Sym *s);
Node* sysfunc(char *name);
Plist* newplist(void);
/*
* gen.c/gsubr.c/obj.c
* obj.c
*/
void Bputdot(Biobuf *b);
void dumpfuncs(void);
void dumpglobls(void);
void dumpobj(void);
void ieeedtod(uint64 *ieee, double native);
void outhist(Biobuf *b);
/*
* arch-specific gen.c/gsubr.c/obj.c
*/
void betypeinit(void);
vlong convvtox(vlong, int);
@ -1021,3 +1044,21 @@ int isfat(Type*);
void clearfat(Node *n);
void cgen(Node*, Node*);
void gused(Node*);
void dumpstrings(void);
void dumpsignatures(void);
void dumpfuncs(void);
void ggloblnod(Node *nam, int32 width);
void ggloblsym(Sym *s, int32 width, int dupok);
void zfile(Biobuf *b, char *p, int n);
void zhist(Biobuf *b, int line, vlong offset);
void zname(Biobuf *b, Sym *s, int t);
void dumpstrings(void);
void nopout(Prog*);
void datastring(char *s, int len);
int dstringptr(Sym *s, int off, char *str);
int dsymptr(Sym *s, int off, Sym *x);
int duint16(Sym *s, int off, uint32 v);
int duint32(Sym *s, int off, uint32 v);
int duintptr(Sym *s, int off, uint32 v);
int duintxx(Sym *s, int off, uint64 v, int wid);
void genembedtramp(Type*, Sig*);

View File

@ -213,8 +213,6 @@ findpkg(String *name)
goroot = getenv("GOROOT");
}
// BOTCH need to get .6 from backend
// try .a before .6. important for building libraries:
// if there is an array.6 in the array.a library,
// want to find all of array.a, not just array.6.
@ -222,7 +220,7 @@ findpkg(String *name)
snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
if(access(namebuf, 0) >= 0)
return 1;
snprint(namebuf, sizeof(namebuf), "%s/%Z.6", p->dir, name);
snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
if(access(namebuf, 0) >= 0)
return 1;
}
@ -230,14 +228,14 @@ findpkg(String *name)
snprint(namebuf, sizeof(namebuf), "%Z.a", name);
if(access(namebuf, 0) >= 0)
return 1;
snprint(namebuf, sizeof(namebuf), "%Z.6", name);
snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
if(access(namebuf, 0) >= 0)
return 1;
if(goroot != nil) {
snprint(namebuf, sizeof(namebuf), "%s/pkg/%Z.a", goroot, name);
if(access(namebuf, 0) >= 0)
return 1;
snprint(namebuf, sizeof(namebuf), "%s/pkg/%Z.6", goroot, name);
snprint(namebuf, sizeof(namebuf), "%s/pkg/%Z.%c", goroot, name, thechar);
if(access(namebuf, 0) >= 0)
return 1;
}
@ -1300,7 +1298,6 @@ mkpackage(char* pkg)
lookup(package)->lexical = LPACK;
if(outfile == nil) {
// BOTCH need to get .6 from backend
p = strrchr(infile, '/');
if(p == nil)
p = infile;
@ -1310,7 +1307,6 @@ mkpackage(char* pkg)
p = strrchr(namebuf, '.');
if(p != nil)
*p = 0;
strncat(namebuf, ".6", sizeof(namebuf));
outfile = strdup(namebuf);
outfile = smprint("%s.%c", namebuf, thechar);
}
}

585
src/cmd/gc/obj.c Normal file
View File

@ -0,0 +1,585 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
/*
* architecture-independent object file output
*/
void
dumpobj(void)
{
bout = Bopen(outfile, OWRITE);
if(bout == nil)
fatal("cant open %s", outfile);
Bprint(bout, "%s\n", thestring);
Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, package);
dumpexport();
Bprint(bout, "\n!\n");
outhist(bout);
// add nil plist w AEND to catch
// auto-generated trampolines, data
newplist();
dumpglobls();
dumpstrings();
dumpsignatures();
dumpfuncs();
Bterm(bout);
}
void
dumpglobls(void)
{
Dcl *d;
Sym *s;
Node *n;
// add globals
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
s = d->dsym;
if(s == S)
fatal("external nil");
n = d->dnode;
if(n == N || n->type == T)
fatal("external %S nil\n", s);
if(n->class == PFUNC)
continue;
dowidth(n->type);
ggloblnod(s->oname, n->type->width);
}
}
void
Bputdot(Biobuf *b)
{
// put out middle dot ·
Bputc(b, 0xc2);
Bputc(b, 0xb7);
}
void
outhist(Biobuf *b)
{
Hist *h;
char *p, *q, *op;
int n;
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') {
op = p;
p = pathname;
}
while(p) {
q = utfrune(p, '/');
if(q) {
n = q-p;
if(n == 0)
n = 1; // leading "/"
q++;
} else {
n = strlen(p);
q = 0;
}
if(n)
zfile(b, p, n);
p = q;
if(p == 0 && op) {
p = op;
op = 0;
}
}
zhist(b, h->line, h->offset);
}
}
void
ieeedtod(uint64 *ieee, double native)
{
double fr, ho, f;
int exp;
uint32 h, l;
if(native < 0) {
ieeedtod(ieee, -native);
*ieee |= 1ULL<<63;
return;
}
if(native == 0) {
*ieee = 0;
return;
}
fr = frexp(native, &exp);
f = 2097152L; /* shouldnt use fp constants here */
fr = modf(fr*f, &ho);
h = ho;
h &= 0xfffffL;
h |= (exp+1022L) << 20;
f = 65536L;
fr = modf(fr*f, &ho);
l = ho;
l <<= 16;
l |= (int32)(fr*f);
*ieee = ((uint64)h << 32) | l;
}
/*
* Add DATA for signature s.
* progt - type in program
* ifacet - type stored in interface (==progt if small, ==ptrto(progt) if large)
* rcvrt - type used as method interface. eqtype(ifacet, rcvrt) is always true,
* but ifacet might have a name that rcvrt does not.
* methodt - type with methods hanging off it (progt==*methodt sometimes)
*
* memory layout is Sigt struct from iface.c:
* struct Sigt
* {
* byte* name; // name of basic type
* Sigt* link; // for linking into hash tables
* uint32 thash; // hash of type
* uint32 mhash; // hash of methods
* uint16 width; // width of base type in bytes
* uint16 alg; // algorithm
* struct {
* byte* fname;
* uint32 fhash; // hash of type
* uint32 offset; // offset of substruct
* void (*fun)(void);
* } meth[1]; // one or more - last name is nil
* };
*/
static int
sigcmp(Sig *a, Sig *b)
{
return strcmp(a->name, b->name);
}
void
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
{
Type *f;
int o;
Sig *a, *b;
char buf[NSYMB];
Type *this;
Iter savet;
Prog *oldlist;
Sym *method;
uint32 sighash;
int ot;
a = nil;
o = 0;
oldlist = nil;
sighash = typehash(progt, 1, 0);
for(f=methodt->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
method = f->sym;
if(method == nil)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = method->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(method, rcvrt);
sighash = sighash*100003 + a->hash;
if(!a->sym->siggen) {
a->sym->siggen = 1;
// TODO(rsc): This test is still not quite right.
this = structfirst(&savet, getthis(f->type))->type;
if(isptr[this->etype] != isptr[ifacet->etype]) {
if(oldlist == nil)
oldlist = pc;
// indirect vs direct mismatch
Sym *oldname, *newname;
Type *oldthis, *newthis;
newthis = ifacet;
if(isptr[newthis->etype])
oldthis = ifacet->type;
else
oldthis = ptrto(ifacet);
newname = a->sym;
oldname = methodsym(method, oldthis);
genptrtramp(method, oldname, oldthis, f->type, newname, newthis);
} else
if(f->embedded) {
// TODO(rsc): only works for pointer receivers
if(oldlist == nil)
oldlist = pc;
genembedtramp(ifacet, a);
}
}
o++;
}
// restore data output
if(oldlist) {
// old list ended with AEND; change to ANOP
// so that the trampolines that follow can be found.
nopout(oldlist);
// start new data list
newplist();
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// base of type signature contains parameters
snprint(buf, sizeof buf, "%#T", progt);
ot = dstringptr(s, ot, buf); // name
ot = duintptr(s, ot, 0); // skip link
ot = duint32(s, ot, typehash(progt, 1, 0)); // thash
ot = duint32(s, ot, sighash); // mhash
ot = duint16(s, ot, progt->width); // width
ot = duint16(s, ot, algtype(progt)); // algorithm
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base of substructure
ot = dstringptr(s, ot, b->name); // field name
ot = duint32(s, ot, b->hash); // hash
ot = duint32(s, ot, 0); // offset
ot = dsymptr(s, ot, b->sym); // &method
}
// nil field name at end
ot = rnd(ot, maxround);
ot = duintptr(s, ot, 0);
// set DUPOK to allow other .6s to contain
// the same signature. only one will be chosen.
// should only happen for empty signatures
ggloblsym(s, ot, a == nil);
}
/*
* memory layout is Sigi struct from iface.c:
* struct Sigi
* {
* byte* name;
* uint32 hash;
* uint32 size; // number of methods
* struct {
* byte* fname;
* uint32 fhash;
* uint32 perm; // location of fun in Sigt
* } meth[1]; // [size+1] - last name is nil
* };
*/
void
dumpsigi(Type *t, Sym *s)
{
Type *f;
Sym *s1;
int o;
Sig *a, *b;
char buf[NSYMB];
uint32 sighash;
int ot;
a = nil;
o = 0;
sighash = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = s1->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
sighash = sighash*100003 + a->hash;
o++;
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// sigi[0].name = type name, for runtime error message
snprint(buf, sizeof buf, "%#T", t);
ot = dstringptr(s, ot, buf);
// first field of an interface signature
// contains the count and is not a real entry
// sigi[0].hash = sighash
ot = duint32(s, ot, sighash);
// sigi[0].offset = count
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
ot = duint32(s, ot, o);
for(b=a; b!=nil; b=b->link) {
//print(" %s\n", b->name);
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
// sigx[++].hash = hashcode
// sigi[++].perm = mapped offset of method
ot = dstringptr(s, ot, b->name);
ot = duint32(s, ot, b->hash);
ot = duint32(s, ot, b->perm);
}
// nil field name at end
ot = rnd(ot, maxround);
ot = duintptr(s, ot, 0);
// TODO(rsc): DUPOK should not be necessary here,
// and I am a bit worried that it is. If I turn it off,
// I get multiple definitions for sigi.dotdotdot.
ggloblsym(s, ot, 1);
}
void
dumpsignatures(void)
{
int et;
Dcl *d, *x;
Type *t, *progt, *methodt, *ifacet, *rcvrt;
Sym *s;
// copy externdcl list to signatlist
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
if(t == T)
continue;
s = signame(t);
if(s == S)
continue;
x = mal(sizeof(*d));
x->op = OTYPE;
if(t->etype == TINTER)
x->dtype = t;
else
x->dtype = ptrto(t);
x->forw = signatlist;
x->block = 0;
signatlist = x;
//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
}
// process signatlist
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
s = signame(t);
if(s == S)
continue;
// only emit one
if(s->siggen)
continue;
s->siggen = 1;
// interface is easy
if(et == TINTER || et == TDDD) {
if(t->sym && !t->local)
continue;
dumpsigi(t, s);
continue;
}
// non-interface is more complex
progt = t;
methodt = t;
ifacet = t;
rcvrt = t;
// if there's a pointer, methods are on base.
if(isptr[methodt->etype] && methodt->type->sym != S) {
methodt = methodt->type;
expandmeth(methodt->sym, methodt);
// if methodt had a name, we don't want to see
// it in the method names that go into the sigt.
// e.g., if
// type item *rat
// then item needs its own sigt distinct from *rat,
// but it needs to have all of *rat's methods, using
// the *rat (not item) in the method names.
if(rcvrt->sym != S)
rcvrt = ptrto(methodt);
}
// and if ifacet is too wide, the methods
// will see a pointer anyway.
if(ifacet->width > 8) {
ifacet = ptrto(progt);
rcvrt = ptrto(progt);
}
// don't emit non-trivial signatures for types defined outside this file.
// non-trivial signatures might also drag in generated trampolines,
// and ar can't handle duplicates of the trampolines.
// only pay attention to types with symbols, because
// the ... structs and maybe other internal structs
// don't get marked as local.
if(methodt->method && methodt->sym && !methodt->local)
continue;
//print("s=%S\n", s);
dumpsigt(progt, ifacet, rcvrt, methodt, s);
}
if(stringo > 0)
ggloblsym(symstringo, stringo, 0);
}
void
stringpool(Node *n)
{
Pool *p;
int w;
if(n->op != OLITERAL || n->val.ctype != CTSTR) {
if(n->val.ctype == CTNIL)
return;
fatal("stringpool: not string %N", n);
}
p = mal(sizeof(*p));
p->sval = n->val.u.sval;
p->link = nil;
if(poolist == nil)
poolist = p;
else
poolast->link = p;
poolast = p;
w = types[TINT32]->width;
symstringo->offset += w; // len
symstringo->offset += p->sval->len; // str[len]
symstringo->offset = rnd(symstringo->offset, w);
}
Sig*
lsort(Sig *l, int(*f)(Sig*, Sig*))
{
Sig *l1, *l2, *le;
if(l == 0 || l->link == 0)
return l;
l1 = l;
l2 = l;
for(;;) {
l2 = l2->link;
if(l2 == 0)
break;
l2 = l2->link;
if(l2 == 0)
break;
l1 = l1->link;
}
l2 = l1->link;
l1->link = 0;
l1 = lsort(l, f);
l2 = lsort(l2, f);
/* set up lead element */
if((*f)(l1, l2) < 0) {
l = l1;
l1 = l1->link;
} else {
l = l2;
l2 = l2->link;
}
le = l;
for(;;) {
if(l1 == 0) {
while(l2) {
le->link = l2;
le = l2;
l2 = l2->link;
}
le->link = 0;
break;
}
if(l2 == 0) {
while(l1) {
le->link = l1;
le = l1;
l1 = l1->link;
}
break;
}
if((*f)(l1, l2) < 0) {
le->link = l1;
le = l1;
l1 = l1->link;
} else {
le->link = l2;
le = l2;
l2 = l2->link;
}
}
le->link = 0;
return l;
}

View File

@ -2403,102 +2403,6 @@ tempname(Node *n, Type *t)
n->xoffset = -stksize;
}
void
stringpool(Node *n)
{
Pool *p;
int w;
if(n->op != OLITERAL || n->val.ctype != CTSTR) {
if(n->val.ctype == CTNIL)
return;
fatal("stringpool: not string %N", n);
}
p = mal(sizeof(*p));
p->sval = n->val.u.sval;
p->link = nil;
if(poolist == nil)
poolist = p;
else
poolast->link = p;
poolast = p;
w = types[TINT32]->width;
symstringo->offset += w; // len
symstringo->offset += p->sval->len; // str[len]
symstringo->offset = rnd(symstringo->offset, w);
}
Sig*
lsort(Sig *l, int(*f)(Sig*, Sig*))
{
Sig *l1, *l2, *le;
if(l == 0 || l->link == 0)
return l;
l1 = l;
l2 = l;
for(;;) {
l2 = l2->link;
if(l2 == 0)
break;
l2 = l2->link;
if(l2 == 0)
break;
l1 = l1->link;
}
l2 = l1->link;
l1->link = 0;
l1 = lsort(l, f);
l2 = lsort(l2, f);
/* set up lead element */
if((*f)(l1, l2) < 0) {
l = l1;
l1 = l1->link;
} else {
l = l2;
l2 = l2->link;
}
le = l;
for(;;) {
if(l1 == 0) {
while(l2) {
le->link = l2;
le = l2;
l2 = l2->link;
}
le->link = 0;
break;
}
if(l2 == 0) {
while(l1) {
le->link = l1;
le = l1;
l1 = l1->link;
}
break;
}
if((*f)(l1, l2) < 0) {
le->link = l1;
le = l1;
l1 = l1->link;
} else {
le->link = l2;
le = l2;
l2 = l2->link;
}
}
le->link = 0;
return l;
}
void
setmaxarg(Type *t)
{