Commit 9b6d385c authored by Russ Cox's avatar Russ Cox

interface speedups and fixes.

more caching, better hash functions, proper locking.
fixed a bug in interface comparison too.

R=ken
DELTA=177  (124 added, 10 deleted, 43 changed)
OCL=23491
CL=23493
parent 7859ae8a
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
CC=quietgcc CC=quietgcc
LD=quietgcc LD=quietgcc
CFLAGS=-ggdb -I$(GOROOT)/include CFLAGS=-ggdb -I$(GOROOT)/include -O1
BIN=$(HOME)/bin BIN=$(HOME)/bin
O=o O=o
YFLAGS=-d YFLAGS=-d
...@@ -635,12 +635,14 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -635,12 +635,14 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
Iter savet; Iter savet;
Prog *oldlist; Prog *oldlist;
Sym *method; Sym *method;
uint32 sighash;
at.sym = s; at.sym = s;
a = nil; a = nil;
o = 0; o = 0;
oldlist = nil; oldlist = nil;
sighash = 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;
...@@ -662,6 +664,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -662,6 +664,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
a->hash += PRIME10*stringhash(package); a->hash += PRIME10*stringhash(package);
a->perm = o; a->perm = o;
a->sym = methodsym(method, rcvrt); a->sym = methodsym(method, rcvrt);
sighash = sighash*100003 + a->hash;
if(!a->sym->siggen) { if(!a->sym->siggen) {
a->sym->siggen = 1; a->sym->siggen = 1;
...@@ -709,7 +713,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -709,7 +713,7 @@ 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
// sigi[0].name = "" // sigt[0].name = ""
ginsatoa(widthptr, stringo); ginsatoa(widthptr, stringo);
// save type name for runtime error message. // save type name for runtime error message.
...@@ -718,10 +722,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -718,10 +722,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
// first field of an type signature contains // first field of an type signature contains
// the element parameters and is not a real entry // the element parameters and is not a real entry
// sigi[0].hash = elemalg // sigt[0].hash = elemalg + sighash<<8
gensatac(wi, algtype(progt)); gensatac(wi, algtype(progt) + (sighash<<8));
// sigi[0].offset = width // sigt[0].offset = width
gensatac(wi, progt->width); gensatac(wi, progt->width);
// skip the function // skip the function
...@@ -730,10 +734,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s) ...@@ -730,10 +734,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
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 structure
// sigx[++].name = "fieldname" // sigt[++].name = "fieldname"
ginsatoa(widthptr, stringo); ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode // sigt[++].hash = hashcode
gensatac(wi, b->hash); gensatac(wi, b->hash);
// sigt[++].offset = of embedded struct // sigt[++].offset = of embedded struct
...@@ -770,11 +774,13 @@ dumpsigi(Type *t, Sym *s) ...@@ -770,11 +774,13 @@ dumpsigi(Type *t, Sym *s)
Sig *a, *b; Sig *a, *b;
Prog *p; Prog *p;
char buf[NSYMB]; char buf[NSYMB];
uint32 sighash;
at.sym = s; at.sym = s;
a = nil; a = nil;
o = 0; o = 0;
sighash = 0;
for(f=t->type; f!=T; f=f->down) { for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC) if(f->type->etype != TFUNC)
continue; continue;
...@@ -797,6 +803,8 @@ dumpsigi(Type *t, Sym *s) ...@@ -797,6 +803,8 @@ dumpsigi(Type *t, Sym *s)
a->perm = o; a->perm = o;
a->sym = methodsym(f->sym, t); a->sym = methodsym(f->sym, t);
a->offset = 0; a->offset = 0;
sighash = sighash*100003 + a->hash;
o++; o++;
} }
...@@ -815,8 +823,8 @@ dumpsigi(Type *t, Sym *s) ...@@ -815,8 +823,8 @@ dumpsigi(Type *t, Sym *s)
// first field of an interface signature // first field of an interface signature
// contains the count and is not a real entry // contains the count and is not a real entry
// sigi[0].hash = 0 // sigi[0].hash = sighash
gensatac(wi, 0); gensatac(wi, sighash);
// sigi[0].offset = count // sigi[0].offset = count
o = 0; o = 0;
......
...@@ -40,6 +40,7 @@ struct Itype ...@@ -40,6 +40,7 @@ struct Itype
static Iface niliface; static Iface niliface;
static Itype* hash[1009]; static Itype* hash[1009];
static Lock ifacelock;
Sigi sigi·empty[2] = { (byte*)"interface { }" }; Sigi sigi·empty[2] = { (byte*)"interface { }" };
...@@ -113,32 +114,48 @@ printiface(Iface i) ...@@ -113,32 +114,48 @@ printiface(Iface i)
static Itype* static Itype*
itype(Sigi *si, Sigt *st, int32 canfail) itype(Sigi *si, Sigt *st, int32 canfail)
{ {
int32 locked;
int32 nt, ni; int32 nt, ni;
uint32 ihash, h; uint32 ihash, h;
byte *sname, *iname; byte *sname, *iname;
Itype *m; Itype *m;
h = ((uint32)(uint64)si + (uint32)(uint64)st) % nelem(hash); // compiler has provided some good hash codes for us.
for(m=hash[h]; m!=nil; m=m->link) { h = 0;
if(m->sigi == si && m->sigt == st) { if(si)
if(m->bad) { h += si->hash;
m = nil; if(st)
if(!canfail) { h += st->hash >> 8;
// this can only happen if the conversion h %= nelem(hash);
// was already done once using the , ok form
// and we have a cached negative result. // look twice - once without lock, once with.
// the cached result doesn't record which // common case will be no lock contention.
// interface function was missing, so jump for(locked=0; locked<2; locked++) {
// down to the interface check, which will if(locked)
// give a better error. lock(&ifacelock);
goto throw; for(m=hash[h]; m!=nil; m=m->link) {
if(m->sigi == si && m->sigt == st) {
if(m->bad) {
m = nil;
if(!canfail) {
// this can only happen if the conversion
// was already done once using the , ok form
// and we have a cached negative result.
// the cached result doesn't record which
// interface function was missing, so jump
// down to the interface check, which will
// give a better error.
goto throw;
}
} }
// prints("old itype\n");
if(locked)
unlock(&ifacelock);
return m;
} }
// prints("old itype\n");
return m;
} }
} }
ni = si[0].perm; // first entry has size ni = si[0].perm; // first entry has 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;
...@@ -180,6 +197,8 @@ throw: ...@@ -180,6 +197,8 @@ throw:
m->bad = 1; m->bad = 1;
m->link = hash[h]; m->link = hash[h];
hash[h] = m; hash[h] = m;
if(locked)
unlock(&ifacelock);
return nil; return nil;
} }
if(ihash == st[nt].hash && strcmp(sname, iname) == 0) if(ihash == st[nt].hash && strcmp(sname, iname) == 0)
...@@ -190,6 +209,8 @@ throw: ...@@ -190,6 +209,8 @@ throw:
m->link = hash[h]; m->link = hash[h];
hash[h] = m; hash[h] = m;
// printf("new itype %p\n", m); // printf("new itype %p\n", m);
if(locked)
unlock(&ifacelock);
return m; return m;
} }
...@@ -216,7 +237,7 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) ...@@ -216,7 +237,7 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...)
prints("\n"); prints("\n");
} }
alg = st->hash; alg = st->hash & 0xFF;
wid = st->offset; wid = st->offset;
if(wid <= sizeof ret->data) if(wid <= sizeof ret->data)
algarray[alg].copy(wid, &ret->data, elem); algarray[alg].copy(wid, &ret->data, elem);
...@@ -272,7 +293,7 @@ sys·ifaceI2T(Sigt *st, Iface i, ...) ...@@ -272,7 +293,7 @@ sys·ifaceI2T(Sigt *st, Iface i, ...)
throw("interface conversion"); throw("interface conversion");
} }
alg = st->hash; alg = st->hash & 0xFF;
wid = st->offset; wid = st->offset;
if(wid <= sizeof i.data) if(wid <= sizeof i.data)
algarray[alg].copy(wid, ret, &i.data); algarray[alg].copy(wid, ret, &i.data);
...@@ -297,7 +318,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ...@@ -297,7 +318,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
int32 alg, wid; int32 alg, wid;
ret = (byte*)(&i+1); ret = (byte*)(&i+1);
alg = st->hash; alg = st->hash & 0xFF;
wid = st->offset; wid = st->offset;
ok = (bool*)(ret+rnd(wid, 8)); ok = (bool*)(ret+rnd(wid, 8));
...@@ -411,7 +432,7 @@ ifacehash(Iface a) ...@@ -411,7 +432,7 @@ ifacehash(Iface a)
if(a.type == nil) if(a.type == nil)
return 0; return 0;
alg = a.type->sigt->hash; alg = a.type->sigt->hash & 0xFF;
wid = a.type->sigt->offset; wid = a.type->sigt->offset;
if(algarray[alg].hash == nohash) { if(algarray[alg].hash == nohash) {
// calling nohash will throw too, // calling nohash will throw too,
...@@ -450,14 +471,12 @@ ifaceeq(Iface i1, Iface i2) ...@@ -450,14 +471,12 @@ ifaceeq(Iface i1, Iface i2)
if(i2.type == nil) if(i2.type == nil)
goto no; goto no;
// value // are they the same type?
alg = i1.type->sigt->hash; if(i1.type->sigt != i2.type->sigt)
if(alg != i2.type->sigt->hash)
goto no; goto no;
alg = i1.type->sigt->hash & 0xFF;
wid = i1.type->sigt->offset; wid = i1.type->sigt->offset;
if(wid != i2.type->sigt->offset)
goto no;
if(algarray[alg].equal == noequal) { if(algarray[alg].equal == noequal) {
// calling noequal will throw too, // calling noequal will throw too,
...@@ -553,20 +572,53 @@ extern int32 ngotypesigs; ...@@ -553,20 +572,53 @@ extern int32 ngotypesigs;
// for .([]int) instead of .(string) above, then there would be a // for .([]int) instead of .(string) above, then there would be a
// 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 int32 nfake;
static Sigt* static Sigt*
fakesigt(string type, bool indir) fakesigt(string type, bool indir)
{ {
// TODO(rsc): Cache these by type string.
Sigt *sigt; Sigt *sigt;
uint32 h;
int32 i, locked;
if(type == nil)
type = emptystring;
h = 0;
for(i=0; i<type->len; i++)
h = h*37 + type->str[i];
h += indir;
h %= nelem(fake);
for(locked=0; locked<2; locked++) {
if(locked)
lock(&ifacelock);
for(sigt = fake[h]; sigt != nil; sigt = (Sigt*)sigt->fun) {
// don't need to compare indir.
// same type string but different indir will have
// different hashes.
if(mcmp(sigt->name, type->str, type->len) == 0)
if(sigt->name[type->len] == '\0') {
if(locked)
unlock(&ifacelock);
return sigt;
}
}
}
sigt = mal(2*sizeof sigt[0]); sigt = mal(2*sizeof sigt[0]);
sigt[0].name = mal(type->len + 1); sigt[0].name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len); mcpy(sigt[0].name, type->str, type->len);
sigt[0].hash = AMEM; // alg sigt[0].hash = AFAKE; // alg
if(indir) if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width sigt[0].offset = 2*sizeof(niliface.data); // big width
else else
sigt[0].offset = 1; // small width sigt[0].offset = 1; // small width
sigt->fun = (void*)fake[h];
fake[h] = sigt;
unlock(&ifacelock);
return sigt; return sigt;
} }
...@@ -574,31 +626,40 @@ static int32 ...@@ -574,31 +626,40 @@ static int32
cmpstringchars(string a, uint8 *b) cmpstringchars(string a, uint8 *b)
{ {
int32 i; int32 i;
byte c1, c2;
for(i=0;; i++) { for(i=0;; i++) {
if(i == a->len) { if(i == a->len)
if(b[i] == 0) c1 = 0;
return 0; else
c1 = a->str[i];
c2 = b[i];
if(c1 < c2)
return -1; return -1;
} if(c1 > c2)
if(b[i] == 0) return +1;
return 1; if(c1 == 0)
if(a->str[i] != b[i]) { return 0;
if((uint8)a->str[i] < (uint8)b[i])
return -1;
return 1;
}
} }
} }
static Sigt* static Sigt*
findtype(string type, bool indir) findtype(string type, bool indir)
{ {
int32 i; int32 i, lo, hi, m;
for(i=0; i<ngotypesigs; i++) lo = 0;
if(cmpstringchars(type, gotypesigs[i]->name) == 0) hi = ngotypesigs;
return gotypesigs[i]; while(lo < hi) {
m = lo + (hi - lo)/2;
i = cmpstringchars(type, gotypesigs[m]->name);
if(i == 0)
return gotypesigs[m];
if(i < 0)
hi = m;
else
lo = m+1;
}
return fakesigt(type, indir); return fakesigt(type, indir);
} }
......
...@@ -69,6 +69,24 @@ mcpy(byte *t, byte *f, uint32 n) ...@@ -69,6 +69,24 @@ mcpy(byte *t, byte *f, uint32 n)
} }
} }
int32
mcmp(byte *s1, byte *s2, uint32 n)
{
uint32 i;
byte c1, c2;
for(i=0; i<n; i++) {
c1 = s1[i];
c2 = s2[i];
if(c1 < c2)
return -1;
if(c1 > c2)
return +1;
}
return 0;
}
void void
mmov(byte *t, byte *f, uint32 n) mmov(byte *t, byte *f, uint32 n)
{ {
...@@ -368,6 +386,23 @@ noequal(uint32 s, void *a, void *b) ...@@ -368,6 +386,23 @@ noequal(uint32 s, void *a, void *b)
return 0; return 0;
} }
static void
noprint(uint32 s, void *a)
{
USED(s);
USED(a);
throw("print of unprintable type");
}
static void
nocopy(uint32 s, void *a, void *b)
{
USED(s);
USED(a);
USED(b);
throw("copy of uncopyable type");
}
Alg Alg
algarray[] = algarray[] =
{ {
...@@ -375,5 +410,6 @@ algarray[] = ...@@ -375,5 +410,6 @@ algarray[] =
[ANOEQ] { nohash, noequal, memprint, memcopy }, [ANOEQ] { nohash, noequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, memcopy }, [ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy }, [AINTER] { interhash, interequal, interprint, memcopy },
[AFAKE] { nohash, noequal, noprint, nocopy },
}; };
...@@ -230,6 +230,7 @@ enum ...@@ -230,6 +230,7 @@ enum
ANOEQ, ANOEQ,
ASTRING, ASTRING,
AINTER, AINTER,
AFAKE,
Amax Amax
}; };
...@@ -269,6 +270,7 @@ void prints(int8*); ...@@ -269,6 +270,7 @@ void prints(int8*);
void printf(int8*, ...); void printf(int8*, ...);
byte* mchr(byte*, byte, byte*); byte* mchr(byte*, byte, byte*);
void mcpy(byte*, byte*, uint32); void mcpy(byte*, byte*, uint32);
int32 mcmp(byte*, byte*, uint32);
void mmov(byte*, byte*, uint32); void mmov(byte*, byte*, uint32);
void* mal(uint32); void* mal(uint32);
uint32 cmpstring(string, string); uint32 cmpstring(string, string);
......
...@@ -41,7 +41,7 @@ func main() ...@@ -41,7 +41,7 @@ func main()
var ic interface{} = c; var ic interface{} = c;
var id interface{} = d; var id interface{} = d;
var ie interface{} = e; var ie interface{} = e;
// these comparisons are okay because // these comparisons are okay because
// string compare is okay and the others // string compare is okay and the others
// are comparisons where the types differ. // are comparisons where the types differ.
...@@ -53,6 +53,13 @@ func main() ...@@ -53,6 +53,13 @@ func main()
istrue(ic == id); istrue(ic == id);
istrue(ie == ie); istrue(ie == ie);
// 6g used to let this go through as true.
var g uint64 = 123;
var h int64 = 123;
var ig interface{} = g;
var ih interface{} = h;
isfalse(ig == ih);
// map of interface should use == on interface values, // map of interface should use == on interface values,
// not memory. // not memory.
// TODO: should m[c], m[d] be valid here? // TODO: should m[c], m[d] be valid here?
......
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