From 5136a9e1f7ed5fbeaa7d48641ae8c28c513727ae Mon Sep 17 00:00:00 2001 From: Ken Thompson Date: Mon, 16 Mar 2009 15:27:08 -0700 Subject: [PATCH] change format of Sigt and Sigi to allow room for type hash needed for log-time type switch. R=r OCL=26354 CL=26354 --- src/cmd/6g/obj.c | 82 ++++++++++++++-------- src/cmd/gc/subr.c | 5 -- src/runtime/iface.c | 167 +++++++++++++++++++++++++------------------- 3 files changed, 147 insertions(+), 107 deletions(-) diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c index 02f987de0f..50d7244a42 100644 --- a/src/cmd/6g/obj.c +++ b/src/cmd/6g/obj.c @@ -470,7 +470,7 @@ sigcmp(Sig *a, Sig *b) } static Addr at, ao, ac, ad; -static int wi, ot; +static int wi, ws, ot; void ginsatoa(int fscale, int toffset) @@ -622,7 +622,26 @@ out: * 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) { @@ -642,7 +661,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) a = nil; o = 0; oldlist = nil; - sighash = 0; + sighash = typehash(progt, 0); for(f=methodt->method; f!=T; f=f->down) { if(f->type->etype != TFUNC) continue; @@ -688,8 +707,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) newname = a->sym; oldname = methodsym(method, oldthis); genptrtramp(method, oldname, oldthis, f->type, newname, newthis); - } - else if(f->embedded) { + } else + if(f->embedded) { // TODO(rsc): only works for pointer receivers if(oldlist == nil) oldlist = pc; @@ -713,38 +732,23 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ot = 0; ot = rnd(ot, maxround); // base structure - // sigt[0].name = "" - ginsatoa(widthptr, stringo); + // base of type signature contains parameters + ginsatoa(widthptr, stringo); // name + ot = rnd(ot, widthptr)+widthptr; // skip link + gensatac(wi, typehash(progt, 0)); // thash + gensatac(wi, sighash); // mhash + gensatac(ws, progt->width); // width + gensatac(ws, algtype(progt)); // algorithm - // save type name for runtime error message. snprint(buf, sizeof buf, "%#T", progt); datastring(buf, strlen(buf)+1); - // first field of an type signature contains - // the element parameters and is not a real entry - // sigt[0].hash = elemalg + sighash<<8 - gensatac(wi, algtype(progt) + (sighash<<8)); - - // sigt[0].offset = width - gensatac(wi, progt->width); - - // skip the function - gensatac(widthptr, 0); - for(b=a; b!=nil; b=b->link) { - ot = rnd(ot, maxround); // base structure - - // sigt[++].name = "fieldname" - ginsatoa(widthptr, stringo); - - // sigt[++].hash = hashcode - gensatac(wi, b->hash); - - // sigt[++].offset = of embedded struct - gensatac(wi, 0); - - // sigt[++].fun = &method - gensatad(b->sym); + 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); } @@ -765,6 +769,20 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) p->to.offset = ot; } +/* + * 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) { @@ -875,6 +893,7 @@ dumpsignatures(void) memset(&ad, 0, sizeof(ad)); wi = types[TINT32]->width; + ws = types[TINT16]->width; // sig structure at.type = D_EXTERN; @@ -986,6 +1005,7 @@ dumpsignatures(void) if(methodt->method && methodt->sym && !methodt->local) continue; +//print("s=%S\n", s); dumpsigt(progt, ifacet, rcvrt, methodt, s); } diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 80405e37cd..a112849a8e 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -1929,10 +1929,6 @@ typehash(Type *at, int d) if(d >= 5) return PRIME3; - if(at->recur) - return 0; - at->recur = 1; - h = at->etype*PRIME4; switch(at->etype) { @@ -1961,7 +1957,6 @@ typehash(Type *at, int d) break; } - at->recur = 0; return h; } diff --git a/src/runtime/iface.c b/src/runtime/iface.c index 34c4a2da8b..5526ca7ecf 100644 --- a/src/runtime/iface.c +++ b/src/runtime/iface.c @@ -15,17 +15,31 @@ typedef struct Itype Itype; */ struct Sigt { - byte* name; - uint32 hash; // hash of type // first is alg - uint32 offset; // offset of substruct // first is width - void (*fun)(void); + 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 }; struct Sigi { byte* name; uint32 hash; - uint32 perm; // location of fun in Sigt // first is size + 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 }; struct Itype @@ -52,10 +66,10 @@ printsigi(Sigi *si) sys·printpointer(si); prints("{"); - prints((int8*)si[0].name); + prints((int8*)si->name); prints(":"); - for(i=1;; i++) { - name = si[i].name; + for(i=0;; i++) { + name = si->meth[i].fname; if(name == nil) break; prints("["); @@ -63,9 +77,9 @@ printsigi(Sigi *si) prints("]\""); prints((int8*)name); prints("\""); - sys·printint(si[i].hash%999); + sys·printint(si->meth[i].fhash%999); prints("/"); - sys·printint(si[i].perm); + sys·printint(si->meth[i].perm); } prints("}"); } @@ -78,13 +92,17 @@ printsigt(Sigt *st) sys·printpointer(st); prints("{"); - prints((int8*)st[0].name); + prints((int8*)st->name); prints(":"); - sys·printint(st[0].hash); // first element has alg + sys·printint(st->thash%999); // type hash + prints(","); + sys·printint(st->mhash%999); // method hash + prints(","); + sys·printint(st->width); // width prints(","); - sys·printint(st[0].offset); // first element has width - for(i=1;; i++) { - name = st[i].name; + sys·printint(st->alg); // algorithm + for(i=0;; i++) { + name = st->meth[i].fname; if(name == nil) break; prints("["); @@ -92,11 +110,11 @@ printsigt(Sigt *st) prints("]\""); prints((int8*)name); prints("\""); - sys·printint(st[i].hash%999); + sys·printint(st->meth[i].fhash%999); prints("/"); - sys·printint(st[i].offset); + sys·printint(st->meth[i].offset); prints("/"); - sys·printpointer(st[i].fun); + sys·printpointer(st->meth[i].fun); } prints("}"); } @@ -124,8 +142,11 @@ itype(Sigi *si, Sigt *st, int32 canfail) h = 0; if(si) h += si->hash; - if(st) - h += st->hash >> 8; + if(st) { + h += st->thash; + h += st->mhash; + } + h %= nelem(hash); // look twice - once without lock, once with. @@ -156,30 +177,30 @@ itype(Sigi *si, Sigt *st, int32 canfail) } } - ni = si[0].perm; // first entry has size + ni = si->size; m = mal(sizeof(*m) + ni*sizeof(m->fun[0])); m->sigi = si; m->sigt = st; throw: - nt = 1; - for(ni=1;; ni++) { // ni=1: skip first word - iname = si[ni].name; + nt = 0; + for(ni=0;; ni++) { + iname = si->meth[ni].fname; if(iname == nil) break; // pick up next name from // interface signature - ihash = si[ni].hash; + ihash = si->meth[ni].fhash; for(;; nt++) { // pick up and compare next name // from structure signature - sname = st[nt].name; + sname = st->meth[nt].fname; if(sname == nil) { if(!canfail) { printf("cannot convert type %s to interface %s: missing method %s\n", - st[0].name, si[0].name, iname); + st->name, si->name, iname); if(iface_debug) { prints("interface"); printsigi(si); @@ -196,16 +217,17 @@ throw: unlock(&ifacelock); return nil; } - if(ihash == st[nt].hash && strcmp(sname, iname) == 0) + if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0) break; } - m->fun[si[ni].perm] = st[nt].fun; + m->fun[si->meth[ni].perm] = st->meth[nt].fun; } m->link = hash[h]; hash[h] = m; - // printf("new itype %p\n", m); if(locked) unlock(&ifacelock); + + // printf("new itype %p\n", m); return m; } @@ -218,9 +240,6 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) int32 alg, wid; elem = (byte*)(&st+1); - wid = st->offset; - ret = (Iface*)(elem + rnd(wid, 8)); - ret->type = itype(si, st, 0); if(iface_debug) { prints("T2I sigi="); @@ -232,11 +251,14 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) prints("\n"); } - alg = st->hash & 0xFF; - wid = st->offset; - if(wid <= sizeof ret->data) + wid = st->width; + alg = st->alg; + ret = (Iface*)(elem + rnd(wid, 8)); + ret->type = itype(si, st, 0); + + if(wid <= sizeof(ret->data)) algarray[alg].copy(wid, &ret->data, elem); - else{ + else { ret->data = mal(wid); if(iface_debug) printf("T2I mal %d %p\n", wid, ret->data); @@ -273,24 +295,24 @@ sys·ifaceI2T(Sigt *st, Iface i, ...) im = i.type; if(im == nil) { prints("interface is nil, not "); - prints((int8*)st[0].name); + prints((int8*)st->name); prints("\n"); throw("interface conversion"); } if(im->sigt != st) { - prints((int8*)im->sigi[0].name); + prints((int8*)im->sigi->name); prints(" is "); - prints((int8*)im->sigt[0].name); + prints((int8*)im->sigt->name); prints(", not "); - prints((int8*)st[0].name); + prints((int8*)st->name); prints("\n"); throw("interface conversion"); } - alg = st->hash & 0xFF; - wid = st->offset; - if(wid <= sizeof i.data) + alg = st->alg; + wid = st->width; + if(wid <= sizeof(i.data)) algarray[alg].copy(wid, ret, &i.data); else algarray[alg].copy(wid, ret, i.data); @@ -312,10 +334,6 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) Itype *im; int32 alg, wid; - ret = (byte*)(&i+1); - alg = st->hash & 0xFF; - wid = st->offset; - ok = (bool*)(ret+rnd(wid, 1)); if(iface_debug) { prints("I2T2 sigt="); @@ -325,13 +343,18 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) prints("\n"); } + ret = (byte*)(&i+1); + alg = st->alg; + wid = st->width; + ok = (bool*)(ret+rnd(wid, 1)); + im = i.type; if(im == nil || im->sigt != st) { *ok = false; sys·memclr(ret, wid); } else { *ok = true; - if(wid <= sizeof i.data) + if(wid <= sizeof(i.data)) algarray[alg].copy(wid, ret, &i.data); else algarray[alg].copy(wid, ret, i.data); @@ -424,21 +447,23 @@ uint64 ifacehash(Iface a) { int32 alg, wid; + Sigt *sigt; if(a.type == nil) return 0; - alg = a.type->sigt->hash & 0xFF; - wid = a.type->sigt->offset; + + sigt = a.type->sigt; + alg = sigt->alg; + wid = sigt->width; if(algarray[alg].hash == nohash) { // calling nohash will throw too, // but we can print a better error. - printf("hash of unhashable type %s\n", a.type->sigt->name); + printf("hash of unhashable type %s\n", sigt->name); throw("interface hash"); } - if(wid <= sizeof a.data) + if(wid <= sizeof(a.data)) return algarray[alg].hash(wid, &a.data); - else - return algarray[alg].hash(wid, a.data); + return algarray[alg].hash(wid, a.data); } bool @@ -470,8 +495,8 @@ ifaceeq(Iface i1, Iface i2) if(i1.type->sigt != i2.type->sigt) goto no; - alg = i1.type->sigt->hash & 0xFF; - wid = i1.type->sigt->offset; + alg = i1.type->sigt->alg; + wid = i1.type->sigt->width; if(algarray[alg].equal == noequal) { // calling noequal will throw too, @@ -480,7 +505,7 @@ ifaceeq(Iface i1, Iface i2) throw("interface compare"); } - if(wid <= sizeof i1.data) { + if(wid <= sizeof(i1.data)) { if(!algarray[alg].equal(wid, &i1.data, &i2.data)) goto no; } else { @@ -525,8 +550,8 @@ sys·Reflect(Iface i, uint64 retit, string rettype, bool retindir) } else { retit = (uint64)i.data; rettype = gostring(i.type->sigt->name); - wid = i.type->sigt->offset; - retindir = wid > sizeof i.data; + wid = i.type->sigt->width; + retindir = wid > sizeof(i.data); } FLUSH(&retit); FLUSH(&rettype); @@ -568,7 +593,7 @@ extern int32 ngotypesigs; // signature with type string "[]int" in gotypesigs, and unreflect // wouldn't call fakesigt. -static Sigt *fake[1009]; +static Sigt* fake[1009]; static int32 nfake; static Sigt* @@ -590,7 +615,7 @@ fakesigt(string type, bool indir) for(locked=0; locked<2; locked++) { if(locked) lock(&ifacelock); - for(sigt = fake[h]; sigt != nil; sigt = (Sigt*)sigt->fun) { + for(sigt = fake[h]; sigt != nil; sigt = sigt->link) { // don't need to compare indir. // same type string but different indir will have // different hashes. @@ -603,16 +628,16 @@ fakesigt(string type, bool indir) } } - sigt = mal(2*sizeof sigt[0]); - sigt[0].name = mal(type->len + 1); - mcpy(sigt[0].name, type->str, type->len); - sigt[0].hash = AFAKE; // alg + sigt = mal(sizeof(*sigt)); + sigt->name = mal(type->len + 1); + mcpy(sigt->name, type->str, type->len); + sigt->alg = AFAKE; + sigt->width = 1; // small width if(indir) - sigt[0].offset = 2*sizeof(niliface.data); // big width - else - sigt[0].offset = 1; // small width - sigt->fun = (void*)fake[h]; + sigt->width = 2*sizeof(niliface.data); // big width + sigt->link = fake[h]; fake[h] = sigt; + unlock(&ifacelock); return sigt; } @@ -672,7 +697,7 @@ sys·Unreflect(uint64 it, string type, bool indir, Iface ret) // if we think the type should be indirect // and caller does not, play it safe, return nil. sigt = findtype(type, indir); - if(indir != (sigt[0].offset > sizeof ret.data)) + if(indir != (sigt->width > sizeof(ret.data))) goto out; ret.type = itype(sigi·empty, sigt, 0); -- 2.48.1