diff --git a/src/Make.conf b/src/Make.conf index 3542b70eef..29f352079e 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 76c6a93e28..85e668d668 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 99116806a3..7d312d22cc 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; ilen; 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; iname) == 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 ce9349383c..00e3638ab9 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 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 47103e253a..170657d86b 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 82e932f45e..d1a1c7a0b3 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?