mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: remove slices from rtype.funcType
Alternative to golang.org/cl/19852. This memory layout doesn't have
an easy type representation, but it is noticeably smaller than the
current funcType, and saves significant extra space.
Some notes on the layout are in reflect/type.go:
// A *rtype for each in and out parameter is stored in an array that
// directly follows the funcType (and possibly its uncommonType). So
// a function type with one method, one input, and one output is:
//
// struct {
// funcType
// uncommonType
// [2]*rtype // [0] is in, [1] is out
// uncommonTypeSliceContents
// }
There are three arbitrary limits introduced by this CL:
1. No more than 65535 function input parameters.
2. No more than 32767 function output parameters.
3. reflect.FuncOf is limited to 128 parameters.
I don't think these are limits in practice, but are worth noting.
Reduces godoc binary size by 2.4%, 330KB.
For #6853.
Change-Id: I225c0a0516ebdbe92d41dfdf43f716da42dfe347
Reviewed-on: https://go-review.googlesource.com/19916
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
b050adeebd
commit
8df733bd22
8 changed files with 187 additions and 88 deletions
|
|
@ -330,11 +330,20 @@ type chanType struct {
|
|||
}
|
||||
|
||||
// funcType represents a function type.
|
||||
//
|
||||
// A *rtype for each in and out parameter is stored in an array that
|
||||
// directly follows the funcType (and possibly its uncommonType). So
|
||||
// a function type with one method, one input, and one output is:
|
||||
//
|
||||
// struct {
|
||||
// funcType
|
||||
// uncommonType
|
||||
// [2]*rtype // [0] is in, [1] is out
|
||||
// }
|
||||
type funcType struct {
|
||||
rtype `reflect:"func"`
|
||||
dotdotdot bool // last input parameter is ...
|
||||
in []*rtype // input parameter types
|
||||
out []*rtype // output parameter types
|
||||
rtype `reflect:"func"`
|
||||
inCount uint16
|
||||
outCount uint16 // top bit is set if last input parameter is ...
|
||||
}
|
||||
|
||||
// imethod represents a method on an interface type
|
||||
|
|
@ -672,7 +681,7 @@ func (t *rtype) IsVariadic() bool {
|
|||
panic("reflect: IsVariadic of non-func type")
|
||||
}
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
return tt.dotdotdot
|
||||
return tt.outCount&(1<<15) != 0
|
||||
}
|
||||
|
||||
func (t *rtype) Elem() Type {
|
||||
|
|
@ -733,7 +742,7 @@ func (t *rtype) In(i int) Type {
|
|||
panic("reflect: In of non-func type")
|
||||
}
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
return toType(tt.in[i])
|
||||
return toType(tt.in()[i])
|
||||
}
|
||||
|
||||
func (t *rtype) Key() Type {
|
||||
|
|
@ -765,7 +774,7 @@ func (t *rtype) NumIn() int {
|
|||
panic("reflect: NumIn of non-func type")
|
||||
}
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
return len(tt.in)
|
||||
return int(tt.inCount)
|
||||
}
|
||||
|
||||
func (t *rtype) NumOut() int {
|
||||
|
|
@ -773,7 +782,7 @@ func (t *rtype) NumOut() int {
|
|||
panic("reflect: NumOut of non-func type")
|
||||
}
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
return len(tt.out)
|
||||
return len(tt.out())
|
||||
}
|
||||
|
||||
func (t *rtype) Out(i int) Type {
|
||||
|
|
@ -781,7 +790,28 @@ func (t *rtype) Out(i int) Type {
|
|||
panic("reflect: Out of non-func type")
|
||||
}
|
||||
tt := (*funcType)(unsafe.Pointer(t))
|
||||
return toType(tt.out[i])
|
||||
return toType(tt.out()[i])
|
||||
}
|
||||
|
||||
func (t *funcType) in() []*rtype {
|
||||
uadd := uintptr(unsafe.Sizeof(*t))
|
||||
if t.tflag&tflagUncommon != 0 {
|
||||
uadd += unsafe.Sizeof(uncommonType{})
|
||||
}
|
||||
return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd))[:t.inCount]
|
||||
}
|
||||
|
||||
func (t *funcType) out() []*rtype {
|
||||
uadd := uintptr(unsafe.Sizeof(*t))
|
||||
if t.tflag&tflagUncommon != 0 {
|
||||
uadd += unsafe.Sizeof(uncommonType{})
|
||||
}
|
||||
outCount := t.outCount & (1<<15 - 1)
|
||||
return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
|
||||
}
|
||||
|
||||
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
func (d ChanDir) String() string {
|
||||
|
|
@ -1330,16 +1360,16 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
|
|||
case Func:
|
||||
t := (*funcType)(unsafe.Pointer(T))
|
||||
v := (*funcType)(unsafe.Pointer(V))
|
||||
if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
|
||||
if t.outCount != v.outCount || t.inCount != v.inCount {
|
||||
return false
|
||||
}
|
||||
for i, typ := range t.in {
|
||||
if typ != v.in[i] {
|
||||
for i := 0; i < t.NumIn(); i++ {
|
||||
if t.In(i) != v.In(i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i, typ := range t.out {
|
||||
if typ != v.out[i] {
|
||||
for i := 0; i < t.NumOut(); i++ {
|
||||
if t.Out(i) != v.Out(i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -1617,6 +1647,31 @@ func MapOf(key, elem Type) Type {
|
|||
return cachePut(ckey, &mt.rtype)
|
||||
}
|
||||
|
||||
type funcTypeFixed4 struct {
|
||||
funcType
|
||||
args [4]*rtype
|
||||
}
|
||||
type funcTypeFixed8 struct {
|
||||
funcType
|
||||
args [8]*rtype
|
||||
}
|
||||
type funcTypeFixed16 struct {
|
||||
funcType
|
||||
args [16]*rtype
|
||||
}
|
||||
type funcTypeFixed32 struct {
|
||||
funcType
|
||||
args [32]*rtype
|
||||
}
|
||||
type funcTypeFixed64 struct {
|
||||
funcType
|
||||
args [64]*rtype
|
||||
}
|
||||
type funcTypeFixed128 struct {
|
||||
funcType
|
||||
args [128]*rtype
|
||||
}
|
||||
|
||||
// FuncOf returns the function type with the given argument and result types.
|
||||
// For example if k represents int and e represents string,
|
||||
// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
|
||||
|
|
@ -1632,15 +1687,45 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
|||
// Make a func type.
|
||||
var ifunc interface{} = (func())(nil)
|
||||
prototype := *(**funcType)(unsafe.Pointer(&ifunc))
|
||||
ft := new(funcType)
|
||||
n := len(in) + len(out)
|
||||
|
||||
var ft *funcType
|
||||
var args []*rtype
|
||||
switch {
|
||||
case n <= 4:
|
||||
fixed := new(funcTypeFixed4)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
case n <= 8:
|
||||
fixed := new(funcTypeFixed8)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
case n <= 16:
|
||||
fixed := new(funcTypeFixed16)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
case n <= 32:
|
||||
fixed := new(funcTypeFixed32)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
case n <= 64:
|
||||
fixed := new(funcTypeFixed64)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
case n <= 128:
|
||||
fixed := new(funcTypeFixed128)
|
||||
args = fixed.args[:0:len(fixed.args)]
|
||||
ft = &fixed.funcType
|
||||
default:
|
||||
panic("reflect.FuncOf: too many arguments")
|
||||
}
|
||||
*ft = *prototype
|
||||
|
||||
// Build a hash and minimally populate ft.
|
||||
var hash uint32
|
||||
var fin, fout []*rtype
|
||||
for _, in := range in {
|
||||
t := in.(*rtype)
|
||||
fin = append(fin, t)
|
||||
args = append(args, t)
|
||||
hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
|
||||
}
|
||||
if variadic {
|
||||
|
|
@ -1649,13 +1734,18 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
|||
hash = fnv1(hash, '.')
|
||||
for _, out := range out {
|
||||
t := out.(*rtype)
|
||||
fout = append(fout, t)
|
||||
args = append(args, t)
|
||||
hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
|
||||
}
|
||||
if len(args) > 50 {
|
||||
panic("reflect.FuncOf does not support more than 50 arguments")
|
||||
}
|
||||
ft.hash = hash
|
||||
ft.in = fin
|
||||
ft.out = fout
|
||||
ft.dotdotdot = variadic
|
||||
ft.inCount = uint16(len(in))
|
||||
ft.outCount = uint16(len(out))
|
||||
if variadic {
|
||||
ft.outCount |= 1 << 15
|
||||
}
|
||||
|
||||
// Look in cache.
|
||||
funcLookupCache.RLock()
|
||||
|
|
@ -1699,11 +1789,11 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
|||
func funcStr(ft *funcType) string {
|
||||
repr := make([]byte, 0, 64)
|
||||
repr = append(repr, "func("...)
|
||||
for i, t := range ft.in {
|
||||
for i, t := range ft.in() {
|
||||
if i > 0 {
|
||||
repr = append(repr, ", "...)
|
||||
}
|
||||
if ft.dotdotdot && i == len(ft.in)-1 {
|
||||
if ft.IsVariadic() && i == int(ft.inCount)-1 {
|
||||
repr = append(repr, "..."...)
|
||||
repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...)
|
||||
} else {
|
||||
|
|
@ -1711,18 +1801,19 @@ func funcStr(ft *funcType) string {
|
|||
}
|
||||
}
|
||||
repr = append(repr, ')')
|
||||
if l := len(ft.out); l == 1 {
|
||||
out := ft.out()
|
||||
if len(out) == 1 {
|
||||
repr = append(repr, ' ')
|
||||
} else if l > 1 {
|
||||
} else if len(out) > 1 {
|
||||
repr = append(repr, " ("...)
|
||||
}
|
||||
for i, t := range ft.out {
|
||||
for i, t := range out {
|
||||
if i > 0 {
|
||||
repr = append(repr, ", "...)
|
||||
}
|
||||
repr = append(repr, t.string...)
|
||||
}
|
||||
if len(ft.out) > 1 {
|
||||
if len(out) > 1 {
|
||||
repr = append(repr, ')')
|
||||
}
|
||||
return string(repr)
|
||||
|
|
@ -2175,7 +2266,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
}
|
||||
offset += ptrSize
|
||||
}
|
||||
for _, arg := range tt.in {
|
||||
for _, arg := range tt.in() {
|
||||
offset += -offset & uintptr(arg.align-1)
|
||||
addTypeBits(ptrmap, offset, arg)
|
||||
offset += arg.size
|
||||
|
|
@ -2187,7 +2278,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
|
|||
}
|
||||
offset += -offset & (ptrSize - 1)
|
||||
retOffset = offset
|
||||
for _, res := range tt.out {
|
||||
for _, res := range tt.out() {
|
||||
offset += -offset & uintptr(res.align-1)
|
||||
addTypeBits(ptrmap, offset, res)
|
||||
offset += res.size
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue