]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: remove rtype *uncommonType field
authorDavid Crawshaw <crawshaw@golang.org>
Sun, 21 Feb 2016 03:54:15 +0000 (22:54 -0500)
committerDavid Crawshaw <crawshaw@golang.org>
Tue, 8 Mar 2016 23:23:13 +0000 (23:23 +0000)
Instead of a pointer on every rtype, use a bit flag to indicate that
the contents of uncommonType directly follows the rtype value when it
is needed.

This requires a bit of juggling in the compiler's rtype encoder. The
backing arrays for fields in the rtype are presently encoded directly
after the slice header. This packing requires separating the encoding
of the uncommonType slice headers from their backing arrays.

Reduces binary size of godoc by ~180KB (1.5%).
No measurable change in all.bash time.
For #6853.

Change-Id: I60205948ceb5c0abba76fdf619652da9c465a597
Reviewed-on: https://go-review.googlesource.com/19790
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/reflect.go
src/cmd/link/internal/ld/decodesym.go
src/reflect/type.go
src/runtime/heapdump.go
src/runtime/iface.go
src/runtime/mfinal.go
src/runtime/type.go

index 0bb980e92facb08a9d29a7a2b4d2a365469f0d73..a18016fa78a0ab24a491e67a88bd5f675cbc4411 100644 (file)
@@ -53,6 +53,15 @@ const (
        MAXVALSIZE = 128
 )
 
+func structfieldSize() int       { return 5 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int           { return 3 * Widthptr } // Sizeof(runtime.imethod{})
+func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
+       if t.Sym == nil && len(methods(t)) == 0 {
+               return 0
+       }
+       return 2*Widthptr + 2*Widthint
+}
+
 func makefield(name string, t *Type) *Type {
        f := typ(TFIELD)
        f.Type = t
@@ -473,18 +482,19 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
        return dsymptr(s, ot, pkg.Pathsym, 0)
 }
 
-// uncommonType
-// ../../../../runtime/type.go:/uncommonType
-func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
+// dextratype dumps the fields of a runtime.uncommontype.
+// dataAdd is the offset in bytes after the header where the
+// backing array of the []method field is written (by dextratypeData).
+func dextratype(sym *Sym, off int, t *Type, dataAdd int) int {
        m := methods(t)
        if t.Sym == nil && len(m) == 0 {
                return off
        }
-
-       // fill in *extraType pointer in header
-       off = int(Rnd(int64(off), int64(Widthptr)))
-
-       dsymptr(sym, ptroff, sym, off)
+       noff := int(Rnd(int64(off), int64(Widthptr)))
+       if noff != off {
+               panic("dextratype rounding does something. :-(")
+       }
+       off = noff
 
        for _, a := range m {
                dtypesym(a.type_)
@@ -499,14 +509,19 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
        }
 
        // slice header
-       ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+       ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd)
 
        n := len(m)
        ot = duintxx(s, ot, uint64(n), Widthint)
        ot = duintxx(s, ot, uint64(n), Widthint)
 
-       // methods
-       for _, a := range m {
+       return ot
+}
+
+// dextratypeData dumps the backing array for the []method field of
+// runtime.uncommontype.
+func dextratypeData(s *Sym, ot int, t *Type) int {
+       for _, a := range methods(t) {
                // method
                // ../../../../runtime/type.go:/method
                ot = dgostringptr(s, ot, a.name)
@@ -525,7 +540,6 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
                        ot = duintptr(s, ot, 0)
                }
        }
-
        return ot
 }
 
@@ -674,8 +688,11 @@ func typeptrdata(t *Type) int64 {
        }
 }
 
+// tflag is documented in ../../../../reflect/type.go.
+const tflagUncommon = 1
+
 // commonType
-// ../../runtime/type.go:/commonType
+// ../../../../runtime/type.go:/commonType
 
 var dcommontype_algarray *Sym
 
@@ -713,20 +730,24 @@ func dcommontype(s *Sym, ot int, t *Type) int {
        //              size          uintptr
        //              ptrdata       uintptr
        //              hash          uint32
-       //              _             uint8
+       //              tflag         tflag
        //              align         uint8
        //              fieldAlign    uint8
        //              kind          uint8
        //              alg           *typeAlg
        //              gcdata        *byte
        //              string        *string
-       //              *uncommonType
        //      }
        ot = duintptr(s, ot, uint64(t.Width))
        ot = duintptr(s, ot, uint64(ptrdata))
 
        ot = duint32(s, ot, typehash(t))
-       ot = duint8(s, ot, 0) // unused
+
+       var tflag uint8
+       if uncommonSize(t) != 0 {
+               tflag |= tflagUncommon
+       }
+       ot = duint8(s, ot, tflag)
 
        // runtime (and common sense) expects alignment to be a power of two.
        i := int(t.Align)
@@ -776,13 +797,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
        _, symdata := stringsym(p) // string
        ot = dsymptr(s, ot, symdata, prefix)
        ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint)
