]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: cache itab lookup in convT2I.
authorNigel Tao <nigeltao@golang.org>
Mon, 2 Jul 2012 23:09:05 +0000 (09:09 +1000)
committerNigel Tao <nigeltao@golang.org>
Mon, 2 Jul 2012 23:09:05 +0000 (09:09 +1000)
There may be further savings if convT2I can avoid the function call
if the cache is good and T is uintptr-shaped, a la convT2E, but that
will be a follow-up CL.

src/pkg/runtime:
benchmark                  old ns/op    new ns/op    delta
BenchmarkConvT2ISmall             43           15  -64.01%
BenchmarkConvT2IUintptr           45           14  -67.48%
BenchmarkConvT2ILarge            130          101  -22.31%

test/bench/go1:
benchmark                 old ns/op    new ns/op    delta
BenchmarkBinaryTree17    8588997000   8499058000   -1.05%
BenchmarkFannkuch11      5300392000   5358093000   +1.09%
BenchmarkGobDecode         30295580     31040190   +2.46%
BenchmarkGobEncode         18102070     17675650   -2.36%
BenchmarkGzip             774191400    771591400   -0.34%
BenchmarkGunzip           245915100    247464100   +0.63%
BenchmarkJSONEncode       123577000    121423050   -1.74%
BenchmarkJSONDecode       451969800    596256200  +31.92%
BenchmarkMandelbrot200     10060050     10072880   +0.13%
BenchmarkParse             10989840     11037710   +0.44%
BenchmarkRevcomp         1782666000   1716864000   -3.69%
BenchmarkTemplate         798286600    723234400   -9.40%

R=rsc, bradfitz, go.peter.90, daniel.morsing, dave, uriel
CC=golang-dev
https://golang.org/cl/6337058

13 files changed:
src/cmd/5g/gsubr.c
src/cmd/6g/gsubr.c
src/cmd/8g/gsubr.c
src/cmd/gc/builtin.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/obj.c
src/cmd/gc/reflect.c
src/cmd/gc/runtime.go
src/cmd/gc/walk.c
src/pkg/runtime/iface.c
src/pkg/runtime/iface_test.go
test/convT2X.go [moved from test/convT2E.go with 54% similarity]

index 80a173404ce1900ae65d98276d75fc3793672753..19036a36f7c9202f724072f67a9391a02b979b7a 100644 (file)
@@ -208,7 +208,7 @@ ggloblnod(Node *nam, int32 width)
 }
 
 void
-ggloblsym(Sym *s, int32 width, int dupok)
+ggloblsym(Sym *s, int32 width, int dupok, int rodata)
 {
        Prog *p;
 
@@ -220,8 +220,9 @@ ggloblsym(Sym *s, int32 width, int dupok)
        p->to.name = D_NONE;
        p->to.offset = width;
        if(dupok)
-               p->reg = DUPOK;
-       p->reg |= RODATA;
+               p->reg |= DUPOK;
+       if(rodata)
+               p->reg |= RODATA;
 }
 
 int
index 8284bd3da50fee18e5fe1832157d73ba982f97af..2758304427a8cdc9d3bb64943843dbed98545c61 100644 (file)
@@ -206,7 +206,7 @@ ggloblnod(Node *nam, int32 width)
 }
 
 void
-ggloblsym(Sym *s, int32 width, int dupok)
+ggloblsym(Sym *s, int32 width, int dupok, int rodata)
 {
        Prog *p;
 
@@ -218,8 +218,9 @@ ggloblsym(Sym *s, int32 width, int dupok)
        p->to.index = D_NONE;
        p->to.offset = width;
        if(dupok)
-               p->from.scale = DUPOK;
-       p->from.scale |= RODATA;
+               p->from.scale |= DUPOK;
+       if(rodata)
+               p->from.scale |= RODATA;
 }
 
 int
index 4011fa5c59b1e0c2d8c3b790b6c1350321ae3336..439495c0345919c72ccd13b9490b05a84441473b 100644 (file)
@@ -207,7 +207,7 @@ ggloblnod(Node *nam, int32 width)
 }
 
 void
