Commit 30f93f09 authored by David Crawshaw's avatar David Crawshaw

cmd/compile: remove rtype.ptrToThis

Simplifies some code as ptrToThis was unreliable under dynamic
linking. Now the same type lookup is used regardless of execution
mode.

A synthetic relocation, R_USETYPE, is introduced to make sure the
linker includes *T on use of T, if *T is carrying methods.

Changes the heap dump format. Anything reading the format needs to
look at the last bool of a type of an interface value to determine
if the type should be the pointer-to type.

Reduces binary size of cmd/go by 0.2%.
For #6853.

Change-Id: I79fcb19a97402bdb0193f3c7f6d94ddf061ee7b2
Reviewed-on: https://go-review.googlesource.com/19695Reviewed-by: 's avatarKeith Randall <khr@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 5abd327d
...@@ -701,12 +701,14 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -701,12 +701,14 @@ func dcommontype(s *Sym, ot int, t *Type) int {
algsym = dalgsym(t) algsym = dalgsym(t)
} }
var sptr *Sym
tptr := Ptrto(t) tptr := Ptrto(t)
if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) { if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
sptr = dtypesym(tptr) sptr := dtypesym(tptr)
} else { r := obj.Addrel(Linksym(s))
sptr = weaktypesym(tptr) r.Off = 0
r.Siz = 0
r.Sym = sptr.Lsym
r.Type = obj.R_USETYPE
} }
gcsym, useGCProg, ptrdata := dgcsym(t) gcsym, useGCProg, ptrdata := dgcsym(t)
...@@ -725,7 +727,6 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -725,7 +727,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// gcdata *byte // gcdata *byte
// string *string // string *string
// *uncommonType // *uncommonType
// ptrToThis *rtype
// } // }
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))
...@@ -779,7 +780,6 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -779,7 +780,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// otherwise linker will assume 0. // otherwise linker will assume 0.
ot += Widthptr ot += Widthptr
ot = dsymptr(s, ot, sptr, 0) // ptrto type
return ot return ot
} }
...@@ -1009,7 +1009,7 @@ ok: ...@@ -1009,7 +1009,7 @@ ok:
switch t.Etype { switch t.Etype {
default: default:
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 1*Widthptr
case TARRAY: case TARRAY:
if t.Bound >= 0 { if t.Bound >= 0 {
...@@ -1021,7 +1021,7 @@ ok: ...@@ -1021,7 +1021,7 @@ 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 - 2*Widthptr 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))
...@@ -1030,7 +1030,7 @@ ok: ...@@ -1030,7 +1030,7 @@ ok:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
} }
...@@ -1039,7 +1039,7 @@ ok: ...@@ -1039,7 +1039,7 @@ ok:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr 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))
...@@ -1058,7 +1058,7 @@ ok: ...@@ -1058,7 +1058,7 @@ ok:
} }
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr 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.
...@@ -1096,7 +1096,7 @@ ok: ...@@ -1096,7 +1096,7 @@ ok:
// ../../../../runtime/type.go:/interfaceType // ../../../../runtime/type.go:/interfaceType
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint) 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)
...@@ -1116,7 +1116,7 @@ ok: ...@@ -1116,7 +1116,7 @@ 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 - 2*Widthptr 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)
...@@ -1153,7 +1153,7 @@ ok: ...@@ -1153,7 +1153,7 @@ ok:
s1 := dtypesym(t.Type) s1 := dtypesym(t.Type)
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s1, 0)
// ../../../../runtime/type.go:/structType // ../../../../runtime/type.go:/structType
...@@ -1167,7 +1167,7 @@ ok: ...@@ -1167,7 +1167,7 @@ ok:
} }
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 1*Widthptr
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint) 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)
...@@ -1206,21 +1206,7 @@ ok: ...@@ -1206,21 +1206,7 @@ ok:
// we want be able to find. // we want be able to find.
if t.Sym == nil { if t.Sym == nil {
switch t.Etype { switch t.Etype {
case TPTR32, TPTR64: case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP:
// The ptrto field of the type data cannot be relied on when
// dynamic linking: a type T may be defined in a module that makes
// no use of pointers to that type, but another module can contain
// a package that imports the first one and does use *T pointers.
// The second module will end up defining type data for *T and a
// type.*T symbol pointing at it. It's important that calling
// .PtrTo() on the reflect.Type for T returns this type data and
// not some synthesized object, so we need reflect to be able to
// find it!
if !Ctxt.Flag_dynlink {
break
}
fallthrough
case TARRAY, TCHAN, TFUNC, TMAP:
slink := typelinksym(t) slink := typelinksym(t)
dsymptr(slink, 0, s, 0) dsymptr(slink, 0, s, 0)
ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA)) ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
......
...@@ -444,6 +444,11 @@ const ( ...@@ -444,6 +444,11 @@ const (
R_PLT1 R_PLT1
R_PLT2 R_PLT2
R_USEFIELD R_USEFIELD
// R_USETYPE resolves to an *rtype, but no relocation is created. The
// linker uses this as a signal that the pointed-to type information
// should be linked into the final binary, even if there are no other
// direct references. (This is used for types reachable by reflection.)
R_USETYPE
R_POWER_TOC R_POWER_TOC
R_GOTPCREL R_GOTPCREL
// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
......
...@@ -47,7 +47,7 @@ func decode_inuxi(p []byte, sz int) uint64 { ...@@ -47,7 +47,7 @@ func decode_inuxi(p []byte, sz int) uint64 {
// commonsize returns the size of the common prefix for all type // commonsize returns the size of the common prefix for all type
// structures (runtime._type). // structures (runtime._type).
func commonsize() int { func commonsize() int {
return 8*Thearch.Ptrsize + 8 return 7*Thearch.Ptrsize + 8
} }
// Type.commonType.kind // Type.commonType.kind
......
...@@ -256,7 +256,6 @@ type rtype struct { ...@@ -256,7 +256,6 @@ type rtype struct {
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 *uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
} }
// a copy of runtime.typeAlg // a copy of runtime.typeAlg
...@@ -1030,15 +1029,7 @@ func PtrTo(t Type) Type { ...@@ -1030,15 +1029,7 @@ func PtrTo(t Type) Type {
} }
func (t *rtype) ptrTo() *rtype { func (t *rtype) ptrTo() *rtype {
if p := t.ptrToThis; p != nil { // Check the cache.
return p
}
// Otherwise, synthesize one.
// This only happens for pointers with no methods.
// We keep the mapping in a map on the side, because
// this operation is rare and a separate map lets us keep
// the type structures in read-only memory.
ptrMap.RLock() ptrMap.RLock()
if m := ptrMap.m; m != nil { if m := ptrMap.m; m != nil {
if p := m[t]; p != nil { if p := m[t]; p != nil {
...@@ -1047,6 +1038,7 @@ func (t *rtype) ptrTo() *rtype { ...@@ -1047,6 +1038,7 @@ func (t *rtype) ptrTo() *rtype {
} }
} }
ptrMap.RUnlock() ptrMap.RUnlock()
ptrMap.Lock() ptrMap.Lock()
if ptrMap.m == nil { if ptrMap.m == nil {
ptrMap.m = make(map[*rtype]*ptrType) ptrMap.m = make(map[*rtype]*ptrType)
...@@ -1086,7 +1078,6 @@ func (t *rtype) ptrTo() *rtype { ...@@ -1086,7 +1078,6 @@ func (t *rtype) ptrTo() *rtype {
p.hash = fnv1(t.hash, '*') p.hash = fnv1(t.hash, '*')
p.uncommonType = nil p.uncommonType = nil
p.ptrToThis = nil
p.elem = t p.elem = t
ptrMap.m[t] = p ptrMap.m[t] = p
...@@ -1310,7 +1301,7 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { ...@@ -1310,7 +1301,7 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
// Note that strings are not unique identifiers for types: // Note that strings are not unique identifiers for types:
// there can be more than one with a given string. // there can be more than one with a given string.
// Only types we might want to look up are included: // Only types we might want to look up are included:
// channels, maps, slices, and arrays. // pointers, channels, maps, slices, and arrays.
func typelinks() [][]*rtype func typelinks() [][]*rtype
// typesByString returns the subslice of typelinks() whose elements have // typesByString returns the subslice of typelinks() whose elements have
...@@ -1465,7 +1456,6 @@ func ChanOf(dir ChanDir, t Type) Type { ...@@ -1465,7 +1456,6 @@ func ChanOf(dir ChanDir, t Type) Type {
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 ch.uncommonType = nil
ch.ptrToThis = nil
return cachePut(ckey, &ch.rtype) return cachePut(ckey, &ch.rtype)
} }
...@@ -1528,7 +1518,6 @@ func MapOf(key, elem Type) Type { ...@@ -1528,7 +1518,6 @@ func MapOf(key, elem Type) Type {
mt.reflexivekey = isReflexive(ktyp) mt.reflexivekey = isReflexive(ktyp)
mt.needkeyupdate = needKeyUpdate(ktyp) mt.needkeyupdate = needKeyUpdate(ktyp)
mt.uncommonType = nil mt.uncommonType = nil
mt.ptrToThis = nil
return cachePut(ckey, &mt.rtype) return cachePut(ckey, &mt.rtype)
} }
...@@ -1607,7 +1596,6 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1607,7 +1596,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 ft.uncommonType = nil
ft.ptrToThis = 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
...@@ -1837,7 +1825,6 @@ func SliceOf(t Type) Type { ...@@ -1837,7 +1825,6 @@ func SliceOf(t Type) Type {
slice.hash = fnv1(typ.hash, '[') slice.hash = fnv1(typ.hash, '[')
slice.elem = typ slice.elem = typ
slice.uncommonType = nil slice.uncommonType = nil
slice.ptrToThis = nil
return cachePut(ckey, &slice.rtype) return cachePut(ckey, &slice.rtype)
} }
...@@ -1895,7 +1882,6 @@ func ArrayOf(count int, elem Type) Type { ...@@ -1895,7 +1882,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.uncommonType = nil
array.ptrToThis = nil
array.len = uintptr(count) array.len = uintptr(count)
array.slice = slice.(*rtype) array.slice = slice.(*rtype)
......
...@@ -502,28 +502,10 @@ func dumpparams() { ...@@ -502,28 +502,10 @@ func dumpparams() {
func itab_callback(tab *itab) { func itab_callback(tab *itab) {
t := tab._type t := tab._type
// Dump a map from itab* to the type of its data field. dumptype(t)
// We want this map so we can deduce types of interface referents. dumpint(tagItab)
if t.kind&kindDirectIface == 0 { dumpint(uint64(uintptr(unsafe.Pointer(tab))))
// indirect - data slot is a pointer to t. dumpint(uint64(uintptr(unsafe.Pointer(t))))
dumptype(t.ptrto)
dumpint(tagItab)
dumpint(uint64(uintptr(unsafe.Pointer(tab))))
dumpint(uint64(uintptr(unsafe.Pointer(t.ptrto))))
} else if t.kind&kindNoPointers == 0 {
// t is pointer-like - data slot is a t.
dumptype(t)
dumpint(tagItab)
dumpint(uint64(uintptr(unsafe.Pointer(tab))))
dumpint(uint64(uintptr(unsafe.Pointer(t))))
} else {
// Data slot is a scalar. Dump type just for fun.
// With pointer-only interfaces, this shouldn't happen.
dumptype(t)
dumpint(tagItab)
dumpint(uint64(uintptr(unsafe.Pointer(tab))))
dumpint(uint64(uintptr(unsafe.Pointer(t))))
}
} }
func dumpitabs() { func dumpitabs() {
...@@ -639,7 +621,7 @@ func dumpmemprof() { ...@@ -639,7 +621,7 @@ func dumpmemprof() {
} }
} }
var dumphdr = []byte("go1.6 heap dump\n") var dumphdr = []byte("go1.7 heap dump\n")
func mdump() { func mdump() {
// make sure we're done sweeping // make sure we're done sweeping
......
...@@ -26,7 +26,6 @@ type _type struct { ...@@ -26,7 +26,6 @@ type _type struct {
gcdata *byte gcdata *byte
_string string _string string
x *uncommontype x *uncommontype
ptrto *_type
} }
type method struct { type method struct {
......
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