]> Cypherpunks repositories - gostls13.git/commitdiff
interface speedups and fixes.
authorRuss Cox <rsc@golang.org>
Mon, 26 Jan 2009 20:36:21 +0000 (12:36 -0800)
committerRuss Cox <rsc@golang.org>
Mon, 26 Jan 2009 20:36:21 +0000 (12:36 -0800)
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

src/Make.conf
src/cmd/6g/obj.c
src/runtime/iface.c
src/runtime/runtime.c
src/runtime/runtime.h
test/cmp1.go

index 3542b70eefc68b3cead4d8cad546434f4fdcaf6c..29f352079e7dd6ed79a1f8b691d9ffcf3d9eb105 100644 (file)
@@ -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
index 76c6a93e2817d57d2f53ff5190409720e234d141..85e668d668517be712509f561a0dcf74f993b181 100644 (file)
@@ -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;
index 99116806a3918db4a963db293a67fffeaad3359c..7d312d22cc971f9bf112e5c411fd3c74d73a8af1 100644 (file)
@@ -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);
 }
 
index ce9349383c5d36e1af3eeffd365c33865a2256b0..00e3638ab9c81413d129019b3aab60b2f75ca4f4 100644 (file)
@@ -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 },
 };
 
index 47103e253addbcf1c2b18d701a0a4ded396dd0c1..170657d86b95b7ed074ac7559c8670270e565a28 100644 (file)
@@ -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);
index 82e932f45ef4ae67b0f803829434a8723b35b532..d1a1c7a0b34fc335e99e052bd8ca1fb818315720 100644 (file)
@@ -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?