-ggloblsym(Sym *s, int32 width, int dupok)
+ggloblsym(Sym *s, int32 width, int dupok, int rodata)
 {
        Prog *p;
 
@@ -219,8 +219,9 @@ ggloblsym(Sym *s, int32 width, int dupok)
        p->to.index = D_NONE;
        p->to.offset = width;
        if(dupok)
-               p->from.scale = DUPOK;
-       p->from.scale |= RODATA;
+               p->from.scale |= DUPOK;
+       if(rodata)
+               p->from.scale |= RODATA;
 }
 
 int
index 4aec0c04eae642cb82c8794691575d90afde82ed..e17aa7953ae445a133a51239722e9d48f630f69f 100644 (file)
@@ -41,7 +41,7 @@ char *runtimeimport =
        "func @\"\".convI2E(@\"\".elem any) (@\"\".ret any)\n"
        "func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
        "func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
-       "func @\"\".convT2I(@\"\".typ *byte, @\"\".typ2 *byte, @\"\".elem any) (@\"\".ret any)\n"
+       "func @\"\".convT2I(@\"\".typ *byte, @\"\".typ2 *byte, @\"\".cache **byte, @\"\".elem any) (@\"\".ret any)\n"
        "func @\"\".assertE2E(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
        "func @\"\".assertE2E2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
        "func @\"\".assertE2I(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
index 7864b7b72d4fa20e280783d7458a73d7287bf399..9045922d37d3429b0e2651fe08f708eafe4c3390 100644 (file)
@@ -767,6 +767,7 @@ EXTERN      Pkg*    importpkg;      // package being imported
 EXTERN Pkg*    structpkg;      // package that declared struct, during import
 EXTERN Pkg*    builtinpkg;     // fake package for builtins
 EXTERN Pkg*    gostringpkg;    // fake pkg for Go strings
+EXTERN Pkg*    itabpkg;        // fake pkg for itab cache
 EXTERN Pkg*    runtimepkg;     // package runtime
 EXTERN Pkg*    stringpkg;      // fake package for C strings
 EXTERN Pkg*    typepkg;        // fake package for runtime type info
@@ -1330,7 +1331,7 @@ void      gdatacomplex(Node*, Mpcplx*);
 void   gdatastring(Node*, Strlit*);
 void   genembedtramp(Type*, Type*, Sym*, int iface);
 void   ggloblnod(Node *nam, int32 width);
-void   ggloblsym(Sym *s, int32 width, int dupok);
+void   ggloblsym(Sym *s, int32 width, int dupok, int rodata);
 Prog*  gjmp(Prog*);
 void   gused(Node*);
 int    isfat(Type*);
index e6e7558958017eb7d478a2259a457497c46bd527..641cb6f62c593c248850cb54ab5095dbdda31140 100644 (file)
@@ -204,6 +204,10 @@ main(int argc, char *argv[])
        gostringpkg->name = "go.string";
        gostringpkg->prefix = "go.string";      // not go%2estring
 
+       itabpkg = mkpkg(strlit("go.itab"));
+       itabpkg->name = "go.itab";
+       itabpkg->prefix = "go.itab";    // not go%2eitab
+
        runtimepkg = mkpkg(strlit("runtime"));
        runtimepkg->name = "runtime";
 
index e45b4e0d44c94fb92c58c98eaa698b63d322cb50..8094671cb26b0228bc27ddc292836c8de3ee054a 100644 (file)
@@ -314,7 +314,7 @@ stringsym(char *s, int len)
        }
        off = duint8(sym, off, 0);  // terminating NUL for runtime
        off = (off+widthptr-1)&~(widthptr-1);  // round to pointer alignment
-       ggloblsym(sym, off, 1);
+       ggloblsym(sym, off, 1, 1);
 
        return sym;     
 }
index bab17d89ee82642a25def6d9ca153fd70b79b508..fa9bc993bb3816444003906d49c7fed810070146 100644 (file)
@@ -305,7 +305,7 @@ dimportpath(Pkg *p)
        p->pathsym = n->sym;
 
        gdatastring(n, p->path);
-       ggloblsym(n->sym, types[TSTRING]->width, 1);
+       ggloblsym(n->sym, types[TSTRING]->width, 1, 1);
 }
 
 static int
