mirror of https://github.com/golang/go.git
runtime: add pointer size to type structure
This adds a field to the runtime type structure that records the size of the prefix of objects of that type containing pointers. Any data after this offset is scalar data. This is necessary for shrinking the type bitmaps to 1 bit and will help the garbage collector efficiently estimate the amount of heap that needs to be scanned. Change-Id: I1318d79e6360dca0ac980245016c562e61f52ff5 Reviewed-on: https://go-review.googlesource.com/9691 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
91938fd1ca
commit
98a9d36837
|
|
@ -676,12 +676,64 @@ func haspointers(t *Type) bool {
|
|||
fallthrough
|
||||
default:
|
||||
ret = true
|
||||
|
||||
case TFIELD:
|
||||
Fatal("haspointers: unexpected type, %v", t)
|
||||
}
|
||||
|
||||
t.Haspointers = 1 + uint8(obj.Bool2int(ret))
|
||||
return ret
|
||||
}
|
||||
|
||||
// typeptrsize returns the length in bytes of the prefix of t
|
||||
// containing pointer data. Anything after this offset is scalar data.
|
||||
func typeptrsize(t *Type) uint64 {
|
||||
if !haspointers(t) {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch t.Etype {
|
||||
case TPTR32,
|
||||
TPTR64,
|
||||
TUNSAFEPTR,
|
||||
TFUNC,
|
||||
TCHAN,
|
||||
TMAP:
|
||||
return uint64(Widthptr)
|
||||
|
||||
case TSTRING:
|
||||
// struct { byte *str; intgo len; }
|
||||
return uint64(Widthptr)
|
||||
|
||||
case TINTER:
|
||||
// struct { Itab *tab; void *data; } or
|
||||
// struct { Type *type; void *data; }
|
||||
return 2 * uint64(Widthptr)
|
||||
|
||||
case TARRAY:
|
||||
if Isslice(t) {
|
||||
// struct { byte *array; uintgo len; uintgo cap; }
|
||||
return uint64(Widthptr)
|
||||
}
|
||||
// haspointers already eliminated t.Bound == 0.
|
||||
return uint64(t.Bound-1)*uint64(t.Type.Width) + typeptrsize(t.Type)
|
||||
|
||||
case TSTRUCT:
|
||||
// Find the last field that has pointers.
|
||||
var lastPtrField *Type
|
||||
for t1 := t.Type; t1 != nil; t1 = t1.Down {
|
||||
if haspointers(t1.Type) {
|
||||
lastPtrField = t1
|
||||
}
|
||||
}
|
||||
return uint64(lastPtrField.Width) + typeptrsize(lastPtrField.Type)
|
||||
|
||||
default:
|
||||
Fatal("typeptrsize: unexpected type, %v", t)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* commonType
|
||||
* ../../runtime/type.go:/commonType
|
||||
|
|
@ -728,6 +780,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
|||
// actual type structure
|
||||
// type commonType struct {
|
||||
// size uintptr
|
||||
// ptrsize uintptr
|
||||
// hash uint32
|
||||
// _ uint8
|
||||
// align uint8
|
||||
|
|
@ -741,6 +794,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
|||
// zero unsafe.Pointer
|
||||
// }
|
||||
ot = duintptr(s, ot, uint64(t.Width))
|
||||
ot = duintptr(s, ot, typeptrsize(t))
|
||||
|
||||
ot = duint32(s, ot, typehash(t))
|
||||
ot = duint8(s, ot, 0) // unused
|
||||
|
|
|
|||
|
|
@ -41,23 +41,25 @@ 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 8*Thearch.Ptrsize + 8
|
||||
return 9*Thearch.Ptrsize + 8
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_kind(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
|
||||
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_noptr(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
|
||||
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_usegcprog(s *LSym) uint8 {
|
||||
return uint8(s.P[1*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
|
||||
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.size
|
||||
|
|
@ -72,11 +74,11 @@ func decodetype_gcprog(s *LSym) *LSym {
|
|||
x := "type..gcprog." + s.Name[5:]
|
||||
return Linklookup(Ctxt, x, 0)
|
||||
}
|
||||
return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
|
||||
return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
|
||||
}
|
||||
|
||||
func decodetype_gcprog_shlib(s *LSym) uint64 {
|
||||
return decode_inuxi(s.P[1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
|
||||
return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
|
||||
}
|
||||
|
||||
func decodetype_gcmask(s *LSym) []byte {
|
||||
|
|
@ -85,7 +87,7 @@ func decodetype_gcmask(s *LSym) []byte {
|
|||
// of gcmask for types defined in that shared library.
|
||||
return s.gcmask
|
||||
}
|
||||
mask := decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
|
||||
mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
|
||||
return mask.P
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ const (
|
|||
// so that code cannot convert from, say, *arrayType to *ptrType.
|
||||
type rtype struct {
|
||||
size uintptr
|
||||
ptrsize uintptr
|
||||
hash uint32 // hash of type; avoids computation in hash tables
|
||||
_ uint8 // unused/padding
|
||||
align uint8 // alignment of variable with this type
|
||||
|
|
@ -1825,12 +1826,14 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
|
|||
}
|
||||
// overflow
|
||||
gc.append(bitsPointer)
|
||||
tptrsize := gc.size
|
||||
if runtime.GOARCH == "amd64p32" {
|
||||
gc.append(bitsScalar)
|
||||
}
|
||||
|
||||
b := new(rtype)
|
||||
b.size = gc.size
|
||||
b.ptrsize = tptrsize
|
||||
b.kind = kind
|
||||
b.gc[0], _ = gc.finalize()
|
||||
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
|
||||
|
|
@ -1917,6 +1920,9 @@ func ArrayOf(count int, elem Type) Type {
|
|||
panic("reflect.ArrayOf: array size would exceed virtual address space")
|
||||
}
|
||||
array.size = typ.size * uintptr(count)
|
||||
if count > 0 && typ.ptrsize != 0 {
|
||||
array.ptrsize = typ.size*uintptr(count-1) + typ.ptrsize
|
||||
}
|
||||
array.align = typ.align
|
||||
array.fieldAlign = typ.fieldAlign
|
||||
array.uncommonType = nil
|
||||
|
|
@ -2084,6 +2090,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
// build dummy rtype holding gc program
|
||||
x := new(rtype)
|
||||
x.size = gc.size
|
||||
x.ptrsize = gc.size // over-approximation
|
||||
var hasPtr bool
|
||||
x.gc[0], hasPtr = gc.finalize()
|
||||
if !hasPtr {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,12 @@ package runtime
|
|||
|
||||
import "unsafe"
|
||||
|
||||
// Needs to be in sync with ../../cmd/internal/ld/decodesym.go:/^commonsize and pkg/reflect/type.go:/type.
|
||||
// Needs to be in sync with ../cmd/internal/ld/decodesym.go:/^func.commonsize,
|
||||
// ../cmd/internal/gc/reflect.go:/^func.dcommontype and
|
||||
// ../reflect/type.go:/^type.rtype.
|
||||
type _type struct {
|
||||
size uintptr
|
||||
ptrsize uintptr // Bytes of prefix containing pointer slots.
|
||||
hash uint32
|
||||
_unused uint8
|
||||
align uint8
|
||||
|
|
|
|||
Loading…
Reference in New Issue