-       //fmt.Printf("dcommontype: %s\n", p)
-
-       // skip pointer to extraType,
-       // which follows the rest of this type structure.
-       // caller will fill in if needed.
-       // otherwise linker will assume 0.
-       ot += Widthptr
 
        return ot
 }
@@ -1000,11 +1014,10 @@ func dtypesym(t *Type) *Sym {
 
 ok:
        ot := 0
-       xt := 0
        switch t.Etype {
        default:
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
+               ot = dextratype(s, ot, t, 0)
 
        case TARRAY:
                if t.Bound >= 0 {
@@ -1016,7 +1029,6 @@ ok:
                        t2.Bound = -1 // slice
                        s2 := dtypesym(t2)
                        ot = dcommontype(s, ot, t)
-                       xt = ot - 1*Widthptr
                        ot = dsymptr(s, ot, s1, 0)
                        ot = dsymptr(s, ot, s2, 0)
                        ot = duintptr(s, ot, uint64(t.Bound))
@@ -1025,18 +1037,18 @@ ok:
                        s1 := dtypesym(t.Type)
 
                        ot = dcommontype(s, ot, t)
-                       xt = ot - 1*Widthptr
                        ot = dsymptr(s, ot, s1, 0)
                }
+               ot = dextratype(s, ot, t, 0)
 
        // ../../../../runtime/type.go:/chanType
        case TCHAN:
                s1 := dtypesym(t.Type)
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
                ot = duintptr(s, ot, uint64(t.Chan))
+               ot = dextratype(s, ot, t, 0)
 
        case TFUNC:
                for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
@@ -1053,20 +1065,31 @@ ok:
                }
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
                ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
 
                // two slice headers: in and out.
                ot = int(Rnd(int64(ot), int64(Widthptr)))
 
-               ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint))
+               ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint)+uncommonSize(t))
                n := t.Thistuple + t.Intuple
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
-               ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+n*Widthptr)
+               ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+uncommonSize(t)+n*Widthptr)
                ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
                ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
 
+               dataAdd := 0
+               for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
+                       dataAdd += Widthptr
+               }
+               for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
+                       dataAdd += Widthptr
+               }
+               for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
+                       dataAdd += Widthptr
+               }
+               ot = dextratype(s, ot, t, dataAdd)
+
                // slice data
                for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
                        ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
@@ -1091,14 +1114,15 @@ ok:
                // ../../../../runtime/type.go:/interfaceType
                ot = dcommontype(s, ot, t)
 
-               xt = ot - 1*Widthptr
-               ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+               ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
+               dataAdd := imethodSize() * n
+               ot = dextratype(s, ot, t, dataAdd)
+
                for _, a := range m {
                        // ../../../../runtime/type.go:/imethod
                        ot = dgostringptr(s, ot, a.name)
-
                        ot = dgopkgpath(s, ot, a.pkg)
                        ot = dsymptr(s, ot, dtypesym(a.type_), 0)
                }
@@ -1111,7 +1135,6 @@ ok:
                s3 := dtypesym(mapbucket(t))
                s4 := dtypesym(hmap(t))
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
                ot = dsymptr(s, ot, s2, 0)
                ot = dsymptr(s, ot, s3, 0)
@@ -1135,11 +1158,13 @@ ok:
                ot = duint16(s, ot, uint16(mapbucket(t).Width))
                ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
                ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
+               ot = dextratype(s, ot, t, 0)
 
        case TPTR32, TPTR64:
                if t.Type.Etype == TANY {
                        // ../../../../runtime/type.go:/UnsafePointerType
                        ot = dcommontype(s, ot, t)
+                       ot = dextratype(s, ot, t, 0)
 
                        break
                }
@@ -1148,8 +1173,8 @@ ok:
                s1 := dtypesym(t.Type)
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
+               ot = dextratype(s, ot, t, 0)
 
        // ../../../../runtime/type.go:/structType
        // for security, only the exported fields.