@@ -857,7 +857,7 @@ ok:
                break;
        }
        ot = dextratype(s, ot, t, xt);
-       ggloblsym(s, ot, dupok);
+       ggloblsym(s, ot, dupok, 1);
        return s;
 }
 
@@ -955,7 +955,7 @@ dalgsym(Type *t)
                break;
        }
 
-       ggloblsym(s, ot, 1);
+       ggloblsym(s, ot, 1, 1);
        return s;
 }
 
index d5cdb2a5ea14fc1689685272df9f8f93f1903d19..91fb7720f50714295bc6951f10f032976c726fb2 100644 (file)
@@ -61,7 +61,7 @@ func slicestringcopy(to any, fr any) int
 func convI2E(elem any) (ret any)
 func convI2I(typ *byte, elem any) (ret any)
 func convT2E(typ *byte, elem any) (ret any)
-func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
+func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
 
 // interface type assertions  x.(T)
 func assertE2E(typ *byte, iface any) (ret any)
index f5ccc198b3cb2dff2c461dfff36edaf53eb5ee91..20f8bbfe93b7fee5e0d47e408524d19e78d8e35e 100644 (file)
@@ -375,6 +375,7 @@ walkexpr(Node **np, NodeList **init)
        int64 v;
        int32 lno;
        Node *n, *fn;
+       Sym *sym;
        char buf[100], *p;
 
        n = *np;
@@ -755,6 +756,22 @@ walkexpr(Node **np, NodeList **init)
                        ll = list(ll, typename(n->left->type));
                if(!isnilinter(n->type))
                        ll = list(ll, typename(n->type));
+               if(!isinter(n->left->type) && !isnilinter(n->type)){
+                       sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg);
+                       if(sym->def == N) {
+                               l = nod(ONAME, N, N);
+                               l->sym = sym;
+                               l->type = ptrto(types[TUINT8]);
+                               l->addable = 1;
+                               l->class = PEXTERN;
+                               l->xoffset = 0;
+                               sym->def = l;
+                               ggloblsym(sym, widthptr, 1, 0);
+                       }
+                       l = nod(OADDR, sym->def, N);
+                       l->addable = 1;
+                       ll = list(ll, l);
+               }
                ll = list(ll, n->left);
                argtype(fn, n->left->type);
                argtype(fn, n->type);
index 358cdcbbb65cd015eb4b5d9081bebad9240bc2f7..864954d0d523c1973108553cfb0c3c26bc6ccda9 100644 (file)
@@ -183,19 +183,25 @@ copyout(Type *t, void **src, void *dst)
                alg->copy(size, dst, *src);
 }
 
-// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
+// func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
 #pragma textflag 7
 void
-runtime·convT2I(Type *t, InterfaceType *inter, ...)
+runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, ...)
 {
        byte *elem;
        Iface *ret;
+       Itab *tab;
        int32 wid;
 
-       elem = (byte*)(&inter+1);
+       elem = (byte*)(&cache+1);
        wid = t->size;
        ret = (Iface*)(elem + ROUND(wid, Structrnd));
-       ret->tab = itab(inter, t, 0);
+       tab = runtime·atomicloadp(cache);
+       if(!tab) {
+               tab = itab(inter, t, 0);
+               runtime·atomicstorep(cache, tab);
+       }
+       ret->tab = tab;
        copyin(t, elem, &ret->data);
 }
 
index ee534db15defb55795319684538786576604e9cd..bca0ea0ee758334082a13f3a4c2a942bda6b1297 100644 (file)
 package runtime_test
 
 import (
-       "bytes"
-       "io"
        "testing"
 )
 
