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
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
index 8b2a47c..20763cf 100644
--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -516,7 +516,6 @@
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 @@
}
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 @@
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;
+ }
}
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index faf5025..b9e8dd3 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -113,6 +113,7 @@
short become;
short frame;
uchar subtype;
+ uchar dupok;
ushort file;
vlong value;
int32 sig;
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 8c001e7..bc7413f 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -972,6 +972,8 @@
}
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 @@
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
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 025edaa..7e4e22c 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -125,6 +125,7 @@
uchar methptr; // 1=direct 2=pointer
uchar printed;
uchar embedded; // TFIELD embedded type
+ uchar siggen;
// TFUNCT
uchar thistuple;
@@ -208,6 +209,7 @@
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 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*);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 15650c8..b6e225f 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -1606,134 +1606,53 @@
}
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:
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index f0627d4..ceae448 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -919,10 +919,10 @@
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 @@
return N;
}
-more:
+
a = nod(OAS, nodarg(l, fp), r);
a = convas(a);
nn = list(a, nn);
@@ -1786,6 +1786,8 @@
// if(eqtype(t2, nilptr, 0))
// return 1;
+ if(isnilinter(t1))
+ return 1;
if(isinter(t1)) {
if(isinter(t2))
return 1;
@@ -1793,6 +1795,8 @@
return 1;
}
+ if(isnilinter(t2))
+ return 1;
if(isinter(t2))
if(ismethod(t1))
return 1;
@@ -2649,13 +2653,13 @@
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 @@
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 @@
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 @@
a = n; // interface
r = a;
- s = signame(tl, 0); // sigi
+ s = signame(tl); // sigi
if(s == S)
fatal("ifaceop: signame I2I");
a = s->oname;
diff --git a/src/runtime/iface.c b/src/runtime/iface.c
index 10a4c53..dba4c03 100644
--- a/src/runtime/iface.c
+++ b/src/runtime/iface.c
@@ -45,31 +45,7 @@
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 @@
retim = 0;
retit = 0;
} else {
- retim = hashmap(sigi·inter, findtype(type), 0);
+ retim = hashmap(sigi·empty, findtype(type), 0);
retit = (void*)it;
}
FLUSH(&retim);