@@ -1162,12 +1187,15 @@ ok:
                }
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 1*Widthptr
-               ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+               ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
+
+               dataAdd := n * structfieldSize()
+               ot = dextratype(s, ot, t, dataAdd)
+
                for t1 := t.Type; t1 != nil; t1 = t1.Down {
-                       // ../../../../runtime/type.go:/structField
+                       // ../../../../runtime/type.go:/structfield
                        if t1.Sym != nil && t1.Embedded == 0 {
                                ot = dgostringptr(s, ot, t1.Sym.Name)
                                if exportname(t1.Sym.Name) {
@@ -1191,7 +1219,7 @@ ok:
                }
        }
 
-       ot = dextratype(s, ot, t, xt)
+       ot = dextratypeData(s, ot, t)
        ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
 
        // generate typelink.foo pointing at s = type.foo.
index ec3a9b56131be3f87c76ded0b61e074e9aa0150e..89cf0b0564dbdca983461a889471fb0690803dd8 100644 (file)
@@ -44,11 +44,9 @@ func decode_inuxi(p []byte, sz int) uint64 {
        }
 }
 
-// commonsize returns the size of the common prefix for all type
-// structures (runtime._type).
-func commonsize() int {
-       return 7*Thearch.Ptrsize + 8
-}
+func commonsize() int      { return 6*Thearch.Ptrsize + 8 }                 // runtime._type
+func structfieldSize() int { return 5 * Thearch.Ptrsize }                   // runtime.structfield
+func uncommonSize() int    { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
 
 // Type.commonType.kind
 func decodetype_kind(s *LSym) uint8 {
@@ -75,6 +73,12 @@ func decodetype_ptrdata(s *LSym) int64 {
        return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
 }
 
+// Type.commonType.tflag
+func decodetype_hasUncommon(s *LSym) bool {
+       const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
+       return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0
+}
+
 // Find the elf.Section of a given shared library that contains a given address.
 func findShlibSection(path string, addr uint64) *elf.Section {
        for _, shlib := range Ctxt.Shlibs {
@@ -201,15 +205,18 @@ func decodetype_structfieldcount(s *LSym) int {
        return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
 }
 
-func structfieldsize() int {
-       return 5 * Thearch.Ptrsize
+func decodetype_structfieldarrayoff(s *LSym, i int) int {
+       off := commonsize() + Thearch.Ptrsize + 2*Thearch.Intsize
+       if decodetype_hasUncommon(s) {
+               off += uncommonSize()
+       }
+       off += i * structfieldSize()
+       return off
 }
 
-// Type.StructType.fields[]-> name, typ and offset.
 func decodetype_structfieldname(s *LSym, i int) string {
-       // go.string."foo"  0x28 / 0x40
-       s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
-
+       off := decodetype_structfieldarrayoff(s, i)
+       s = decode_reloc_sym(s, int32(off))
        if s == nil { // embedded structs have a nil name.
                return ""
        }
@@ -222,11 +229,13 @@ func decodetype_structfieldname(s *LSym, i int) string {
 }
 
 func decodetype_structfieldtype(s *LSym, i int) *LSym {
-       return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
+       off := decodetype_structfieldarrayoff(s, i)
+       return decode_reloc_sym(s, int32(off+2*Thearch.Ptrsize))
 }
 
 func decodetype_structfieldoffs(s *LSym, i int) int64 {
-       return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
+       off := decodetype_structfieldarrayoff(s, i)
+       return int64(decode_inuxi(s.P[off+4*Thearch.Ptrsize:], Thearch.Intsize))
 }
 
 // InterfaceType.methods.length
index 425b27588173d3a3701986583ea5e99278d75dd0..de0768a45f223178bc4bd65d3ebe19affb0db18e 100644 (file)
@@ -240,22 +240,40 @@ const (
        UnsafePointer
 )
 
+// tflag is used by an rtype to signal what extra type information is
+// available in the memory directly following the rtype value.
+type tflag uint8
+
+const (
+       // tflagUncommon means that there is a pointer, *uncommonType,
+       // just beyond the outer type structure.
+       //
+       // For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0,
+       // then t has uncommonType data and it can be accessed as:
+       //
+       //      type tUncommon struct {
+       //              structType
+       //              u uncommonType
+       //      }
+       //      u := &(*tUncommon)(unsafe.Pointer(t)).u
+       tflagUncommon tflag = 1
+)
+
 // rtype is the common implementation of most values.
 // It is embedded in other, public struct types, but always
 // with a unique tag like `reflect:"array"` or `reflect:"ptr"`
 // so that code cannot convert from, say, *arrayType to *ptrType.
 type rtype struct {
-       size          uintptr
-       ptrdata       uintptr
-       hash          uint32   // hash of type; avoids computation in hash tables
-       _             uint8    // unused/padding
-       align         uint8    // alignment of variable with this type
-       fieldAlign    uint8    // alignment of struct field with this type
-       kind          uint8    // enumeration for C
-       alg           *typeAlg // algorithm table
-       gcdata        *byte    // garbage collection data
-       string        string   // string form; unnecessary but undeniably useful
-       *uncommonType          // (relatively) uncommon fields
+       size       uintptr
+       ptrdata    uintptr
+       hash       uint32   // hash of type; avoids computation in hash tables
+       tflag      tflag    // extra type information flags
+       align      uint8    // alignment of variable with this type
+       fieldAlign uint8    // alignment of struct field with this type
+       kind       uint8    // enumeration for C
+       alg        *typeAlg // algorithm table
+       gcdata     *byte    // garbage collection data
+       string     string   // string form; unnecessary but undeniably useful
 }
 
 // a copy of runtime.typeAlg
@@ -440,10 +458,6 @@ var kindNames = []string{
        UnsafePointer: "unsafe.Pointer",
 }
 
-func (t *uncommonType) uncommon() *uncommonType {
-       return t
-}
-
 func (t *uncommonType) PkgPath() string {
        if t == nil || t.pkgPath == nil {
                return ""
@@ -451,6 +465,68 @@ func (t *uncommonType) PkgPath() string {
        return *t.pkgPath
 }
 
+func (t *rtype) uncommon() *uncommonType {
+       if t.tflag&tflagUncommon == 0 {
+               return nil
+       }
+       switch t.Kind() {
+       case Struct:
+               type u struct {
+                       structType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Ptr:
+               type u struct {
+                       ptrType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Func:
+               type u struct {
+                       funcType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Slice:
+               type u struct {
+                       sliceType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Array:
+               type u struct {
+                       arrayType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Chan:
+               type u struct {
+                       chanType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Map:
+               type u struct {
+                       mapType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case Interface:
+               type u struct {
+                       interfaceType
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       default:
+               type u struct {
+                       rtype
+                       u uncommonType
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       }
+}
+
 func (t *rtype) String() string { return t.string }
 
 func (t *rtype) Size() uintptr { return t.size }
@@ -526,7 +602,7 @@ func (t *rtype) NumMethod() int {
                tt := (*interfaceType)(unsafe.Pointer(t))
                return tt.NumMethod()
        }
-       return t.uncommonType.NumMethod()
+       return t.uncommon().NumMethod()
 }
 
 func (t *rtype) Method(i int) (m Method) {
@@ -534,7 +610,7 @@ func (t *rtype) Method(i int) (m Method) {
                tt := (*interfaceType)(unsafe.Pointer(t))
                return tt.Method(i)
        }
-       return t.uncommonType.Method(i)
+       return t.uncommon().Method(i)
 }
 
 func (t *rtype) MethodByName(name string) (m Method, ok bool) {
@@ -542,11 +618,11 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) {
                tt := (*interfaceType)(unsafe.Pointer(t))
                return tt.MethodByName(name)
        }
-       return t.uncommonType.MethodByName(name)
+       return t.uncommon().MethodByName(name)
 }
 
 func (t *rtype) PkgPath() string {
-       return t.uncommonType.PkgPath()
+       return t.uncommon().PkgPath()
 }
 
 func hasPrefix(s, prefix string) bool {
@@ -1099,7 +1175,6 @@ func (t *rtype) ptrTo() *rtype {
        // old hash and the new "*".
        p.hash = fnv1(t.hash, '*')
 
-       p.uncommonType = nil
        p.elem = t
 
        ptrMap.m[t] = p
@@ -1477,7 +1552,6 @@ func ChanOf(dir ChanDir, t Type) Type {
        ch.string = s
        ch.hash = fnv1(typ.hash, 'c', byte(dir))
        ch.elem = typ
-       ch.uncommonType = nil
 
        return cachePut(ckey, &ch.rtype)
 }
@@ -1539,7 +1613,6 @@ func MapOf(key, elem Type) Type {
        mt.bucketsize = uint16(mt.bucket.size)
        mt.reflexivekey = isReflexive(ktyp)
        mt.needkeyupdate = needKeyUpdate(ktyp)
-       mt.uncommonType = nil
 
        return cachePut(ckey, &mt.rtype)
 }
@@ -1617,7 +1690,6 @@ func FuncOf(in, out []Type, variadic bool) Type {
 
        // Populate the remaining fields of ft and store in cache.
        ft.string = str
-       ft.uncommonType = nil
        funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
 
        return &ft.rtype
@@ -1846,7 +1918,6 @@ func SliceOf(t Type) Type {
        slice.string = s
        slice.hash = fnv1(typ.hash, '[')
        slice.elem = typ
-       slice.uncommonType = nil
 
        return cachePut(ckey, &slice.rtype)
 }
@@ -1903,7 +1974,6 @@ func ArrayOf(count int, elem Type) Type {
        }
        array.align = typ.align
        array.fieldAlign = typ.fieldAlign
-       array.uncommonType = nil
        array.len = uintptr(count)
        array.slice = slice.(*rtype)
 
index 508ee9a916136e4653370f5129a700008ba16464..ae63b2182cfb2d831b79e548844209cc80af5d50 100644 (file)
@@ -183,10 +183,10 @@ func dumptype(t *_type) {
        dumpint(tagType)
        dumpint(uint64(uintptr(unsafe.Pointer(t))))
        dumpint(uint64(t.size))
-       if t.x == nil || t.x.pkgpath == nil {
+       if x := t.uncommon(); x == nil || x.pkgpath == nil {
                dumpstr(t._string)
        } else {
-               pkgpath := stringStructOf(t.x.pkgpath)
+               pkgpath := stringStructOf(x.pkgpath)
                namestr := t.name()
                name := stringStructOf(&namestr)
                dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
index 917b5b3f2a747b55e7c3cec23cbf4df2340d0687..ff54c59a5287fa02dcada24d0fa8856b1deedfe1 100644 (file)
@@ -25,7 +25,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
        }
 
        // easy case
-       x := typ.x
+       x := typ.uncommon()
        if x == nil {
                if canfail {
                        return nil
@@ -89,6 +89,9 @@ search:
                itype := i._type
                for ; j < nt; j++ {
                        t := &x.mhdr[j]
+                       if t.name == nil {
+                               throw("itab t.name is nil")
+                       }
                        if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
                                if m != nil {
                                        *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn
index 95cd1ef2f5c55e721aeb0b2a2ae790e3c19c2e38..6d5378200e19ce97ff4ea7ec9a51c8dd524b8bb9 100644 (file)
@@ -340,7 +340,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
                // ok - same type
                goto okarg
        case fint.kind&kindMask == kindPtr:
-               if (fint.x == nil || etyp.x == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
+               if (fint.uncommon() == nil || etyp.uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
                        // ok - not same type, but both pointers,
                        // one or the other is unnamed, and same element type, so assignable.
                        goto okarg
index 2312f819ea0db2a4cb334a99407c2cd9d2e20654..9c9b5fb8cc5688a5d6e4d80d1e945d9a9090ff0d 100644 (file)
@@ -8,6 +8,11 @@ package runtime
 
 import "unsafe"
 
+// tflag is documented in ../reflect/type.go.
+type tflag uint8
+
+const tflagUncommon tflag = 1
+
 // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize,
 // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
 // ../reflect/type.go:/^type.rtype.
@@ -15,7 +20,7 @@ type _type struct {
        size       uintptr
        ptrdata    uintptr // size of memory prefix holding all pointers
        hash       uint32
-       _unused    uint8
+       tflag      tflag
        align      uint8
        fieldalign uint8
        kind       uint8
@@ -25,7 +30,68 @@ type _type struct {
        // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
        gcdata  *byte
        _string string
-       x       *uncommontype
+}
+
+func (t *_type) uncommon() *uncommontype {
+       if t.tflag&tflagUncommon == 0 {
+               return nil
+       }
+       switch t.kind & kindMask {
+       case kindStruct:
+               type u struct {
+                       structtype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindPtr:
+               type u struct {
+                       ptrtype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindFunc:
+               type u struct {
+                       functype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindSlice:
+               type u struct {
+                       slicetype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindArray:
+               type u struct {
+                       arraytype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindChan:
+               type u struct {
+                       chantype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindMap:
+               type u struct {
+                       maptype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       case kindInterface:
+               type u struct {
+                       interfacetype
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       default:
+               type u struct {
+                       _type
+                       u uncommontype
+               }
+               return &(*u)(unsafe.Pointer(t)).u
+       }
 }
 
 func hasPrefix(s, prefix string) bool {