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

6g interface changes:

* allow conversion between nil interface and any type.
	* mark signatures as DUPOK so that multiple .6 can
	  contain sigt.*[]byte and only one gets used.

R=ken
OCL=18538
CL=18542
This commit is contained in:
Russ Cox 2008-11-05 11:27:50 -08:00
parent 6cd74b03f3
commit 1983121bbb
7 changed files with 238 additions and 368 deletions

View File

@ -516,7 +516,6 @@ gentramp(Type *t, Sig *b)
int c, d, o;
Prog *p;
Type *f;
Sym *msym;
e = lookup(b->name);
for(d=0; d<nelem(dotlist); d++) {
@ -596,292 +595,213 @@ out:
}
void
dumpsigt(void)
dumpsigt(Type *t0, Sym *s)
{
Dcl *d, *x;
Type *t, *f;
Sym *s1, *s;
int et, o;
Type *f, *t;
Sym *s1;
int o;
Sig *a, *b;
Prog *p;
char *sp;
char buf[NSYMB];
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
if(et == TINTER)
continue;
at.sym = signame(t, d->block);
if(at.sym == S)
at.sym = s;
t = t0;
if(isptr[t->etype] && t->type->sym != S) {
t = t->type;
expandmeth(t->sym, t);
}
a = nil;
o = 0;
for(f=t->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
// make unique
if(at.sym->local != 1)
continue;
at.sym->local = 2;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s = d->dsym;
if(s == S)
s1 = f->sym;
if(s1 == nil)
continue;
if(s->name[0] == '_')
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
if(strcmp(s->opackage, package) != 0)
continue;
a->name = s1->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = f->embedded; // need trampoline
expandmeth(s, t);
o++;
}
a = nil;
o = 0;
for(f=t->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
// sigi[0].name = ""
ginsatoa(widthptr, stringo);
s1 = f->sym;
if(s1 == nil)
continue;
// save type name for runtime error message.
snprint(buf, sizeof buf, "%#T", t0);
datastring(buf, strlen(buf)+1);
b = mal(sizeof(*b));
b->link = a;
a = b;
// first field of an type signature contains
// the element parameters and is not a real entry
if(t->methptr & 2)
t = types[tptr];
a->name = s1->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = f->embedded; // need trampoline
// sigi[0].hash = elemalg
gensatac(wi, algtype(t));
o++;
}
// sigi[0].offset = width
gensatac(wi, t->width);
a = lsort(a, sigcmp);
ot = 0;
// skip the function
gensatac(widthptr, 0);
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
// sigx[++].name = "fieldname"
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
// TODO(rsc): the * is a botch but right more often than not.
snprint(buf, sizeof buf, "*%#T", t);
datastring(buf, strlen(buf)+1);
// sigx[++].hash = hashcode
gensatac(wi, b->hash);
// first field of an type signature contains
// the element parameters and is not a real entry
// sigt[++].offset = of embeded struct
gensatac(wi, 0);
t = d->dtype;
if(t->methptr & 2)
t = types[tptr];
// sigt[++].fun = &method
gensatad(b->sym);
// sigi[0].hash = elemalg
gensatac(wi, algtype(t));
datastring(b->name, strlen(b->name)+1);
// sigi[0].offset = width
gensatac(wi, t->width);
// skip the function
gensatac(widthptr, 0);
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode
gensatac(wi, b->hash);
// sigt[++].offset = of embeded struct
gensatac(wi, 0);
// sigt[++].fun = &method
gensatad(b->sym);
datastring(b->name, strlen(b->name)+1);
if(b->offset)
gentramp(d->dtype, b);
}
// nil field name at end
ot = rnd(ot, maxround);
gensatac(widthptr, 0);
p = pc;
gins(AGLOBL, N, N);
p->from = at;
p->to = ac;
p->to.offset = ot;
if(b->offset)
gentramp(t0, b);
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
// 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.
p = pc;
gins(AGLOBL, N, N);
p->from = at;
p->from.scale = DUPOK;
p->to = ac;
p->to.offset = ot;
}
void
dumpsigi(void)
dumpsigi(Type *t, Sym *s)
{
Dcl *d, *x;
Type *t, *f;
Sym *s1, *s;
int et, o;
Type *f;
Sym *s1;
int o;
Sig *a, *b;
Prog *p;
char *sp;
char buf[NSYMB];
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
at.sym = s;
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
a = nil;
o = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
t = d->dtype;
et = t->etype;
if(et != TINTER)
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
if(s1->name[0] == '_')
continue;
at.sym = signame(t, d->block);
if(at.sym == S)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
// make unique
if(at.sym->local != 1)
continue;
at.sym->local = 2;
a->name = s1->name;
sp = strchr(s1->name, '_');
if(sp != nil)
a->name = sp+1;
s = d->dsym;
if(s == S)
continue;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
if(s->name[0] == '_')
continue;
o++;
}
if(strcmp(s->opackage, package) != 0)
continue;
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
//print("sigi: %S\n", s);
// sigi[0].name = ""
ginsatoa(widthptr, stringo);
a = nil;
o = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
// save type name for runtime error message.
snprint(buf, sizeof buf, "%#T", t);
datastring(buf, strlen(buf)+1);
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
// first field of an interface signature
// contains the count and is not a real entry
s1 = f->sym;
if(s1 == nil)
continue;
if(s1->name[0] == '_')
continue;
// sigi[0].hash = 0
gensatac(wi, 0);
b = mal(sizeof(*b));
b->link = a;
a = b;
// sigi[0].offset = count
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
gensatac(wi, o);
a->name = s1->name;
sp = strchr(s1->name, '_');
if(sp != nil)
a->name = sp+1;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
o++;
}
a = lsort(a, sigcmp);
ot = 0;
for(b=a; b!=nil; b=b->link) {
//print(" %s\n", b->name);
ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
// sigx[++].name = "fieldname"
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
// TODO(rsc): the * is a botch but right more often than not.
snprint(buf, sizeof buf, "%#T", t);
datastring(buf, strlen(buf)+1);
// sigx[++].hash = hashcode
gensatac(wi, b->hash);
// first field of an interface signature
// contains the count and is not a real entry
// sigi[++].perm = mapped offset of method
gensatac(wi, b->perm);
// sigi[0].hash = 0
gensatac(wi, 0);
// 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->to = ac;
p->to.offset = ot;
datastring(b->name, strlen(b->name)+1);
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
// 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;
Sym *s;
Sym *s, *s1;
Prog *p;
memset(&at, 0, sizeof(at));
memset(&ao, 0, sizeof(ao));
@ -923,19 +843,60 @@ dumpsignatures(void)
if(t == T)
continue;
s = signame(t, 0);
s = signame(t);
if(s == S)
continue;
x = mal(sizeof(*d));
x->op = OTYPE;
x->dsym = d->dsym;
x->dtype = d->dtype;
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);
}
dumpsigi();
dumpsigt();
// 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;
//print("dosig %T\n", t);
// don't emit signatures for *NamedStruct or interface if
// they were defined by other packages.
// (optimization)
s1 = S;
if(isptr[et] && t->type != T)
s1 = t->type->sym;
else if(et == TINTER)
s1 = t->sym;
if(s1 != S && strcmp(s1->opackage, package) != 0)
continue;
if(et == TINTER)
dumpsigi(t, s);
else
dumpsigt(t, s);
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
}

View File

@ -113,6 +113,7 @@ struct Sym
short become;
short frame;
uchar subtype;
uchar dupok;
ushort file;
vlong value;
int32 sig;

View File

@ -972,6 +972,8 @@ loop:
}
if(p->to.offset > s->value)
s->value = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
goto loop;
case ADYNT:
@ -1017,6 +1019,12 @@ loop:
case ADATA:
data:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
if(p->from.sym != S && p->from.sym->dupok)
goto loop;
if(edatap == P)
datap = p;
else

View File

@ -125,6 +125,7 @@ struct Type
uchar methptr; // 1=direct 2=pointer
uchar printed;
uchar embedded; // TFIELD embedded type
uchar siggen;
// TFUNCT
uchar thistuple;
@ -208,6 +209,7 @@ struct Sym
uchar sym; // huffman encoding in object file
uchar local; // created in this file
uchar uniq; // imbedded field name first found
uchar siggen; // signature generated
char* opackage; // original package name
char* package; // package name
@ -596,11 +598,10 @@ int isptrdarray(Type*);
int isinter(Type*);
int isnilinter(Type*);
int isddd(Type*);
Sym* globalsig(Type*);
Type* ismethod(Type*);
Type* methtype(Type*);
int needaddr(Type*);
Sym* signame(Type*, int);
Sym* signame(Type*);
int bytearraysz(Type*);
int eqtype(Type*, Type*, int);
void argtype(Node*, Type*);

