Commit 5136a9e1 authored by Ken Thompson's avatar Ken Thompson

change format of Sigt and Sigi

to allow room for type hash
needed for log-time type switch.

R=r
OCL=26354
CL=26354
parent 1b141ca0
...@@ -470,7 +470,7 @@ sigcmp(Sig *a, Sig *b) ...@@ -470,7 +470,7 @@ sigcmp(Sig *a, Sig *b)
} }
static Addr at, ao, ac, ad; static Addr at, ao, ac, ad;
static int wi, ot; static int wi, ws, ot;
void void
ginsatoa(int fscale, int toffset) ginsatoa(int fscale, int toffset)
...@@ -622,7 +622,26 @@ out: ...@@ -622,7 +622,26 @@ out:
* rcvrt - type used as method interface. eqtype(ifacet, rcvrt) is always true, * rcvrt - type used as method interface. eqtype(ifacet, rcvrt) is always true,
* but ifacet might have a name that rcvrt does not. * but ifacet might have a name that rcvrt does not.
* methodt - type with methods hanging off it (progt==*methodt sometimes) * 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 void
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) 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) ...@@ -642,7 +661,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
a = nil; a = nil;
o = 0; o = 0;
oldlist = nil; oldlist = nil;
sighash = 0; sighash = typehash(progt, 0);
for(f=methodt->method; f!=T; f=f->down) { for(f=methodt->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC) if(f->type->etype != TFUNC)
continue; continue;
...@@ -688,8 +707,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -688,8 +707,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
newname = a->sym; newname = a->sym;
oldname = methodsym(method, oldthis); oldname = methodsym(method, oldthis);
genptrtramp(method, oldname, oldthis, f->type, newname, newthis); genptrtramp(method, oldname, oldthis, f->type, newname, newthis);
} } else
else if(f->embedded) { if(f->embedded) {
// TODO(rsc): only works for pointer receivers // TODO(rsc): only works for pointer receivers
if(oldlist == nil) if(oldlist == nil)
oldlist = pc; oldlist = pc;
...@@ -713,38 +732,23 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -713,38 +732,23 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
ot = 0; ot = 0;
ot = rnd(ot, maxround); // base structure ot = rnd(ot, maxround); // base structure
// sigt[0].name = "" // base of type signature contains parameters
ginsatoa(widthptr, stringo); 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); snprint(buf, sizeof buf, "%#T", progt);
datastring(buf, strlen(buf)+1); 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) { for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base structure ot = rnd(ot, maxround); // base of substructure
ginsatoa(widthptr, stringo); // field name
// sigt[++].name = "fieldname" gensatac(wi, b->hash); // hash
ginsatoa(widthptr, stringo); gensatac(wi, 0); // offset
gensatad(b->sym); // &method
// sigt[++].hash = hashcode
gensatac(wi, b->hash);
// sigt[++].offset = of embedded struct
gensatac(wi, 0);
// sigt[++].fun = &method
gensatad(b->sym);
datastring(b->name, strlen(b->name)+1); datastring(b->name, strlen(b->name)+1);
} }
...@@ -765,6 +769,20 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -765,6 +769,20 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
p->to.offset = ot; 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 void
dumpsigi(Type *t, Sym *s) dumpsigi(Type *t, Sym *s)
{ {
...@@ -875,6 +893,7 @@ dumpsignatures(void) ...@@ -875,6 +893,7 @@ dumpsignatures(void)
memset(&ad, 0, sizeof(ad)); memset(&ad, 0, sizeof(ad));
wi = types[TINT32]->width; wi = types[TINT32]->width;
ws = types[TINT16]->width;
// sig structure // sig structure
at.type = D_EXTERN; at.type = D_EXTERN;
...@@ -986,6 +1005,7 @@ dumpsignatures(void) ...@@ -986,6 +1005,7 @@ dumpsignatures(void)
if(methodt->method && methodt->sym && !methodt->local) if(methodt->method && methodt->sym && !methodt->local)
continue; continue;
//print("s=%S\n", s);
dumpsigt(progt, ifacet, rcvrt, methodt, s); dumpsigt(progt, ifacet, rcvrt, methodt, s);
} }
......
...@@ -1929,10 +1929,6 @@ typehash(Type *at, int d) ...@@ -1929,10 +1929,6 @@ typehash(Type *at, int d)
if(d >= 5) if(d >= 5)
return PRIME3; return PRIME3;
if(at->recur)
return 0;
at->recur = 1;
h = at->etype*PRIME4; h = at->etype*PRIME4;
switch(at->etype) { switch(at->etype) {
...@@ -1961,7 +1957,6 @@ typehash(Type *at, int d) ...@@ -1961,7 +1957,6 @@ typehash(Type *at, int d)
break; break;
} }
at->recur = 0;
return h; return h;
} }
......
...@@ -15,17 +15,31 @@ typedef struct Itype Itype; ...@@ -15,17 +15,31 @@ typedef struct Itype Itype;
*/ */
struct Sigt struct Sigt
{ {
byte* name; byte* name; // name of basic type
uint32 hash; // hash of type // first is alg Sigt* link; // for linking into hash tables
uint32 offset; // offset of substruct // first is width uint32 thash; // hash of type
void (*fun)(void); 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 struct Sigi
{ {
byte* name; byte* name;
uint32 hash; 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 struct Itype
...@@ -52,10 +66,10 @@ printsigi(Sigi *si) ...@@ -52,10 +66,10 @@ printsigi(Sigi *si)
sys·printpointer(si); sys·printpointer(si);
prints("{"); prints("{");
prints((int8*)si[0].name); prints((int8*)si->name);
prints(":"); prints(":");
for(i=1;; i++) { for(i=0;; i++) {
name = si[i].name; name = si->meth[i].fname;
if(name == nil) if(name == nil)
break; break;
prints("["); prints("[");
...@@ -63,9 +77,9 @@ printsigi(Sigi *si) ...@@ -63,9 +77,9 @@ printsigi(Sigi *si)
prints("]\""); prints("]\"");
prints((int8*)name); prints((int8*)name);
prints("\""); prints("\"");
sys·printint(si[i].hash%999); sys·printint(si->meth[i].fhash%999);
prints("/"); prints("/");
sys·printint(si[i].perm); sys·printint(si->meth[i].perm);
} }
prints("}"); prints("}");
} }
...@@ -78,13 +92,17 @@ printsigt(Sigt *st) ...@@ -78,13 +92,17 @@ printsigt(Sigt *st)
sys·printpointer(st); sys·printpointer(st);
prints("{"); prints("{");
prints((int8*)st[0].name); prints((int8*)st->name);
prints(":"); 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(","); prints(",");
sys·printint(st[0].offset); // first element has width sys·printint(st->alg); // algorithm
for(i=1;; i++) { for(i=0;; i++) {
name = st[i].name; name = st->meth[i].fname;
if(name == nil) if(name == nil)
break; break;
prints("["); prints("[");
...@@ -92,11 +110,11 @@ printsigt(Sigt *st) ...@@ -92,11 +110,11 @@ printsigt(Sigt *st)
prints("]\""); prints("]\"");
prints((int8*)name); prints((int8*)name);
prints("\""); prints("\"");
sys·printint(st[i].hash%999); sys·printint(st->meth[i].fhash%999);
prints("/"); prints("/");
sys·printint(st[i].offset); sys·printint(st->meth[i].offset);
prints("/"); prints("/");
sys·printpointer(st[i].fun); sys·printpointer(st->meth[i].fun);
} }
prints("}"); prints("}");
} }
...@@ -124,8 +142,11 @@ itype(Sigi *si, Sigt *st, int32 canfail) ...@@ -124,8 +142,11 @@ itype(Sigi *si, Sigt *st, int32 canfail)
h = 0; h = 0;
if(si) if(si)
h += si->hash; h += si->hash;
if(st) if(st) {
h += st->hash >> 8; h += st->thash;
h += st->mhash;
}
h %= nelem(hash); h %= nelem(hash);
// look twice - once without lock, once with. // look twice - once without lock, once with.
...@@ -156,30 +177,30 @@ itype(Sigi *si, Sigt *st, int32 canfail) ...@@ -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 = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
m->sigi = si; m->sigi = si;
m->sigt = st; m->sigt = st;
throw: throw:
nt = 1; nt = 0;
for(ni=1;; ni++) { // ni=1: skip first word for(ni=0;; ni++) {
iname = si[ni].name; iname = si->meth[ni].fname;
if(iname == nil) if(iname == nil)
break; break;
// pick up next name from // pick up next name from
// interface signature // interface signature
ihash = si[ni].hash; ihash = si->meth[ni].fhash;
for(;; nt++) { for(;; nt++) {
// pick up and compare next name // pick up and compare next name
// from structure signature // from structure signature
sname = st[nt].name; sname = st->meth[nt].fname;
if(sname == nil) { if(sname == nil) {
if(!canfail) { if(!canfail) {
printf("cannot convert type %s to interface %s: missing method %s\n", 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) { if(iface_debug) {
prints("interface"); prints("interface");
printsigi(si); printsigi(si);
...@@ -196,16 +217,17 @@ throw: ...@@ -196,16 +217,17 @@ throw:
unlock(&ifacelock); unlock(&ifacelock);
return nil; return nil;
} }
if(ihash == st[nt].hash && strcmp(sname, iname) == 0) if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0)
break; break;
} }
m->fun[si[ni].perm] = st[nt].fun; m->fun[si->meth[ni].perm] = st->meth[nt].fun;
} }
m->link = hash[h]; m->link = hash[h];
hash[h] = m; hash[h] = m;
// printf("new itype %p\n", m);
if(locked) if(locked)
unlock(&ifacelock); unlock(&ifacelock);
// printf("new itype %p\n", m);
return m; return m;
} }
...@@ -218,9 +240,6 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) ...@@ -218,9 +240,6 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...)
int32 alg, wid; int32 alg, wid;
elem = (byte*)(&st+1); elem = (byte*)(&st+1);
wid = st->offset;
ret = (Iface*)(elem + rnd(wid, 8));
ret->type = itype(si, st, 0);
if(iface_debug) { if(iface_debug) {
prints("T2I sigi="); prints("T2I sigi=");
...@@ -232,11 +251,14 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) ...@@ -232,11 +251,14 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...)
prints("\n"); prints("\n");
} }
alg = st->hash & 0xFF; wid = st->width;
wid = st->offset; alg = st->alg;
if(wid <= sizeof ret->data) ret = (Iface*)(elem + rnd(wid, 8));
ret->type = itype(si, st, 0);
if(wid <= sizeof(ret->data))
algarray[alg].copy(wid, &ret->data, elem); algarray[alg].copy(wid, &ret->data, elem);
else{ else {
ret->data = mal(wid); ret->data = mal(wid);
if(iface_debug) if(iface_debug)
printf("T2I mal %d %p\n", wid, ret->data); printf("T2I mal %d %p\n", wid, ret->data);
...@@ -273,24 +295,24 @@ sys·ifaceI2T(Sigt *st, Iface i, ...) ...@@ -273,24 +295,24 @@ sys·ifaceI2T(Sigt *st, Iface i, ...)
im = i.type; im = i.type;
if(im == nil) { if(im == nil) {
prints("interface is nil, not "); prints("interface is nil, not ");
prints((int8*)st[0].name); prints((int8*)st->name);
prints("\n"); prints("\n");
throw("interface conversion"); throw("interface conversion");
} }
if(im->sigt != st) { if(im->sigt != st) {
prints((int8*)im->sigi[0].name); prints((int8*)im->sigi->name);
prints(" is "); prints(" is ");
prints((int8*)im->sigt[0].name); prints((int8*)im->sigt->name);
prints(", not "); prints(", not ");
prints((int8*)st[0].name); prints((int8*)st->name);
prints("\n"); prints("\n");
throw("interface conversion"); throw("interface conversion");
} }
alg = st->hash & 0xFF; alg = st->alg;
wid = st->offset; wid = st->width;
if(wid <= sizeof i.data) if(wid <= sizeof(i.data))
algarray[alg].copy(wid, ret, &i.data); algarray[alg].copy(wid, ret, &i.data);
else else
algarray[alg].copy(wid, ret, i.data); algarray[alg].copy(wid, ret, i.data);
...@@ -312,10 +334,6 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ...@@ -312,10 +334,6 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
Itype *im; Itype *im;
int32 alg, wid; int32 alg, wid;
ret = (byte*)(&i+1);
alg = st->hash & 0xFF;
wid = st->offset;
ok = (bool*)(ret+rnd(wid, 1));
if(iface_debug) { if(iface_debug) {
prints("I2T2 sigt="); prints("I2T2 sigt=");
...@@ -325,13 +343,18 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ...@@ -325,13 +343,18 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
prints("\n"); prints("\n");
} }
ret = (byte*)(&i+1);
alg = st->alg;
wid = st->width;
ok = (bool*)(ret+rnd(wid, 1));
im = i.type; im = i.type;
if(im == nil || im->sigt != st) { if(im == nil || im->sigt != st) {
*ok = false; *ok = false;
sys·memclr(ret, wid); sys·memclr(ret, wid);
} else { } else {
*ok = true; *ok = true;
if(wid <= sizeof i.data) if(wid <= sizeof(i.data))
algarray[alg].copy(wid, ret, &i.data); algarray[alg].copy(wid, ret, &i.data);
else else
algarray[alg].copy(wid, ret, i.data); algarray[alg].copy(wid, ret, i.data);
...@@ -424,21 +447,23 @@ uint64 ...@@ -424,21 +447,23 @@ uint64
ifacehash(Iface a) ifacehash(Iface a)
{ {
int32 alg, wid; int32 alg, wid;
Sigt *sigt;
if(a.type == nil) if(a.type == nil)
return 0; 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) { if(algarray[alg].hash == nohash) {
// calling nohash will throw too, // calling nohash will throw too,
// but we can print a better error. // 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"); throw("interface hash");
} }
if(wid <= sizeof a.data) if(wid <= sizeof(a.data))
return algarray[alg].hash(wid, &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 bool
...@@ -470,8 +495,8 @@ ifaceeq(Iface i1, Iface i2) ...@@ -470,8 +495,8 @@ ifaceeq(Iface i1, Iface i2)
if(i1.type->sigt != i2.type->sigt) if(i1.type->sigt != i2.type->sigt)
goto no; goto no;
alg = i1.type->sigt->hash & 0xFF; alg = i1.type->sigt->alg;
wid = i1.type->sigt->offset; wid = i1.type->sigt->width;
if(algarray[alg].equal == noequal) { if(algarray[alg].equal == noequal) {
// calling noequal will throw too, // calling noequal will throw too,
...@@ -480,7 +505,7 @@ ifaceeq(Iface i1, Iface i2) ...@@ -480,7 +505,7 @@ ifaceeq(Iface i1, Iface i2)
throw("interface compare"); throw("interface compare");
} }
if(wid <= sizeof i1.data) { if(wid <= sizeof(i1.data)) {
if(!algarray[alg].equal(wid, &i1.data, &i2.data)) if(!algarray[alg].equal(wid, &i1.data, &i2.data))
goto no; goto no;
} else { } else {
...@@ -525,8 +550,8 @@ sys·Reflect(Iface i, uint64 retit, string rettype, bool retindir) ...@@ -525,8 +550,8 @@ sys·Reflect(Iface i, uint64 retit, string rettype, bool retindir)
} else { } else {
retit = (uint64)i.data; retit = (uint64)i.data;
rettype = gostring(i.type->sigt->name); rettype = gostring(i.type->sigt->name);
wid = i.type->sigt->offset; wid = i.type->sigt->width;
retindir = wid > sizeof i.data; retindir = wid > sizeof(i.data);
} }
FLUSH(&retit); FLUSH(&retit);
FLUSH(&rettype); FLUSH(&rettype);
...@@ -568,7 +593,7 @@ extern int32 ngotypesigs; ...@@ -568,7 +593,7 @@ extern int32 ngotypesigs;
// signature with type string "[]int" in gotypesigs, and unreflect // signature with type string "[]int" in gotypesigs, and unreflect
// wouldn't call fakesigt. // wouldn't call fakesigt.
static Sigt *fake[1009]; static Sigt* fake[1009];
static int32 nfake; static int32 nfake;
static Sigt* static Sigt*
...@@ -590,7 +615,7 @@ fakesigt(string type, bool indir) ...@@ -590,7 +615,7 @@ fakesigt(string type, bool indir)
for(locked=0; locked<2; locked++) { for(locked=0; locked<2; locked++) {
if(locked) if(locked)
lock(&ifacelock); 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. // don't need to compare indir.
// same type string but different indir will have // same type string but different indir will have
// different hashes. // different hashes.
...@@ -603,16 +628,16 @@ fakesigt(string type, bool indir) ...@@ -603,16 +628,16 @@ fakesigt(string type, bool indir)
} }
} }
sigt = mal(2*sizeof sigt[0]); sigt = mal(sizeof(*sigt));
sigt[0].name = mal(type->len + 1); sigt->name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len); mcpy(sigt->name, type->str, type->len);
sigt[0].hash = AFAKE; // alg sigt->alg = AFAKE;
sigt->width = 1; // small width
if(indir) if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width sigt->width = 2*sizeof(niliface.data); // big width
else sigt->link = fake[h];
sigt[0].offset = 1; // small width
sigt->fun = (void*)fake[h];
fake[h] = sigt; fake[h] = sigt;
unlock(&ifacelock); unlock(&ifacelock);
return sigt; return sigt;
} }
...@@ -672,7 +697,7 @@ sys·Unreflect(uint64 it, string type, bool indir, Iface ret) ...@@ -672,7 +697,7 @@ sys·Unreflect(uint64 it, string type, bool indir, Iface ret)
// if we think the type should be indirect // if we think the type should be indirect
// and caller does not, play it safe, return nil. // and caller does not, play it safe, return nil.
sigt = findtype(type, indir); sigt = findtype(type, indir);
if(indir != (sigt[0].offset > sizeof ret.data)) if(indir != (sigt->width > sizeof(ret.data)))
goto out; goto out;
ret.type = itype(sigi·empty, sigt, 0); ret.type = itype(sigi·empty, sigt, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment