Commit 8df733bd authored by David Crawshaw's avatar David Crawshaw

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/19916Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent b050adee
...@@ -1059,49 +1059,34 @@ ok: ...@@ -1059,49 +1059,34 @@ ok:
isddd = t1.Isddd isddd = t1.Isddd
dtypesym(t1.Type) dtypesym(t1.Type)
} }
for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down { for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
dtypesym(t1.Type) dtypesym(t1.Type)
} }
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
ot = duint8(s, ot, uint8(obj.Bool2int(isddd))) inCount := t.Thistuple + t.Intuple
outCount := t.Outtuple
// two slice headers: in and out. if isddd {
ot = int(Rnd(int64(ot), int64(Widthptr))) outCount |= 1 << 15
ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint)+uncommonSize(t))
n := t.Thistuple + t.Intuple
ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint)
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)
dataAdd := 0
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
dataAdd += Widthptr
} }
for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down { ot = duint16(s, ot, uint16(inCount))
dataAdd += Widthptr ot = duint16(s, ot, uint16(outCount))
} if Widthptr == 8 {
for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down { ot += 4 // align for *rtype
dataAdd += Widthptr
} }
dataAdd := (inCount + outCount) * Widthptr
ot = dextratype(s, ot, t, dataAdd) ot = dextratype(s, ot, t, dataAdd)
// slice data // Array of rtype pointers follows funcType.
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)
n++
} }
for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down { for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0) ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
n++
} }
for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down { for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0) ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
n++
} }
case TINTER: case TINTER:
......
...@@ -171,33 +171,32 @@ func decodetype_chanelem(s *LSym) *LSym { ...@@ -171,33 +171,32 @@ func decodetype_chanelem(s *LSym) *LSym {
} }
// Type.FuncType.dotdotdot // Type.FuncType.dotdotdot
func decodetype_funcdotdotdot(s *LSym) int { func decodetype_funcdotdotdot(s *LSym) bool {
return int(s.P[commonsize()]) return uint16(decode_inuxi(s.P[commonsize()+2:], 2))&(1<<15) != 0
} }
// Type.FuncType.in.length // Type.FuncType.inCount
func decodetype_funcincount(s *LSym) int { func decodetype_funcincount(s *LSym) int {
return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize)) return int(decode_inuxi(s.P[commonsize():], 2))
} }
func decodetype_funcoutcount(s *LSym) int { func decodetype_funcoutcount(s *LSym) int {
return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize)) return int(uint16(decode_inuxi(s.P[commonsize()+2:], 2)) & (1<<15 - 1))
} }
func decodetype_funcintype(s *LSym, i int) *LSym { func decodetype_funcintype(s *LSym, i int) *LSym {
r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize)) uadd := commonsize() + 4
if r == nil { if Thearch.Ptrsize == 8 {
return nil uadd += 4
}
if decodetype_hasUncommon(s) {
uadd += uncommonSize()
} }
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize)))) return decode_reloc_sym(s, int32(uadd+i*Thearch.Ptrsize))
} }
func decodetype_funcouttype(s *LSym, i int) *LSym { func decodetype_funcouttype(s *LSym, i int) *LSym {
r := decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)) return decodetype_funcintype(s, i+decodetype_funcincount(s))
if r == nil {
return nil
}
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
} }
// Type.StructType.fields.Slice::length // Type.StructType.fields.Slice::length
......
...@@ -984,7 +984,7 @@ func defgotype(gotype *LSym) *DWDie { ...@@ -984,7 +984,7 @@ func defgotype(gotype *LSym) *DWDie {
newrefattr(fld, DW_AT_type, defgotype(s)) newrefattr(fld, DW_AT_type, defgotype(s))
} }
if decodetype_funcdotdotdot(gotype) != 0 { if decodetype_funcdotdotdot(gotype) {
newdie(die, DW_ABRV_DOTDOTDOT, "...") newdie(die, DW_ABRV_DOTDOTDOT, "...")
} }
nfields = decodetype_funcoutcount(gotype) nfields = decodetype_funcoutcount(gotype)
......
...@@ -330,11 +330,20 @@ type chanType struct { ...@@ -330,11 +330,20 @@ type chanType struct {
} }
// funcType represents a function type. // 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 { type funcType struct {
rtype `reflect:"func"` rtype `reflect:"func"`
dotdotdot bool // last input parameter is ... inCount uint16
in []*rtype // input parameter types outCount uint16 // top bit is set if last input parameter is ...
out []*rtype // output parameter types
} }
// imethod represents a method on an interface type // imethod represents a method on an interface type
...@@ -672,7 +681,7 @@ func (t *rtype) IsVariadic() bool { ...@@ -672,7 +681,7 @@ func (t *rtype) IsVariadic() bool {
panic("reflect: IsVariadic of non-func type") panic("reflect: IsVariadic of non-func type")
} }
tt := (*funcType)(unsafe.Pointer(t)) tt := (*funcType)(unsafe.Pointer(t))
return tt.dotdotdot return tt.outCount&(1<<15) != 0
} }
func (t *rtype) Elem() Type { func (t *rtype) Elem() Type {
...@@ -733,7 +742,7 @@ func (t *rtype) In(i int) Type { ...@@ -733,7 +742,7 @@ func (t *rtype) In(i int) Type {
panic("reflect: In of non-func type") panic("reflect: In of non-func type")
} }
tt := (*funcType)(unsafe.Pointer(t)) tt := (*funcType)(unsafe.Pointer(t))
return toType(tt.in[i]) return toType(tt.in()[i])
} }
func (t *rtype) Key() Type { func (t *rtype) Key() Type {
...@@ -765,7 +774,7 @@ func (t *rtype) NumIn() int { ...@@ -765,7 +774,7 @@ func (t *rtype) NumIn() int {
panic("reflect: NumIn of non-func type") panic("reflect: NumIn of non-func type")
} }
tt := (*funcType)(unsafe.Pointer(t)) tt := (*funcType)(unsafe.Pointer(t))
return len(tt.in) return int(tt.inCount)
} }
func (t *rtype) NumOut() int { func (t *rtype) NumOut() int {
...@@ -773,7 +782,7 @@ func (t *rtype) NumOut() int { ...@@ -773,7 +782,7 @@ func (t *rtype) NumOut() int {
panic("reflect: NumOut of non-func type") panic("reflect: NumOut of non-func type")
} }
tt := (*funcType)(unsafe.Pointer(t)) tt := (*funcType)(unsafe.Pointer(t))
return len(tt.out) return len(tt.out())
} }
func (t *rtype) Out(i int) Type { func (t *rtype) Out(i int) Type {
...@@ -781,7 +790,28 @@ 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") panic("reflect: Out of non-func type")
} }
tt := (*funcType)(unsafe.Pointer(t)) 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 { func (d ChanDir) String() string {
...@@ -1330,16 +1360,16 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { ...@@ -1330,16 +1360,16 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
case Func: case Func:
t := (*funcType)(unsafe.Pointer(T)) t := (*funcType)(unsafe.Pointer(T))
v := (*funcType)(unsafe.Pointer(V)) 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 return false
} }
for i, typ := range t.in { for i := 0; i < t.NumIn(); i++ {
if typ != v.in[i] { if t.In(i) != v.In(i) {
return false return false
} }
} }
for i, typ := range t.out { for i := 0; i < t.NumOut(); i++ {
if typ != v.out[i] { if t.Out(i) != v.Out(i) {
return false return false
} }
} }
...@@ -1617,6 +1647,31 @@ func MapOf(key, elem Type) Type { ...@@ -1617,6 +1647,31 @@ func MapOf(key, elem Type) Type {
return cachePut(ckey, &mt.rtype) 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. // FuncOf returns the function type with the given argument and result types.
// For example if k represents int and e represents string, // For example if k represents int and e represents string,
// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string. // FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
...@@ -1632,15 +1687,45 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1632,15 +1687,45 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Make a func type. // Make a func type.
var ifunc interface{} = (func())(nil) var ifunc interface{} = (func())(nil)
prototype := *(**funcType)(unsafe.Pointer(&ifunc)) 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 *ft = *prototype
// Build a hash and minimally populate ft. // Build a hash and minimally populate ft.
var hash uint32 var hash uint32
var fin, fout []*rtype
for _, in := range in { for _, in := range in {
t := in.(*rtype) 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)) hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
} }
if variadic { if variadic {
...@@ -1649,13 +1734,18 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1649,13 +1734,18 @@ func FuncOf(in, out []Type, variadic bool) Type {
hash = fnv1(hash, '.') hash = fnv1(hash, '.')
for _, out := range out { for _, out := range out {
t := out.(*rtype) 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)) 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.hash = hash
ft.in = fin ft.inCount = uint16(len(in))
ft.out = fout ft.outCount = uint16(len(out))
ft.dotdotdot = variadic if variadic {
ft.outCount |= 1 << 15
}
// Look in cache. // Look in cache.
funcLookupCache.RLock() funcLookupCache.RLock()
...@@ -1699,11 +1789,11 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1699,11 +1789,11 @@ func FuncOf(in, out []Type, variadic bool) Type {
func funcStr(ft *funcType) string { func funcStr(ft *funcType) string {
repr := make([]byte, 0, 64) repr := make([]byte, 0, 64)
repr = append(repr, "func("...) repr = append(repr, "func("...)
for i, t := range ft.in { for i, t := range ft.in() {
if i > 0 { if i > 0 {
repr = append(repr, ", "...) 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, "..."...)
repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...) repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...)
} else { } else {
...@@ -1711,18 +1801,19 @@ func funcStr(ft *funcType) string { ...@@ -1711,18 +1801,19 @@ func funcStr(ft *funcType) string {
} }
} }
repr = append(repr, ')') repr = append(repr, ')')
if l := len(ft.out); l == 1 { out := ft.out()
if len(out) == 1 {
repr = append(repr, ' ') repr = append(repr, ' ')
} else if l > 1 { } else if len(out) > 1 {
repr = append(repr, " ("...) repr = append(repr, " ("...)
} }
for i, t := range ft.out { for i, t := range out {
if i > 0 { if i > 0 {
repr = append(repr, ", "...) repr = append(repr, ", "...)
} }
repr = append(repr, t.string...) repr = append(repr, t.string...)
} }
if len(ft.out) > 1 { if len(out) > 1 {
repr = append(repr, ')') repr = append(repr, ')')
} }
return string(repr) return string(repr)
...@@ -2175,7 +2266,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin ...@@ -2175,7 +2266,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
} }
offset += ptrSize offset += ptrSize
} }
for _, arg := range tt.in { for _, arg := range tt.in() {
offset += -offset & uintptr(arg.align-1) offset += -offset & uintptr(arg.align-1)
addTypeBits(ptrmap, offset, arg) addTypeBits(ptrmap, offset, arg)
offset += arg.size offset += arg.size
...@@ -2187,7 +2278,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin ...@@ -2187,7 +2278,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
} }
offset += -offset & (ptrSize - 1) offset += -offset & (ptrSize - 1)
retOffset = offset retOffset = offset
for _, res := range tt.out { for _, res := range tt.out() {
offset += -offset & uintptr(res.align-1) offset += -offset & uintptr(res.align-1)
addTypeBits(ptrmap, offset, res) addTypeBits(ptrmap, offset, res)
offset += res.size offset += res.size
......
...@@ -483,9 +483,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { ...@@ -483,9 +483,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Copy argument frame into Values. // Copy argument frame into Values.
ptr := frame ptr := frame
off := uintptr(0) off := uintptr(0)
in := make([]Value, 0, len(ftyp.in)) in := make([]Value, 0, int(ftyp.inCount))
for _, arg := range ftyp.in { for _, typ := range ftyp.in() {
typ := arg
off += -off & uintptr(typ.align-1) off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off) addr := unsafe.Pointer(uintptr(ptr) + off)
v := Value{typ, nil, flag(typ.Kind())} v := Value{typ, nil, flag(typ.Kind())}
...@@ -506,18 +505,18 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { ...@@ -506,18 +505,18 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Call underlying function. // Call underlying function.
out := f(in) out := f(in)
if len(out) != len(ftyp.out) { numOut := ftyp.NumOut()
if len(out) != numOut {
panic("reflect: wrong return count from function created by MakeFunc") panic("reflect: wrong return count from function created by MakeFunc")
} }
// Copy results back into argument frame. // Copy results back into argument frame.
if len(ftyp.out) > 0 { if numOut > 0 {
off += -off & (ptrSize - 1) off += -off & (ptrSize - 1)
if runtime.GOARCH == "amd64p32" { if runtime.GOARCH == "amd64p32" {
off = align(off, 8) off = align(off, 8)
} }
for i, arg := range ftyp.out { for i, typ := range ftyp.out() {
typ := arg
v := out[i] v := out[i]
if v.typ != typ { if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(f) + panic("reflect: function created by MakeFunc using " + funcName(f) +
......
...@@ -331,10 +331,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { ...@@ -331,10 +331,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function") throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function")
} }
ft := (*functype)(unsafe.Pointer(ftyp)) ft := (*functype)(unsafe.Pointer(ftyp))
if ft.dotdotdot || len(ft.in) != 1 { if ft.dotdotdot() {
throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string + " because dotdotdot")
}
if ft.dotdotdot() || ft.inCount != 1 {
throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string) throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string)
} }
fint := ft.in[0] fint := ft.in()[0]
switch { switch {
case fint == etyp: case fint == etyp:
// ok - same type // ok - same type
...@@ -359,8 +362,8 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { ...@@ -359,8 +362,8 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
okarg: okarg:
// compute size needed for return parameters // compute size needed for return parameters
nret := uintptr(0) nret := uintptr(0)
for _, t := range ft.out { for _, t := range ft.out() {
nret = round(nret, uintptr(t.align)) + t.size nret = round(nret, uintptr(t.align)) + uintptr(t.size)
} }
nret = round(nret, sys.PtrSize) nret = round(nret, sys.PtrSize)
......
...@@ -45,15 +45,15 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { ...@@ -45,15 +45,15 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
panic("compileCallback: not a function") panic("compileCallback: not a function")
} }
ft := (*functype)(unsafe.Pointer(fn._type)) ft := (*functype)(unsafe.Pointer(fn._type))
if len(ft.out) != 1 { if len(ft.out()) != 1 {
panic("compileCallback: function must have one output parameter") panic("compileCallback: function must have one output parameter")
} }
uintptrSize := unsafe.Sizeof(uintptr(0)) uintptrSize := unsafe.Sizeof(uintptr(0))
if ft.out[0].size != uintptrSize { if ft.out()[0].size != uintptrSize {
panic("compileCallback: output parameter size is wrong") panic("compileCallback: output parameter size is wrong")
} }
argsize := uintptr(0) argsize := uintptr(0)
for _, t := range ft.in { for _, t := range ft.in() {
if t.size > uintptrSize { if t.size > uintptrSize {
panic("compileCallback: input parameter size is wrong") panic("compileCallback: input parameter size is wrong")
} }
......
...@@ -128,6 +128,29 @@ func (t *_type) name() string { ...@@ -128,6 +128,29 @@ func (t *_type) name() string {
return t._string[i+1:] return t._string[i+1:]
} }
func (t *functype) in() []*_type {
// See funcType in reflect/type.go for details on data layout.
uadd := uintptr(unsafe.Sizeof(functype{}))
if t.typ.tflag&tflagUncommon != 0 {
uadd += unsafe.Sizeof(uncommontype{})
}
return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
}
func (t *functype) out() []*_type {
// See funcType in reflect/type.go for details on data layout.
uadd := uintptr(unsafe.Sizeof(functype{}))
if t.typ.tflag&tflagUncommon != 0 {
uadd += unsafe.Sizeof(uncommontype{})
}
outCount := t.outCount & (1<<15 - 1)
return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
}
func (t *functype) dotdotdot() bool {
return t.outCount&(1<<15) != 0
}
type method struct { type method struct {
name *string name *string
pkgpath *string pkgpath *string
...@@ -187,10 +210,9 @@ type slicetype struct { ...@@ -187,10 +210,9 @@ type slicetype struct {
} }
type functype struct { type functype struct {
typ _type typ _type
dotdotdot bool inCount uint16
in []*_type outCount uint16
out []*_type
} }
type ptrtype struct { type ptrtype 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