View File

@ -1606,134 +1606,53 @@ iscomposite(Type *t)
}
Sym*
globalsig(Type *t)
signame(Type *t)
{
int et;
Sym *s;
char buf[NSYMB];
char *sigx;
if(t == T)
return S;
et = t->etype;
switch(et) {
default:
return S;
case TINTER:
case TDDD:
if(isnilinter(t)) {
sigx = "sigi";
strcpy(buf, "inter");
goto out;
}
return S;
case TPTR32:
case TPTR64:
if(isptrto(t, TSTRING)) {
et = TSTRING;
break;
}
return S;
case TINT:
case TINT8:
case TINT16:
case TINT32:
case TINT64:
case TUINT:
case TUINT8:
case TUINT16:
case TUINT32:
case TUINT64:
case TUINTPTR:
case TFLOAT:
case TFLOAT32:
case TFLOAT64:
case TFLOAT80:
case TBOOL:
break;
}
if(t->sym == S)
return S;
if(t->method != T)
return S;
if(strcmp(t->sym->name, types[et]->sym->name) != 0)
return S;
sigx = "sigt";
snprint(buf, sizeof(buf), "%#T", t);
out:
s = pkglookup(buf, sigx);
if(s->oname == N) {
s->oname = newname(s);
s->oname->type = types[TUINT8];
s->oname->class = PEXTERN;
s->local = s->local;
}
//print("*** %lT %lS\n", t, s);
return s;
}
Sym*
signame(Type *t, int block)
{
Sym *s, *ss;
Sym *ss;
char *e;
Dcl *x;
char buf[NSYMB];
//print("signame %T\n", t);
if(t == T)
goto bad;
ss = globalsig(t);
if(ss != S)
return ss;
s = t->sym;
if(s == S) {
if(isptr[t->etype]) {
t = t->type;
if(t == T)
goto bad;
}
s = t->sym;
if(s == S)
goto bad;
}
e = "sigt";
if(t->etype == TINTER)
e = "sigi";
if(block == 0)
block = s->tblock;
if(block > 1) {
// record internal type for signature generation
x = mal(sizeof(*x));
x->op = OTYPE;
x->dsym = s;
x->dtype = s->otype;
x->forw = signatlist;
x->block = block;
signatlist = x;
}
// name is exported name, like *[]byte or *Struct or Interface
// (special symbols don't bother the linker).
snprint(buf, sizeof(buf), "%#T", t);
// special case: empty interface is named sigi.empty
// so that it can be referred to by the runtime.
if(strcmp(buf, "interface { }") == 0)
strcpy(buf, "empty");
ss = pkglookup(buf, e);
if(ss->oname == N) {
ss->oname = newname(ss);
ss->oname->type = types[TUINT8];
ss->oname->class = PEXTERN;
ss->local = s->local;
//print("signame: %d %lS\n", ss->local, ss);
}
if(!t->siggen) {
//print("siggen %T\n", t);
// special case: don't generate the empty interface
if(strcmp(buf, "empty") == 0)
goto out;
// record internal type for signature generation
x = mal(sizeof(*x));
x->op = OTYPE;
x->dtype = t;
x->forw = signatlist;
t->siggen = 1;
signatlist = x;
}
out:
return ss;
bad:

View File

@ -919,10 +919,10 @@ loop:
nnew = nod(ONEW, N, N);
nnew->type = nvar->type;
nnew = newcompat(nnew);
nas = nod(OAS, nvar, nnew);
addtop = list(addtop, nas);
nas = nod(OAS, nod(OIND, nvar, N), n->left);
addtop = list(addtop, nas);
@ -1761,7 +1761,7 @@ loop:
return N;
}
more:
a = nod(OAS, nodarg(l, fp), r);
a = convas(a);
nn = list(a, nn);
@ -1786,6 +1786,8 @@ ascompat(Type *t1, Type *t2)
// if(eqtype(t2, nilptr, 0))
// return 1;
if(isnilinter(t1))
return 1;
if(isinter(t1)) {
if(isinter(t2))
return 1;
@ -1793,6 +1795,8 @@ ascompat(Type *t1, Type *t2)
return 1;
}
if(isnilinter(t2))
return 1;
if(isinter(t2))
if(ismethod(t1))
return 1;
@ -2649,13 +2653,13 @@ isandss(Type *lt, Node *r)
return I2I;
return Inone;
}
if(ismethod(rt) != T)
if(isnilinter(lt) || ismethod(rt) != T)
return T2I;
return Inone;
}
if(isinter(rt)) {
if(ismethod(lt) != T)
if(isnilinter(rt) || ismethod(lt) != T)
return I2T;
return Inone;
}
@ -2682,7 +2686,7 @@ ifaceop(Type *tl, Node *n, int op)
a = n; // interface
r = a;
s = signame(tl, 0); // sigi
s = signame(tl); // sigi
if(s == S)
fatal("ifaceop: signame I2T");
a = s->oname;
@ -2701,14 +2705,14 @@ ifaceop(Type *tl, Node *n, int op)
a = n; // elem
r = a;
s = signame(tr, 0); // sigt
s = signame(tr); // sigt
if(s == S)
fatal("ifaceop: signame-1 T2I: %lT", tr);
a = s->oname;
a = nod(OADDR, a, N);
r = list(a, r);
s = signame(tl, 0); // sigi
s = signame(tl); // sigi
if(s == S) {
fatal("ifaceop: signame-2 T2I: %lT", tl);
}
@ -2728,7 +2732,7 @@ ifaceop(Type *tl, Node *n, int op)
a = n; // interface
r = a;
s = signame(tl, 0); // sigi
s = signame(tl); // sigi
if(s == S)
fatal("ifaceop: signame I2I");
a = s->oname;

