Commit a24b3ed7 authored by David Crawshaw's avatar David Crawshaw

cmd/compile: remove rtype *uncommonType field

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/19790Reviewed-by: default avatarRuss Cox <rsc@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 0321cabd
...@@ -53,6 +53,15 @@ const ( ...@@ -53,6 +53,15 @@ const (
MAXVALSIZE = 128 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 { func makefield(name string, t *Type) *Type {
f := typ(TFIELD) f := typ(TFIELD)
f.Type = t f.Type = t
...@@ -473,18 +482,19 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int { ...@@ -473,18 +482,19 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
return dsymptr(s, ot, pkg.Pathsym, 0) return dsymptr(s, ot, pkg.Pathsym, 0)
} }
// uncommonType // dextratype dumps the fields of a runtime.uncommontype.
// ../../../../runtime/type.go:/uncommonType // dataAdd is the offset in bytes after the header where the
func dextratype(sym *Sym, off int, t *Type, ptroff int) int { // backing array of the []method field is written (by dextratypeData).
func dextratype(sym *Sym, off int, t *Type, dataAdd int) int {
m := methods(t) m := methods(t)
if t.Sym == nil && len(m) == 0 { if t.Sym == nil && len(m) == 0 {
return off return off
} }
noff := int(Rnd(int64(off), int64(Widthptr)))
// fill in *extraType pointer in header if noff != off {
off = int(Rnd(int64(off), int64(Widthptr))) panic("dextratype rounding does something. :-(")
}
dsymptr(sym, ptroff, sym, off) off = noff
for _, a := range m { for _, a := range m {
dtypesym(a.type_) dtypesym(a.type_)
...@@ -499,14 +509,19 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int { ...@@ -499,14 +509,19 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
} }
// slice header // slice header
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint) ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd)
n := len(m) n := len(m)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
// methods return ot
for _, a := range m { }
// 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 // method
// ../../../../runtime/type.go:/method // ../../../../runtime/type.go:/method
ot = dgostringptr(s, ot, a.name) ot = dgostringptr(s, ot, a.name)
...@@ -525,7 +540,6 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int { ...@@ -525,7 +540,6 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
ot = duintptr(s, ot, 0) ot = duintptr(s, ot, 0)
} }
} }
return ot return ot
} }
...@@ -674,8 +688,11 @@ func typeptrdata(t *Type) int64 { ...@@ -674,8 +688,11 @@ func typeptrdata(t *Type) int64 {
} }
} }
// tflag is documented in ../../../../reflect/type.go.
const tflagUncommon = 1
// commonType // commonType
// ../../runtime/type.go:/commonType // ../../../../runtime/type.go:/commonType
var dcommontype_algarray *Sym var dcommontype_algarray *Sym
...@@ -713,20 +730,24 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -713,20 +730,24 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// size uintptr // size uintptr
// ptrdata uintptr // ptrdata uintptr
// hash uint32 // hash uint32
// _ uint8 // tflag tflag
// align uint8 // align uint8
// fieldAlign uint8 // fieldAlign uint8
// kind uint8 // kind uint8
// alg *typeAlg // alg *typeAlg
// gcdata *byte // gcdata *byte
// string *string // string *string
// *uncommonType
// } // }
ot = duintptr(s, ot, uint64(t.Width)) ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata)) ot = duintptr(s, ot, uint64(ptrdata))
ot = duint32(s, ot, typehash(t)) 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. // runtime (and common sense) expects alignment to be a power of two.
i := int(t.Align) i := int(t.Align)
...@@ -776,13 +797,6 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -776,13 +797,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
_, symdata := stringsym(p) // string _, symdata := stringsym(p) // string
ot = dsymptr(s, ot, symdata, prefix) ot = dsymptr(s, ot, symdata, prefix)
ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint) 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 return ot
} }
...@@ -1000,11 +1014,10 @@ func dtypesym(t *Type) *Sym { ...@@ -1000,11 +1014,10 @@ func dtypesym(t *Type) *Sym {
ok: ok:
ot := 0 ot := 0
xt := 0
switch t.Etype { switch t.Etype {
default: default:
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr ot = dextratype(s, ot, t, 0)
case TARRAY: case TARRAY:
if t.Bound >= 0 { if t.Bound >= 0 {
...@@ -1016,7 +1029,6 @@ ok: ...@@ -1016,7 +1029,6 @@ ok:
t2.Bound = -1 // slice t2.Bound = -1 // slice
s2 := dtypesym(t2) s2 := dtypesym(t2)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
ot = dsymptr(s, ot, s2, 0) ot = dsymptr(s, ot, s2, 0)
ot = duintptr(s, ot, uint64(t.Bound)) ot = duintptr(s, ot, uint64(t.Bound))
...@@ -1025,18 +1037,18 @@ ok: ...@@ -1025,18 +1037,18 @@ ok:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
} }
ot = dextratype(s, ot, t, 0)
// ../../../../runtime/type.go:/chanType // ../../../../runtime/type.go:/chanType
case TCHAN: case TCHAN:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
ot = duintptr(s, ot, uint64(t.Chan)) ot = duintptr(s, ot, uint64(t.Chan))
ot = dextratype(s, ot, t, 0)
case TFUNC: case TFUNC:
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down { for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
...@@ -1053,20 +1065,31 @@ ok: ...@@ -1053,20 +1065,31 @@ ok:
} }
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = duint8(s, ot, uint8(obj.Bool2int(isddd))) ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
// two slice headers: in and out. // two slice headers: in and out.
ot = int(Rnd(int64(ot), int64(Widthptr))) 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 n := t.Thistuple + t.Intuple
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
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)
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 // slice data
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down { for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0) ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
...@@ -1091,14 +1114,15 @@ ok: ...@@ -1091,14 +1114,15 @@ ok:
// ../../../../runtime/type.go:/interfaceType // ../../../../runtime/type.go:/interfaceType
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
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 { for _, a := range m {
// ../../../../runtime/type.go:/imethod // ../../../../runtime/type.go:/imethod
ot = dgostringptr(s, ot, a.name) ot = dgostringptr(s, ot, a.name)
ot = dgopkgpath(s, ot, a.pkg) ot = dgopkgpath(s, ot, a.pkg)
ot = dsymptr(s, ot, dtypesym(a.type_), 0) ot = dsymptr(s, ot, dtypesym(a.type_), 0)
} }
...@@ -1111,7 +1135,6 @@ ok: ...@@ -1111,7 +1135,6 @@ ok:
s3 := dtypesym(mapbucket(t)) s3 := dtypesym(mapbucket(t))
s4 := dtypesym(hmap(t)) s4 := dtypesym(hmap(t))
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
ot = dsymptr(s, ot, s2, 0) ot = dsymptr(s, ot, s2, 0)
ot = dsymptr(s, ot, s3, 0) ot = dsymptr(s, ot, s3, 0)
...@@ -1135,11 +1158,13 @@ ok: ...@@ -1135,11 +1158,13 @@ ok:
ot = duint16(s, ot, uint16(mapbucket(t).Width)) 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(isreflexive(t.Down))))
ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down)))) ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
ot = dextratype(s, ot, t, 0)
case TPTR32, TPTR64: case TPTR32, TPTR64:
if t.Type.Etype == TANY { if t.Type.Etype == TANY {
// ../../../../runtime/type.go:/UnsafePointerType // ../../../../runtime/type.go:/UnsafePointerType
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
ot = dextratype(s, ot, t, 0)
break break
} }
...@@ -1148,8 +1173,8 @@ ok: ...@@ -1148,8 +1173,8 @@ ok:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
ot = dextratype(s, ot, t, 0)
// ../../../../runtime/type.go:/structType // ../../../../runtime/type.go:/structType
// for security, only the exported fields. // for security, only the exported fields.
...@@ -1162,12 +1187,15 @@ ok: ...@@ -1162,12 +1187,15 @@ ok:
} }
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 1*Widthptr ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
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 { for t1 := t.Type; t1 != nil; t1 = t1.Down {
// ../../../../runtime/type.go:/structField // ../../../../runtime/type.go:/structfield
if t1.Sym != nil && t1.Embedded == 0 { if t1.Sym != nil && t1.Embedded == 0 {
ot = dgostringptr(s, ot, t1.Sym.Name) ot = dgostringptr(s, ot, t1.Sym.Name)
if exportname(t1.Sym.Name) { if exportname(t1.Sym.Name) {
...@@ -1191,7 +1219,7 @@ ok: ...@@ -1191,7 +1219,7 @@ ok:
} }
} }
ot = dextratype(s, ot, t, xt) ot = dextratypeData(s, ot, t)
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
// generate typelink.foo pointing at s = type.foo. // generate typelink.foo pointing at s = type.foo.
......
...@@ -44,11 +44,9 @@ func decode_inuxi(p []byte, sz int) uint64 { ...@@ -44,11 +44,9 @@ func decode_inuxi(p []byte, sz int) uint64 {
} }
} }
// commonsize returns the size of the common prefix for all type func commonsize() int { return 6*Thearch.Ptrsize + 8 } // runtime._type
// structures (runtime._type). func structfieldSize() int { return 5 * Thearch.Ptrsize } // runtime.structfield
func commonsize() int { func uncommonSize() int { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
return 7*Thearch.Ptrsize + 8
}
// Type.commonType.kind // Type.commonType.kind
func decodetype_kind(s *LSym) uint8 { func decodetype_kind(s *LSym) uint8 {
...@@ -75,6 +73,12 @@ func decodetype_ptrdata(s *LSym) int64 { ...@@ -75,6 +73,12 @@ func decodetype_ptrdata(s *LSym) int64 {
return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10 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. // Find the elf.Section of a given shared library that contains a given address.
func findShlibSection(path string, addr uint64) *elf.Section { func findShlibSection(path string, addr uint64) *elf.Section {
for _, shlib := range Ctxt.Shlibs { for _, shlib := range Ctxt.Shlibs {
...@@ -201,15 +205,18 @@ func decodetype_structfieldcount(s *LSym) int { ...@@ -201,15 +205,18 @@ func decodetype_structfieldcount(s *LSym) int {
return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize)) return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
} }
func structfieldsize() int { func decodetype_structfieldarrayoff(s *LSym, i int) int {
return 5 * Thearch.Ptrsize 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 { func decodetype_structfieldname(s *LSym, i int) string {
// go.string."foo" 0x28 / 0x40 off := decodetype_structfieldarrayoff(s, i)
s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())) s = decode_reloc_sym(s, int32(off))
if s == nil { // embedded structs have a nil name. if s == nil { // embedded structs have a nil name.
return "" return ""
} }
...@@ -222,11 +229,13 @@ func decodetype_structfieldname(s *LSym, i int) string { ...@@ -222,11 +229,13 @@ func decodetype_structfieldname(s *LSym, i int) string {
} }
func decodetype_structfieldtype(s *LSym, i int) *LSym { 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 { 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 // InterfaceType.methods.length
......
...@@ -240,22 +240,40 @@ const ( ...@@ -240,22 +240,40 @@ const (
UnsafePointer 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. // rtype is the common implementation of most values.
// It is embedded in other, public struct types, but always // It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"` // with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType. // so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct { type rtype struct {
size uintptr size uintptr
ptrdata uintptr ptrdata uintptr
hash uint32 // hash of type; avoids computation in hash tables hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused/padding tflag tflag // extra type information flags
align uint8 // alignment of variable with this type align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C kind uint8 // enumeration for C
alg *typeAlg // algorithm table alg *typeAlg // algorithm table
gcdata *byte // garbage collection data gcdata *byte // garbage collection data
string string // string form; unnecessary but undeniably useful string string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
} }
// a copy of runtime.typeAlg // a copy of runtime.typeAlg
...@@ -440,10 +458,6 @@ var kindNames = []string{ ...@@ -440,10 +458,6 @@ var kindNames = []string{
UnsafePointer: "unsafe.Pointer", UnsafePointer: "unsafe.Pointer",
} }
func (t *uncommonType) uncommon() *uncommonType {
return t
}
func (t *uncommonType) PkgPath() string { func (t *uncommonType) PkgPath() string {
if t == nil || t.pkgPath == nil { if t == nil || t.pkgPath == nil {
return "" return ""
...@@ -451,6 +465,68 @@ func (t *uncommonType) PkgPath() string { ...@@ -451,6 +465,68 @@ func (t *uncommonType) PkgPath() string {
return *t.pkgPath 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) String() string { return t.string }
func (t *rtype) Size() uintptr { return t.size } func (t *rtype) Size() uintptr { return t.size }
...@@ -526,7 +602,7 @@ func (t *rtype) NumMethod() int { ...@@ -526,7 +602,7 @@ func (t *rtype) NumMethod() int {
tt := (*interfaceType)(unsafe.Pointer(t)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod() return tt.NumMethod()
} }
return t.uncommonType.NumMethod() return t.uncommon().NumMethod()
} }
func (t *rtype) Method(i int) (m Method) { func (t *rtype) Method(i int) (m Method) {
...@@ -534,7 +610,7 @@ 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)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i) return tt.Method(i)
} }
return t.uncommonType.Method(i) return t.uncommon().Method(i)
} }
func (t *rtype) MethodByName(name string) (m Method, ok bool) { func (t *rtype) MethodByName(name string) (m Method, ok bool) {
...@@ -542,11 +618,11 @@ 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)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.MethodByName(name) return tt.MethodByName(name)
} }
return t.uncommonType.MethodByName(name) return t.uncommon().MethodByName(name)
} }
func (t *rtype) PkgPath() string { func (t *rtype) PkgPath() string {
return t.uncommonType.PkgPath() return t.uncommon().PkgPath()
} }
func hasPrefix(s, prefix string) bool { func hasPrefix(s, prefix string) bool {
...@@ -1099,7 +1175,6 @@ func (t *rtype) ptrTo() *rtype { ...@@ -1099,7 +1175,6 @@ func (t *rtype) ptrTo() *rtype {
// old hash and the new "*". // old hash and the new "*".
p.hash = fnv1(t.hash, '*') p.hash = fnv1(t.hash, '*')
p.uncommonType = nil
p.elem = t p.elem = t
ptrMap.m[t] = p ptrMap.m[t] = p
...@@ -1477,7 +1552,6 @@ func ChanOf(dir ChanDir, t Type) Type { ...@@ -1477,7 +1552,6 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.string = s ch.string = s
ch.hash = fnv1(typ.hash, 'c', byte(dir)) ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ ch.elem = typ
ch.uncommonType = nil
return cachePut(ckey, &ch.rtype) return cachePut(ckey, &ch.rtype)
} }
...@@ -1539,7 +1613,6 @@ func MapOf(key, elem Type) Type { ...@@ -1539,7 +1613,6 @@ func MapOf(key, elem Type) Type {
mt.bucketsize = uint16(mt.bucket.size) mt.bucketsize = uint16(mt.bucket.size)
mt.reflexivekey = isReflexive(ktyp) mt.reflexivekey = isReflexive(ktyp)
mt.needkeyupdate = needKeyUpdate(ktyp) mt.needkeyupdate = needKeyUpdate(ktyp)
mt.uncommonType = nil
return cachePut(ckey, &mt.rtype) return cachePut(ckey, &mt.rtype)
} }
...@@ -1617,7 +1690,6 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1617,7 +1690,6 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Populate the remaining fields of ft and store in cache. // Populate the remaining fields of ft and store in cache.
ft.string = str ft.string = str
ft.uncommonType = nil
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
return &ft.rtype return &ft.rtype
...@@ -1846,7 +1918,6 @@ func SliceOf(t Type) Type { ...@@ -1846,7 +1918,6 @@ func SliceOf(t Type) Type {
slice.string = s slice.string = s
slice.hash = fnv1(typ.hash, '[') slice.hash = fnv1(typ.hash, '[')
slice.elem = typ slice.elem = typ
slice.uncommonType = nil
return cachePut(ckey, &slice.rtype) return cachePut(ckey, &slice.rtype)
} }
...@@ -1903,7 +1974,6 @@ func ArrayOf(count int, elem Type) Type { ...@@ -1903,7 +1974,6 @@ func ArrayOf(count int, elem Type) Type {
} }
array.align = typ.align array.align = typ.align
array.fieldAlign = typ.fieldAlign array.fieldAlign = typ.fieldAlign
array.uncommonType = nil
array.len = uintptr(count) array.len = uintptr(count)
array.slice = slice.(*rtype) array.slice = slice.(*rtype)
......
...@@ -183,10 +183,10 @@ func dumptype(t *_type) { ...@@ -183,10 +183,10 @@ func dumptype(t *_type) {
dumpint(tagType) dumpint(tagType)
dumpint(uint64(uintptr(unsafe.Pointer(t)))) dumpint(uint64(uintptr(unsafe.Pointer(t))))
dumpint(uint64(t.size)) dumpint(uint64(t.size))
if t.x == nil || t.x.pkgpath == nil { if x := t.uncommon(); x == nil || x.pkgpath == nil {
dumpstr(t._string) dumpstr(t._string)
} else { } else {
pkgpath := stringStructOf(t.x.pkgpath) pkgpath := stringStructOf(x.pkgpath)
namestr := t.name() namestr := t.name()
name := stringStructOf(&namestr) name := stringStructOf(&namestr)
dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len))) dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
......
...@@ -25,7 +25,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { ...@@ -25,7 +25,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
} }
// easy case // easy case
x := typ.x x := typ.uncommon()
if x == nil { if x == nil {
if canfail { if canfail {
return nil return nil
...@@ -89,6 +89,9 @@ search: ...@@ -89,6 +89,9 @@ search:
itype := i._type itype := i._type
for ; j < nt; j++ { for ; j < nt; j++ {
t := &x.mhdr[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 t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
if m != nil { if m != nil {
*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn
......
...@@ -340,7 +340,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { ...@@ -340,7 +340,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
// ok - same type // ok - same type
goto okarg goto okarg
case fint.kind&kindMask == kindPtr: 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, // ok - not same type, but both pointers,
// one or the other is unnamed, and same element type, so assignable. // one or the other is unnamed, and same element type, so assignable.
goto okarg goto okarg
......
...@@ -8,6 +8,11 @@ package runtime ...@@ -8,6 +8,11 @@ package runtime
import "unsafe" 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, // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize,
// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
// ../reflect/type.go:/^type.rtype. // ../reflect/type.go:/^type.rtype.
...@@ -15,7 +20,7 @@ type _type struct { ...@@ -15,7 +20,7 @@ type _type struct {
size uintptr size uintptr
ptrdata uintptr // size of memory prefix holding all pointers ptrdata uintptr // size of memory prefix holding all pointers
hash uint32 hash uint32
_unused uint8 tflag tflag
align uint8 align uint8
fieldalign uint8 fieldalign uint8
kind uint8 kind uint8
...@@ -25,7 +30,68 @@ type _type struct { ...@@ -25,7 +30,68 @@ type _type struct {
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
gcdata *byte gcdata *byte
_string string _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 { func hasPrefix(s, prefix string) bool {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment