Commit 98a9d368 authored by Austin Clements's avatar Austin Clements

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/9691Reviewed-by: default avatarRuss Cox <rsc@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 91938fd1
...@@ -676,12 +676,64 @@ func haspointers(t *Type) bool { ...@@ -676,12 +676,64 @@ func haspointers(t *Type) bool {
fallthrough fallthrough
default: default:
ret = true ret = true
case TFIELD:
Fatal("haspointers: unexpected type, %v", t)
} }
t.Haspointers = 1 + uint8(obj.Bool2int(ret)) t.Haspointers = 1 + uint8(obj.Bool2int(ret))
return 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 * commonType
* ../../runtime/type.go:/commonType * ../../runtime/type.go:/commonType
...@@ -728,6 +780,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -728,6 +780,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// actual type structure // actual type structure
// type commonType struct { // type commonType struct {
// size uintptr // size uintptr
// ptrsize uintptr
// hash uint32 // hash uint32
// _ uint8 // _ uint8
// align uint8 // align uint8
...@@ -741,6 +794,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -741,6 +794,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// zero unsafe.Pointer // zero unsafe.Pointer
// } // }
ot = duintptr(s, ot, uint64(t.Width)) ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, typeptrsize(t))
ot = duint32(s, ot, typehash(t)) ot = duint32(s, ot, typehash(t))
ot = duint8(s, ot, 0) // unused ot = duint8(s, ot, 0) // unused
......
...@@ -41,23 +41,25 @@ func decode_inuxi(p []byte, sz int) uint64 { ...@@ -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 { func commonsize() int {
return 8*Thearch.Ptrsize + 8 return 9*Thearch.Ptrsize + 8
} }
// Type.commonType.kind // Type.commonType.kind
func decodetype_kind(s *LSym) uint8 { 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 // Type.commonType.kind
func decodetype_noptr(s *LSym) uint8 { 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 // Type.commonType.kind
func decodetype_usegcprog(s *LSym) uint8 { 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 // Type.commonType.size
...@@ -72,11 +74,11 @@ func decodetype_gcprog(s *LSym) *LSym { ...@@ -72,11 +74,11 @@ func decodetype_gcprog(s *LSym) *LSym {
x := "type..gcprog." + s.Name[5:] x := "type..gcprog." + s.Name[5:]
return Linklookup(Ctxt, x, 0) 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 { 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 { func decodetype_gcmask(s *LSym) []byte {
...@@ -85,7 +87,7 @@ 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. // of gcmask for types defined in that shared library.
return s.gcmask 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 return mask.P
} }
......
...@@ -246,6 +246,7 @@ const ( ...@@ -246,6 +246,7 @@ const (
// 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
ptrsize uintptr
hash uint32 // hash of type; avoids computation in hash tables hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused/padding _ uint8 // unused/padding
align uint8 // alignment of variable with this type align uint8 // alignment of variable with this type
...@@ -1825,12 +1826,14 @@ func bucketOf(ktyp, etyp *rtype) *rtype { ...@@ -1825,12 +1826,14 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
} }
// overflow // overflow
gc.append(bitsPointer) gc.append(bitsPointer)
tptrsize := gc.size
if runtime.GOARCH == "amd64p32" { if runtime.GOARCH == "amd64p32" {
gc.append(bitsScalar) gc.append(bitsScalar)
} }
b := new(rtype) b := new(rtype)
b.size = gc.size b.size = gc.size
b.ptrsize = tptrsize
b.kind = kind b.kind = kind
b.gc[0], _ = gc.finalize() b.gc[0], _ = gc.finalize()
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
...@@ -1917,6 +1920,9 @@ func ArrayOf(count int, elem Type) Type { ...@@ -1917,6 +1920,9 @@ func ArrayOf(count int, elem Type) Type {
panic("reflect.ArrayOf: array size would exceed virtual address space") panic("reflect.ArrayOf: array size would exceed virtual address space")
} }
array.size = typ.size * uintptr(count) 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.align = typ.align
array.fieldAlign = typ.fieldAlign array.fieldAlign = typ.fieldAlign
array.uncommonType = nil array.uncommonType = nil
...@@ -2084,6 +2090,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin ...@@ -2084,6 +2090,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
// build dummy rtype holding gc program // build dummy rtype holding gc program
x := new(rtype) x := new(rtype)
x.size = gc.size x.size = gc.size
x.ptrsize = gc.size // over-approximation
var hasPtr bool var hasPtr bool
x.gc[0], hasPtr = gc.finalize() x.gc[0], hasPtr = gc.finalize()
if !hasPtr { if !hasPtr {
......
...@@ -8,9 +8,12 @@ package runtime ...@@ -8,9 +8,12 @@ package runtime
import "unsafe" 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 { type _type struct {
size uintptr size uintptr
ptrsize uintptr // Bytes of prefix containing pointer slots.
hash uint32 hash uint32
_unused uint8 _unused uint8
align uint8 align uint8
......
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