summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-01-26 12:36:21 -0800
committerRuss Cox <rsc@golang.org>2009-01-26 12:36:21 -0800
commit0a1049d41a25723f16e04731e5b3a783ae6f94d4 (patch)
tree2510d5aae07204aade67d94379f589f3c9bb7738
parent081cbe92037e34574d75be5fddb30660805c67c6 (diff)
downloadgolang-0a1049d41a25723f16e04731e5b3a783ae6f94d4.tar.gz
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
-rw-r--r--src/Make.conf2
-rw-r--r--src/cmd/6g/obj.c24
-rw-r--r--src/runtime/iface.c149
-rw-r--r--src/runtime/runtime.c36
-rw-r--r--src/runtime/runtime.h2
-rw-r--r--test/cmp1.go9
6 files changed, 168 insertions, 54 deletions
diff --git a/src/Make.conf b/src/Make.conf
index 3542b70ee..29f352079 100644
--- a/src/Make.conf
+++ b/src/Make.conf
@@ -4,7 +4,7 @@
CC=quietgcc
LD=quietgcc
-CFLAGS=-ggdb -I$(GOROOT)/include
+CFLAGS=-ggdb -I$(GOROOT)/include -O1
BIN=$(HOME)/bin
O=o
YFLAGS=-d
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
index 76c6a93e2..85e668d66 100644
--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -635,12 +635,14 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
Iter savet;
Prog *oldlist;
Sym *method;
+ uint32 sighash;
at.sym = s;
a = nil;
o = 0;
oldlist = nil;
+ sighash = 0;
for(f=methodt->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
@@ -662,6 +664,8 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(method, rcvrt);
+
+ sighash = sighash*100003 + a->hash;
if(!a->sym->siggen) {
a->sym->siggen = 1;
@@ -709,7 +713,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
ot = 0;
ot = rnd(ot, maxround); // base structure
- // sigi[0].name = ""
+ // sigt[0].name = ""
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
@@ -718,10 +722,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
// first field of an type signature contains
// the element parameters and is not a real entry
- // sigi[0].hash = elemalg
- gensatac(wi, algtype(progt));
+ // sigt[0].hash = elemalg + sighash<<8
+ gensatac(wi, algtype(progt) + (sighash<<8));
- // sigi[0].offset = width
+ // sigt[0].offset = width
gensatac(wi, progt->width);
// skip the function
@@ -730,10 +734,10 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base structure
- // sigx[++].name = "fieldname"
+ // sigt[++].name = "fieldname"
ginsatoa(widthptr, stringo);
- // sigx[++].hash = hashcode
+ // sigt[++].hash = hashcode
gensatac(wi, b->hash);
// sigt[++].offset = of embedded struct
@@ -770,11 +774,13 @@ dumpsigi(Type *t, Sym *s)
Sig *a, *b;
Prog *p;
char buf[NSYMB];
+ uint32 sighash;
at.sym = s;
a = nil;
o = 0;
+ sighash = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
@@ -797,6 +803,8 @@ dumpsigi(Type *t, Sym *s)
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
+
+ sighash = sighash*100003 + a->hash;
o++;
}
@@ -815,8 +823,8 @@ dumpsigi(Type *t, Sym *s)
// first field of an interface signature
// contains the count and is not a real entry
- // sigi[0].hash = 0
- gensatac(wi, 0);
+ // sigi[0].hash = sighash
+ gensatac(wi, sighash);
// sigi[0].offset = count
o = 0;
diff --git a/src/runtime/iface.c b/src/runtime/iface.c
index 99116806a..7d312d22c 100644
--- a/src/runtime/iface.c
+++ b/src/runtime/iface.c
@@ -40,6 +40,7 @@ struct Itype
static Iface niliface;
static Itype* hash[1009];
+static Lock ifacelock;
Sigi sigi·empty[2] = { (byte*)"interface { }" };
@@ -113,32 +114,48 @@ printiface(Iface i)
static Itype*
itype(Sigi *si, Sigt *st, int32 canfail)
{
+ int32 locked;
int32 nt, ni;
uint32 ihash, h;
byte *sname, *iname;
Itype *m;
- h = ((uint32)(uint64)si + (uint32)(uint64)st) % nelem(hash);
- 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;
+ // compiler has provided some good hash codes for us.
+ h = 0;
+ if(si)
+ h += si->hash;
+ if(st)
+ h += st->hash >> 8;
+ h %= nelem(hash);
+
+ // look twice - once without lock, once with.
+ // common case will be no lock contention.
+ for(locked=0; locked<2; locked++) {
+ if(locked)
+ lock(&ifacelock);
+ 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
m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
m->sigi = si;
@@ -180,6 +197,8 @@ throw:
m->bad = 1;
m->link = hash[h];
hash[h] = m;
+ if(locked)
+ unlock(&ifacelock);
return nil;
}
if(ihash == st[nt].hash && strcmp(sname, iname) == 0)
@@ -190,6 +209,8 @@ throw:
m->link = hash[h];
hash[h] = m;
// printf("new itype %p\n", m);
+ if(locked)
+ unlock(&ifacelock);
return m;
}
@@ -216,7 +237,7 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...)
prints("\n");
}
- alg = st->hash;
+ alg = st->hash & 0xFF;
wid = st->offset;
if(wid <= sizeof ret->data)
algarray[alg].copy(wid, &ret->data, elem);
@@ -272,7 +293,7 @@ sys·ifaceI2T(Sigt *st, Iface i, ...)
throw("interface conversion");
}
- alg = st->hash;
+ alg = st->hash & 0xFF;
wid = st->offset;
if(wid <= sizeof i.data)
algarray[alg].copy(wid, ret, &i.data);
@@ -297,7 +318,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
int32 alg, wid;
ret = (byte*)(&i+1);
- alg = st->hash;
+ alg = st->hash & 0xFF;
wid = st->offset;
ok = (bool*)(ret+rnd(wid, 8));
@@ -411,7 +432,7 @@ ifacehash(Iface a)
if(a.type == nil)
return 0;
- alg = a.type->sigt->hash;
+ alg = a.type->sigt->hash & 0xFF;
wid = a.type->sigt->offset;
if(algarray[alg].hash == nohash) {
// calling nohash will throw too,
@@ -450,14 +471,12 @@ ifaceeq(Iface i1, Iface i2)
if(i2.type == nil)
goto no;
- // value
- alg = i1.type->sigt->hash;
- if(alg != i2.type->sigt->hash)
+ // are they the same type?
+ if(i1.type->sigt != i2.type->sigt)
goto no;
+ alg = i1.type->sigt->hash & 0xFF;
wid = i1.type->sigt->offset;
- if(wid != i2.type->sigt->offset)
- goto no;
if(algarray[alg].equal == noequal) {
// calling noequal will throw too,
@@ -553,20 +572,53 @@ extern int32 ngotypesigs;
// for .([]int) instead of .(string) above, then there would be a
// signature with type string "[]int" in gotypesigs, and unreflect
// wouldn't call fakesigt.
+
+static Sigt *fake[1009];
+static int32 nfake;
+
static Sigt*
fakesigt(string type, bool indir)
{
- // TODO(rsc): Cache these by type string.
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[0].name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len);
- sigt[0].hash = AMEM; // alg
+ sigt[0].hash = AFAKE; // alg
if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width
else
sigt[0].offset = 1; // small width
+ sigt->fun = (void*)fake[h];
+ fake[h] = sigt;
+ unlock(&ifacelock);
return sigt;
}
@@ -574,31 +626,40 @@ static int32
cmpstringchars(string a, uint8 *b)
{
int32 i;
+ byte c1, c2;
for(i=0;; i++) {
- if(i == a->len) {
- if(b[i] == 0)
- return 0;
+ if(i == a->len)
+ c1 = 0;
+ else
+ c1 = a->str[i];
+ c2 = b[i];
+ if(c1 < c2)
return -1;
- }
- if(b[i] == 0)
- return 1;
- if(a->str[i] != b[i]) {
- if((uint8)a->str[i] < (uint8)b[i])
- return -1;
- return 1;
- }
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ return 0;
}
}
static Sigt*
findtype(string type, bool indir)
{
- int32 i;
-
- for(i=0; i<ngotypesigs; i++)
- if(cmpstringchars(type, gotypesigs[i]->name) == 0)
- return gotypesigs[i];
+ int32 i, lo, hi, m;
+
+ lo = 0;
+ hi = ngotypesigs;
+ 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);
}
diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c
index ce9349383..00e3638ab 100644
--- a/src/runtime/runtime.c
+++ b/src/runtime/runtime.c
@@ -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
mmov(byte *t, byte *f, uint32 n)
{
@@ -368,6 +386,23 @@ noequal(uint32 s, void *a, void *b)
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
algarray[] =
{
@@ -375,5 +410,6 @@ algarray[] =
[ANOEQ] { nohash, noequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy },
+[AFAKE] { nohash, noequal, noprint, nocopy },
};
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 47103e253..170657d86 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -230,6 +230,7 @@ enum
ANOEQ,
ASTRING,
AINTER,
+ AFAKE,
Amax
};
@@ -269,6 +270,7 @@ void prints(int8*);
void printf(int8*, ...);
byte* mchr(byte*, byte, byte*);
void mcpy(byte*, byte*, uint32);
+int32 mcmp(byte*, byte*, uint32);
void mmov(byte*, byte*, uint32);
void* mal(uint32);
uint32 cmpstring(string, string);
diff --git a/test/cmp1.go b/test/cmp1.go
index 82e932f45..d1a1c7a0b 100644
--- a/test/cmp1.go
+++ b/test/cmp1.go
@@ -41,7 +41,7 @@ func main()
var ic interface{} = c;
var id interface{} = d;
var ie interface{} = e;
-
+
// these comparisons are okay because
// string compare is okay and the others
// are comparisons where the types differ.
@@ -53,6 +53,13 @@ func main()
istrue(ic == id);
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,
// not memory.
// TODO: should m[c], m[d] be valid here?