+type I1 interface {
+       Method1()
+}
+
+type I2 interface {
+       Method1()
+       Method2()
+}
+
+type TS uint16
+type TM uintptr
+type TL [2]uintptr
+
+func (TS) Method1() {}
+func (TS) Method2() {}
+func (TM) Method1() {}
+func (TM) Method2() {}
+func (TL) Method1() {}
+func (TL) Method2() {}
+
 var (
-         interface{}
-       J   int
-       B                 = new(bytes.Buffer)
-       W   io.Writer     = B
-       I2  interface{}   = B
-       R   io.ReadWriter = B
-       Big [2]*int
+       e  interface{}
+       e_ interface{}
+       i1 I1
+       i2 I2
+       ts TS
+       tm TM
+       tl TL
 )
 
 func BenchmarkConvT2ESmall(b *testing.B) {
        for i := 0; i < b.N; i++ {
-               I = uint16(1)
+               e = ts
        }
 }
 
 func BenchmarkConvT2EUintptr(b *testing.B) {
        for i := 0; i < b.N; i++ {
-               I = uintptr(1)
+               e = tm
+       }
+}
+
+func BenchmarkConvT2ELarge(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               e = tl
+       }
+}
+
+func BenchmarkConvT2ISmall(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               i1 = ts
        }
 }
 
