aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/gc/reflect.go37
-rw-r--r--src/cmd/link/internal/ld/decodesym.go27
-rw-r--r--src/cmd/link/internal/ld/dwarf.go2
-rw-r--r--src/reflect/type.go149
-rw-r--r--src/reflect/value.go13
-rw-r--r--src/runtime/mfinal.go11
-rw-r--r--src/runtime/syscall_windows.go6
-rw-r--r--src/runtime/type.go30
8 files changed, 187 insertions, 88 deletions
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index a18016fa78..b234333d5e 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -1059,49 +1059,34 @@ ok:
isddd = t1.Isddd
dtypesym(t1.Type)
}
-
for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
dtypesym(t1.Type)
}
ot = dcommontype(s, ot, t)
- ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
-
- // two slice headers: in and out.
- ot = int(Rnd(int64(ot), int64(Widthptr)))
-
- 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
+ inCount := t.Thistuple + t.Intuple
+ outCount := t.Outtuple
+ if isddd {
+ outCount |= 1 << 15
}
- for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
- dataAdd += Widthptr
- }
- for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
- dataAdd += Widthptr
+ ot = duint16(s, ot, uint16(inCount))
+ ot = duint16(s, ot, uint16(outCount))
+ if Widthptr == 8 {
+ ot += 4 // align for *rtype
}
+
+ dataAdd := (inCount + outCount) * Widthptr
ot = dextratype(s, ot, t, dataAdd)
- // slice data
+ // Array of rtype pointers follows funcType.
for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
- n++
}
for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
- n++
}
for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
- n++
}
case TINTER:
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 89cf0b0564..78da6848b5 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -171,33 +171,32 @@ func decodetype_chanelem(s *LSym) *LSym {
}
// Type.FuncType.dotdotdot
-func decodetype_funcdotdotdot(s *LSym) int {
- return int(s.P[commonsize()])
+func decodetype_funcdotdotdot(s *LSym) bool {
+ 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 {
- 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 {
- 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 {
- r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
- if r == nil {
- return nil
+ uadd := commonsize() + 4
+ if Thearch.Ptrsize == 8 {
+ 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 {
- r := decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
- if r == nil {
- return nil
- }
- return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+ return decodetype_funcintype(s, i+decodetype_funcincount(s))
}
// Type.StructType.fields.Slice::length
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 829d8dabf2..81f7c306f2 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -984,7 +984,7 @@ func defgotype(gotype *LSym) *DWDie {
newrefattr(fld, DW_AT_type, defgotype(s))
}
- if decodetype_funcdotdotdot(gotype) != 0 {
+ if decodetype_funcdotdotdot(gotype) {
newdie(die, DW_ABRV_DOTDOTDOT, "...")
}
nfields = decodetype_funcoutcount(gotype)
diff --git a/src/reflect/type.go b/src/reflect/type.go
index de0768a45f..44ab004274 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -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
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 8af39b12ac..95bfdb561c 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -483,9 +483,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Copy argument frame into Values.
ptr := frame
off := uintptr(0)
- in := make([]Value, 0, len(ftyp.in))
- for _, arg := range ftyp.in {
- typ := arg
+ in := make([]Value, 0, int(ftyp.inCount))
+ for _, typ := range ftyp.in() {
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
v := Value{typ, nil, flag(typ.Kind())}
@@ -506,18 +505,18 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Call underlying function.
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")
}
// Copy results back into argument frame.
- if len(ftyp.out) > 0 {
+ if numOut > 0 {
off += -off & (ptrSize - 1)
if runtime.GOARCH == "amd64p32" {
off = align(off, 8)
}
- for i, arg := range ftyp.out {
- typ := arg
+ for i, typ := range ftyp.out() {
v := out[i]
if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(f) +
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 6d5378200e..1238d4a053 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -331,10 +331,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function")
}
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)
}
- fint := ft.in[0]
+ fint := ft.in()[0]
switch {
case fint == etyp:
// ok - same type
@@ -359,8 +362,8 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
okarg:
// compute size needed for return parameters
nret := uintptr(0)
- for _, t := range ft.out {
- nret = round(nret, uintptr(t.align)) + t.size
+ for _, t := range ft.out() {
+ nret = round(nret, uintptr(t.align)) + uintptr(t.size)
}
nret = round(nret, sys.PtrSize)
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 081516c70a..ebfa32ff8c 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -45,15 +45,15 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
panic("compileCallback: not a function")
}
ft := (*functype)(unsafe.Pointer(fn._type))
- if len(ft.out) != 1 {
+ if len(ft.out()) != 1 {
panic("compileCallback: function must have one output parameter")
}
uintptrSize := unsafe.Sizeof(uintptr(0))
- if ft.out[0].size != uintptrSize {
+ if ft.out()[0].size != uintptrSize {
panic("compileCallback: output parameter size is wrong")
}
argsize := uintptr(0)
- for _, t := range ft.in {
+ for _, t := range ft.in() {
if t.size > uintptrSize {
panic("compileCallback: input parameter size is wrong")
}
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 9c9b5fb8cc..c504e2d294 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -128,6 +128,29 @@ func (t *_type) name() string {
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 {
name *string
pkgpath *string
@@ -187,10 +210,9 @@ type slicetype struct {
}
type functype struct {
- typ _type
- dotdotdot bool
- in []*_type
- out []*_type
+ typ _type
+ inCount uint16
+ outCount uint16
}
type ptrtype struct {