diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c index 8b2a47c24e..20763cf38f 100644 --- a/src/cmd/6g/obj.c +++ b/src/cmd/6g/obj.c @@ -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; dforw) { - 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; + } } diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index faf5025a80..b9e8dd37a3 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -113,6 +113,7 @@ struct Sym 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 8c001e7481..bc7413fe15 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -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 diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 025edaad7f..7e4e22c87b 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -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*); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 15650c8be4..b6e225f81c 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -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: diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index f0627d4f5b..ceae4480a5 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -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; diff --git a/src/runtime/iface.c b/src/runtime/iface.c index 10a4c53417..dba4c03933 100644 --- a/src/runtime/iface.c +++ b/src/runtime/iface.c @@ -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);