-func BenchmarkConvT2EBig(b *testing.B) {
-       v := [2]uintptr{1, 2}
+func BenchmarkConvT2IUintptr(b *testing.B) {
        for i := 0; i < b.N; i++ {
-               I = v
+               i1 = tm
        }
 }
 
-func BenchmarkConvT2I(b *testing.B) {
+func BenchmarkConvT2ILarge(b *testing.B) {
        for i := 0; i < b.N; i++ {
-               W = B
+               i1 = tl
        }
 }
 
 func BenchmarkConvI2E(b *testing.B) {
+       i2 = tm
        for i := 0; i < b.N; i++ {
-               I = W
+               e = i2
        }
 }
 
 func BenchmarkConvI2I(b *testing.B) {
+       i2 = tm
        for i := 0; i < b.N; i++ {
-               W = R
+               i1 = i2
        }
 }
 
 func BenchmarkAssertE2T(b *testing.B) {
-       I = 1
+       e = tm
        for i := 0; i < b.N; i++ {
-               J = I.(int)
+               tm = e.(TM)
        }
 }
 
-func BenchmarkAssertE2TBig(b *testing.B) {
-       var v interface{} = [2]*int{}
+func BenchmarkAssertE2TLarge(b *testing.B) {
+       e = tl
        for i := 0; i < b.N; i++ {
-               Big = v.([2]*int)
+               tl = e.(TL)
        }
 }
 
 func BenchmarkAssertE2I(b *testing.B) {
+       e = tm
        for i := 0; i < b.N; i++ {
-               W = I2.(io.Writer)
+               i1 = e.(I1)
        }
 }
 
 func BenchmarkAssertI2T(b *testing.B) {
+       i1 = tm
        for i := 0; i < b.N; i++ {
-               B = W.(*bytes.Buffer)
+               tm = i1.(TM)
        }
 }
 
 func BenchmarkAssertI2I(b *testing.B) {
+       i1 = tm
        for i := 0; i < b.N; i++ {
-               W = R.(io.Writer)
+               i2 = i1.(I2)
        }
 }
 
 func BenchmarkAssertI2E(b *testing.B) {
+       i1 = tm
        for i := 0; i < b.N; i++ {
-               I = R.(interface{})
+               e = i1.(interface{})
        }
 }
 
 func BenchmarkAssertE2E(b *testing.B) {
+       e = tm
        for i := 0; i < b.N; i++ {
-               I = I2.(interface{})
+               e_ = e
        }
 }
similarity index 54%
rename from test/convT2E.go
rename to test/convT2X.go
index 975808fef71f054b3a3b53e90ba41dde51b36e1e..7e27f06b0cbe4f1830a264f0d040328b45f8e405 100644 (file)
@@ -8,27 +8,56 @@
 
 package main
 
+type J interface {
+       Method()
+}
+
+type (
+       U16  uint16
+       U32  uint32
+       U64  uint64
+       U128 [2]uint64
+       F32  float32
+       F64  float64
+       C128 complex128
+       S    string
+       B    []byte
+       M    map[int]int
+       C    chan int
+       Z    struct{}
+)
+
+func (U16) Method()  {}
+func (U32) Method()  {}
+func (U64) Method()  {}
+func (U128) Method() {}
+func (F32) Method()  {}
+func (F64) Method()  {}
+func (C128) Method() {}
+func (S) Method()    {}
+func (B) Method()    {}
+func (M) Method()    {}
+func (C) Method()    {}
+func (Z) Method()    {}
+
 var (
-       z    = struct{}{}
+       u16  = U16(1)
+       u32  = U32(2)
+       u64  = U64(3)
+       u128 = U128{4, 5}
+       f32  = F32(6)
+       f64  = F64(7)
+       c128 = C128(8 + 9i)
+       s    = S("10")
+       b    = B("11")
+       m    = M{12: 13}
+       c    = make(C, 14)
+       z    = Z{}
        p    = &z
        pp   = &p
-       u16  = uint16(1)
-       u32  = uint32(2)
-       u64  = uint64(3)
-       u128 = [2]uint64{4, 5}
-       f32  = float32(6)
-       f64  = float64(7)
-       c128 = complex128(8 + 9i)
-       s    = "10"
-       b    = []byte("11")
-       m    = map[int]int{12: 13}
-       c    = make(chan int, 14)
 )
 
 var (
-       iz    interface{} = z
-       ip    interface{} = p
-       ipp   interface{} = pp
        iu16  interface{} = u16
        iu32  interface{} = u32
        iu64  interface{} = u64
@@ -40,6 +69,24 @@ var (
        ib    interface{} = b
        im    interface{} = m
        ic    interface{} = c
+       iz    interface{} = z
+       ip    interface{} = p
+       ipp   interface{} = pp
+
+       ju16  J = u16
+       ju32  J = u32
+       ju64  J = u64
+       ju128 J = u128
+       jf32  J = f32
+       jf64  J = f64
+       jc128 J = c128
+       js    J = s
+       jb    J = b
+       jm    J = m
+       jc    J = c
+       jz J = z
+       jp J = p // The method set for *T contains the methods for T.
+       // pp does not implement error.
 )
 
 func second(a ...interface{}) interface{} {
@@ -47,44 +94,78 @@ func second(a ...interface{}) interface{} {
 }
 
 func main() {
-       // Test equality. There are no tests for b and m, as slices and
-       // maps are not comparable by ==.
-       if z != iz {
-               panic("z != iz")
-       }
-       if p != ip {
-               panic("p != ip")
-       }
-       if pp != ipp {
-               panic("pp != ipp")
-       }
+       // Test equality.
        if u16 != iu16 {
                panic("u16 != iu16")
        }
+       if u16 != ju16 {
+               panic("u16 != ju16")
+       }
        if u32 != iu32 {
                panic("u32 != iu32")
        }
+       if u32 != ju32 {
+               panic("u32 != ju32")
+       }
        if u64 != iu64 {
                panic("u64 != iu64")
        }
+       if u64 != ju64 {
+               panic("u64 != ju64")
+       }
        if u128 != iu128 {
                panic("u128 != iu128")
        }
+       if u128 != ju128 {
+               panic("u128 != ju128")
+       }
        if f32 != if32 {
                panic("f32 != if32")
        }
+       if f32 != jf32 {
+               panic("f32 != jf32")
+       }
        if f64 != if64 {
                panic("f64 != if64")
        }
+       if f64 != jf64 {
+               panic("f64 != jf64")
+       }
        if c128 != ic128 {
                panic("c128 != ic128")
        }
+       if c128 != jc128 {
+               panic("c128 != jc128")
+       }
        if s != is {
                panic("s != is")
        }
+       if s != js {
+               panic("s != js")
+       }
        if c != ic {
                panic("c != ic")
        }
+       if c != jc {
+               panic("c != jc")
+       }
+       // There are no tests for b and m, as slices and maps are not comparable by ==.
+       if z != iz {
+               panic("z != iz")
+       }
+       if z != jz {
+               panic("z != jz")
+       }
+       if p != ip {
+               panic("p != ip")
+       }
+       if p != jp {
+               panic("p != jp")
+       }
+       if pp != ipp {
+               panic("pp != ipp")
+       }
+       // pp does not implement J.
 
        // Test that non-interface types can be used as ...interface{} arguments.
        if got := second(z, p, pp, u16, u32, u64, u128, f32, f64, c128, s, b, m, c); got != ip {