]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: compute second method type at runtime
authorDavid Crawshaw <crawshaw@golang.org>
Tue, 15 Mar 2016 01:30:43 +0000 (21:30 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Tue, 15 Mar 2016 19:57:40 +0000 (19:57 +0000)
The type information for a method includes two variants: a func
without the receiver, and a func with the receiver as the first
parameter. The former is used as part of the dynamic interface
checks, but the latter is only returned as a type in the
reflect.Method struct.

Instead of computing it at compile time, construct it at run time
with reflect.FuncOf.

Using cl/20701 as a baseline,

cmd/go: -480KB, (4.4%)
jujud:  -5.6MB, (7.8%)

For #6853.

Change-Id: I1b8c73f3ab894735f53d00cb9c0b506d84d54e92
Reviewed-on: https://go-review.googlesource.com/20709
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/compile/internal/gc/reflect.go
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/decodesym.go
src/reflect/type.go
src/runtime/type.go

index 8dc1e6cd0b9d46a22cd764399e7724a77cbbc277..dda876d65f3a22986d57540e2d590e71212a8560 100644 (file)
@@ -505,7 +505,6 @@ func dextratypeData(s *Sym, ot int, t *Type) int {
 
                ot = dgopkgpath(s, ot, a.pkg)
                ot = dmethodptr(s, ot, dtypesym(a.mtype))
-               ot = dmethodptr(s, ot, dtypesym(a.type_))
                ot = dmethodptr(s, ot, a.isym)
                ot = dmethodptr(s, ot, a.tsym)
        }
index 936737510282ebf1050f4641edcd61960da7dab8..9ed9c56f99ce7fa352bcaffe4a9720e7f5b887df 100644 (file)
@@ -95,7 +95,7 @@ func deadcode(ctxt *Link) {
                                // and setting those fields to nil. Doing so
                                // would reduce the binary size of typical
                                // programs like cmd/go by ~2%.
-                               d.markMethodType(m)
+                               d.mark(m.mtyp(), m.src)
                                rem = append(rem, m)
                        } else {
                                rem = append(rem, m)
@@ -171,18 +171,17 @@ var markextra = []string{
 }
 
 // methodref holds the relocations from a receiver type symbol to its
-// method. There are four relocations, one for each of the fields in
-// the reflect.method struct: mtyp, typ, ifn, and tfn.
+// method. There are three relocations, one for each of the fields in
+// the reflect.method struct: mtyp, ifn, and tfn.
 type methodref struct {
        m   methodsig
        src *LSym     // receiver type symbol
-       r   [4]*Reloc // R_METHOD relocations to fields of runtime.method
+       r   [3]*Reloc // R_METHOD relocations to fields of runtime.method
 }
 
 func (m methodref) mtyp() *LSym { return m.r[0].Sym }
-func (m methodref) typ() *LSym  { return m.r[1].Sym }
-func (m methodref) ifn() *LSym  { return m.r[2].Sym }
-func (m methodref) tfn() *LSym  { return m.r[3].Sym }
+func (m methodref) ifn() *LSym  { return m.r[1].Sym }
+func (m methodref) tfn() *LSym  { return m.r[2].Sym }
 
 func (m methodref) isExported() bool {
        for _, r := range m.m {
@@ -233,12 +232,6 @@ func (d *deadcodepass) markMethod(m methodref) {
        }
 }
 
-// markMethodType marks just a method's types as reachable.
-func (d *deadcodepass) markMethodType(m methodref) {
-       d.mark(m.mtyp(), m.src)
-       d.mark(m.typ(), m.src)
-}
-
 // init marks all initial symbols as reachable.
 // In a typical binary, this is INITENTRY.
 func (d *deadcodepass) init() {
index 98590d367701520e0b5ae883540c6b6e52f4cd8b..00e1a79a83c2a436fe055938b708d9df734c3c1e 100644 (file)
@@ -350,7 +350,7 @@ func decodetype_methods(s *LSym) []methodsig {
        if r.Sym != s {
                panic(fmt.Sprintf("method slice pointer in %q leads to a different symbol", s.Name))
        }
-       off = int(r.Add) // array of reflect.method values
-       sizeofMethod := 6 * Thearch.Ptrsize
+       off = int(r.Add)                    // array of reflect.method values
+       sizeofMethod := 5 * Thearch.Ptrsize // sizeof reflect.method in program
        return decode_methodsig(s, off, sizeofMethod, numMethods)
 }
index 44ab004274658c9de35bb070c32d172afa172325..736c0824cbbbea5310b55b691b8dd80dbed47535 100644 (file)
@@ -291,7 +291,6 @@ type method struct {
        name    *string        // name of method
        pkgPath *string        // nil for exported Names; otherwise import path
        mtyp    *rtype         // method type (without receiver)
-       typ     *rtype         // .(*FuncType) underneath (with receiver)
        ifn     unsafe.Pointer // fn used in interface call (one-word receiver)
        tfn     unsafe.Pointer // fn used for normal method call
 }
@@ -561,11 +560,29 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
 
 func (t *rtype) common() *rtype { return t }
 
-func (t *uncommonType) Method(i int) (m Method) {
-       if t == nil || i < 0 || i >= len(t.methods) {
+func (t *rtype) NumMethod() int {
+       if t.Kind() == Interface {
+               tt := (*interfaceType)(unsafe.Pointer(t))
+               return tt.NumMethod()
+       }
+       ut := t.uncommon()
+       if ut == nil {
+               return 0
+       }
+       return len(ut.methods)
+}
+
+func (t *rtype) Method(i int) (m Method) {
+       if t.Kind() == Interface {
+               tt := (*interfaceType)(unsafe.Pointer(t))
+               return tt.Method(i)
+       }
+       ut := t.uncommon()
+
+       if ut == nil || i < 0 || i >= len(ut.methods) {
                panic("reflect: Method index out of range")
        }
-       p := &t.methods[i]
+       p := &ut.methods[i]
        if p.name != nil {
                m.Name = *p.name
        }
@@ -574,60 +591,41 @@ func (t *uncommonType) Method(i int) (m Method) {
                m.PkgPath = *p.pkgPath
                fl |= flagStickyRO
        }
-       mt := p.typ
+       ft := (*funcType)(unsafe.Pointer(p.mtyp))
+       in := make([]Type, 0, 1+len(ft.in()))
+       in = append(in, t)
+       for _, arg := range ft.in() {
+               in = append(in, arg)
+       }
+       out := make([]Type, 0, len(ft.out()))
+       for _, ret := range ft.out() {
+               out = append(out, ret)
+       }
+       mt := FuncOf(in, out, p.mtyp.IsVariadic())
        m.Type = mt
        fn := unsafe.Pointer(&p.tfn)
-       m.Func = Value{mt, fn, fl}
+       m.Func = Value{mt.(*rtype), fn, fl}
        m.Index = i
-       return
+       return m
 }
 
-func (t *uncommonType) NumMethod() int {
-       if t == nil {
-               return 0
+func (t *rtype) MethodByName(name string) (m Method, ok bool) {
+       if t.Kind() == Interface {
+               tt := (*interfaceType)(unsafe.Pointer(t))
+               return tt.MethodByName(name)
        }
-       return len(t.methods)
-}
-
-func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
-       if t == nil {
-               return
+       ut := t.uncommon()
+       if ut == nil {
+               return Method{}, false
        }
        var p *method
-       for i := range t.methods {
-               p = &t.methods[i]
+       for i := range ut.methods {
+               p = &ut.methods[i]
                if p.name != nil && *p.name == name {
                        return t.Method(i), true
                }
        }
-       return
-}
-
-// TODO(rsc): gc supplies these, but they are not
-// as efficient as they could be: they have commonType
-// as the receiver instead of *rtype.
-func (t *rtype) NumMethod() int {
-       if t.Kind() == Interface {
-               tt := (*interfaceType)(unsafe.Pointer(t))
-               return tt.NumMethod()
-       }
-       return t.uncommon().NumMethod()
-}
-
-func (t *rtype) Method(i int) (m Method) {
-       if t.Kind() == Interface {
-               tt := (*interfaceType)(unsafe.Pointer(t))
-               return tt.Method(i)
-       }
-       return t.uncommon().Method(i)
-}
-
-func (t *rtype) MethodByName(name string) (m Method, ok bool) {
-       if t.Kind() == Interface {
-               tt := (*interfaceType)(unsafe.Pointer(t))
-               return tt.MethodByName(name)
-       }
-       return t.uncommon().MethodByName(name)
+       return Method{}, false
 }
 
 func (t *rtype) PkgPath() string {
index c504e2d29471e603df3130e751e17ca042dc5ab7..c7f11d68c2a38814721c1cc1c6b06e50817b18d4 100644 (file)
@@ -155,7 +155,6 @@ type method struct {
        name    *string
        pkgpath *string
        mtyp    *_type
-       typ     *_type
        ifn     unsafe.Pointer
        tfn     unsafe.Pointer
 }