View File

@ -45,31 +45,7 @@ struct Map
static Map* hash[1009];
#define END nil,0,0,nil
Sigi sigi·inter[2] = { (byte*)"interface {}", 0, 0, nil, 0, 0 };
Sigt sigt·int8[2] = { (byte*)"int8", ASIMP, 1, nil, END };
Sigt sigt·int16[2] = { (byte*)"int16", ASIMP, 2, nil, END };
Sigt sigt·int32[2] = { (byte*)"int32", ASIMP, 4, nil, END };
Sigt sigt·int64[2] = { (byte*)"int64", ASIMP, 8, nil, END };
Sigt sigt·uint8[2] = { (byte*)"uint8", ASIMP, 1, nil, END };
Sigt sigt·uint16[2] = { (byte*)"uint16", ASIMP, 2, nil, END };
Sigt sigt·uint32[2] = { (byte*)"uint32", ASIMP, 4, nil, END };
Sigt sigt·uint64[2] = { (byte*)"uint64", ASIMP, 8, nil, END };
Sigt sigt·float32[2] = { (byte*)"float32", ASIMP, 4, nil, END };
Sigt sigt·float64[2] = { (byte*)"float64", ASIMP, 8, nil, END };
//Sigt sigt·float80[2] = { (byte*)"float80", ASIMP, 0, nil, END };
Sigt sigt·bool[2] = { (byte*)"bool", ASIMP, 1, nil, END };
Sigt sigt·string[2] = { (byte*)"string", ASTRING, 8, nil, END };
Sigt sigt·int[2] = { (byte*)"int", ASIMP, 4, nil, END };
Sigt sigt·uint[2] = { (byte*)"uint", ASIMP, 4, nil, END };
Sigt sigt·uintptr[2] = { (byte*)"uintptr", ASIMP, 8, nil, END };
Sigt sigt·float[2] = { (byte*)"float", ASIMP, 4, nil, END };
Sigi sigi·empty[2] = { (byte*)"interface { }" };
static void
printsigi(Sigi *si)
@ -506,7 +482,7 @@ sys·unreflect(uint64 it, string type, Map *retim, void *retit)
retim = 0;
retit = 0;
} else {
retim = hashmap(sigi·inter, findtype(type), 0);
retim = hashmap(sigi·empty, findtype(type), 0);
retit = (void*)it;
}
FLUSH(&retim);