reflect: Implement MakeFunc for amd64.

From-SVN: r202982
This commit is contained in:
Ian Lance Taylor 2013-09-27 17:53:46 +00:00
parent f6113c278a
commit 8bcd5487e5
8 changed files with 676 additions and 88 deletions

View file

@ -895,9 +895,21 @@ go_path_files = \
go/path/match.go \
go/path/path.go
if LIBGO_IS_X86_64
go_reflect_makefunc_file = \
go/reflect/makefuncgo_amd64.go
go_reflect_makefunc_s_file = \
go/reflect/makefunc_amd64.S
else
go_reflect_makefunc_file =
go_reflect_makefunc_s_file = \
go/reflect/makefunc_dummy.c
endif
go_reflect_files = \
go/reflect/deepequal.go \
go/reflect/makefunc.go \
$(go_reflect_makefunc_file) \
go/reflect/type.go \
go/reflect/value.go
@ -1761,6 +1773,7 @@ libgo_go_objs = \
os.lo \
path.lo \
reflect-go.lo \
reflect/makefunc.lo \
regexp.lo \
runtime-go.lo \
sort.lo \
@ -2147,6 +2160,9 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS)
@$(CHECK)
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check
@go_include@ regexp.lo.dep

View file

@ -134,17 +134,17 @@ am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
errors.lo expvar.lo flag.lo fmt.lo hash.lo html.lo image.lo \
io.lo log.lo math.lo mime.lo net.lo os.lo path.lo \
reflect-go.lo regexp.lo runtime-go.lo sort.lo strconv.lo \
strings.lo sync.lo syscall.lo syscall/errno.lo \
syscall/signame.lo syscall/wait.lo testing.lo time-go.lo \
unicode.lo archive/tar.lo archive/zip.lo compress/bzip2.lo \
compress/flate.lo compress/gzip.lo compress/lzw.lo \
compress/zlib.lo container/heap.lo container/list.lo \
container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \
crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \
crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
reflect-go.lo reflect/makefunc.lo regexp.lo runtime-go.lo \
sort.lo strconv.lo strings.lo sync.lo syscall.lo \
syscall/errno.lo syscall/signame.lo syscall/wait.lo testing.lo \
time-go.lo unicode.lo archive/tar.lo archive/zip.lo \
compress/bzip2.lo compress/flate.lo compress/gzip.lo \
compress/lzw.lo compress/zlib.lo container/heap.lo \
container/list.lo container/ring.lo crypto/aes.lo \
crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
@ -1087,9 +1087,20 @@ go_path_files = \
go/path/match.go \
go/path/path.go
@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file =
@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \
@LIBGO_IS_X86_64_TRUE@ go/reflect/makefuncgo_amd64.go
@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
@LIBGO_IS_X86_64_FALSE@ go/reflect/makefunc_dummy.c
@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_s_file = \
@LIBGO_IS_X86_64_TRUE@ go/reflect/makefunc_amd64.S
go_reflect_files = \
go/reflect/deepequal.go \
go/reflect/makefunc.go \
$(go_reflect_makefunc_file) \
go/reflect/type.go \
go/reflect/value.go
@ -1846,6 +1857,7 @@ libgo_go_objs = \
os.lo \
path.lo \
reflect-go.lo \
reflect/makefunc.lo \
regexp.lo \
runtime-go.lo \
sort.lo \
@ -4499,6 +4511,9 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS)
@$(CHECK)
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check
@go_include@ regexp.lo.dep

View file

@ -1430,11 +1430,13 @@ func TestFunc(t *testing.T) {
}
}
/*
Not yet implemented for gccgo.
func TestMakeFunc(t *testing.T) {
switch runtime.GOARCH {
case "amd64":
default:
t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
}
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
ValueOf(&f).Elem().Set(fv)
@ -1452,8 +1454,6 @@ func TestMakeFunc(t *testing.T) {
}
}
*/
type Point struct {
x, y int
}

View file

@ -7,6 +7,7 @@
package reflect
import (
"runtime"
"unsafe"
)
@ -45,14 +46,33 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
panic("reflect: call of MakeFunc with non-Func type")
}
switch runtime.GOARCH {
case "amd64":
default:
panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
}
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
_, _ = t, ftyp
// Indirect Go func value (dummy) to obtain
// actual code address. (A Go func value is a pointer
// to a C function pointer. http://golang.org/s/go11func.)
dummy := makeFuncStub
code := **(**uintptr)(unsafe.Pointer(&dummy))
panic("reflect MakeFunc not implemented")
impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
}
// makeFuncStub is an assembly function that is the code half of
// the function returned from MakeFunc. It expects a *callReflectFunc
// as its context register, and its job is to invoke callReflect(ctxt, frame)
// where ctxt is the context register and frame is a pointer to the first
// word in the passed-in argument frame.
func makeFuncStub()
// makeMethodValue converts v from the rcvr+method index representation
// of a method value to an actual method func value, which is
// basically the receiver value with a special bit set, into a true

View file

@ -0,0 +1,107 @@
# Copyright 2013 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# MakeFunc amd64 assembly code.
.global reflect.makeFuncStub
#ifdef __ELF__
.type reflect.makeFuncStub,@function
#endif
reflect.makeFuncStub:
.cfi_startproc
# Store all the parameter registers in a struct that looks
# like:
# struct {
# rax uint64 // 0x0
# rdi uint64 // 0x8
# rsi uint64 // 0x10
# rdx uint64 // 0x18
# rcx uint64 // 0x20
# r8 uint64 // 0x28
# r9 uint64 // 0x30
# rsp uint64 // 0x38 Pointer to arguments on stack.
# xmm0 [2]uint64 // 0x40
# xmm1 [2]uint64 // 0x50
# xmm2 [2]uint64 // 0x60
# xmm3 [2]uint64 // 0x70
# xmm4 [2]uint64 // 0x80
# xmm5 [2]uint64 // 0x90
# xmm6 [2]uint64 // 0xa0
# xmm7 [2]uint64 // 0xb0
# };
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $0xc0, %rsp # Space for struct on stack.
movq %rax, 0x0(%rsp)
movq %rdi, 0x8(%rsp)
movq %rsi, 0x10(%rsp)
movq %rdx, 0x18(%rsp)
movq %rcx, 0x20(%rsp)
movq %r8, 0x28(%rsp)
movq %r9, 0x30(%rsp)
leaq 16(%rbp), %rax
movq %rax, 0x38(%rsp)
movdqa %xmm0, 0x40(%rsp)
movdqa %xmm1, 0x50(%rsp)
movdqa %xmm2, 0x60(%rsp)
movdqa %xmm3, 0x70(%rsp)
movdqa %xmm4, 0x80(%rsp)
movdqa %xmm5, 0x90(%rsp)
movdqa %xmm6, 0xa0(%rsp)
movdqa %xmm7, 0xb0(%rsp)
# Get function type.
#ifdef __PIC__
call __go_get_closure@PLT
#else
call __go_get_closure
#endif
movq %rax, %rsi
movq %rsp, %rdi
#ifdef __PIC__
call reflect.MakeFuncStubGo@PLT
#else
call reflect.MakeFuncStubGo
#endif
# The structure will be updated with any return values. Load
# all possible return registers before returning to the caller.
movq 0x0(%rsp), %rax
movq 0x18(%rsp), %rdx
movq 0x8(%rsp), %rdi
movq 0x10(%rsp), %rsi
movdqa 0x40(%rsp), %xmm0
movdqa 0x50(%rsp), %xmm1
# long double values are returned on the floating point stack,
# but we don't worry about that since Go doesn't have a long
# double type.
leave
.cfi_def_cfa %rsp, 8
ret
.cfi_endproc
#ifdef __ELF__
.size reflect.makeFuncStub, . - reflect.makeFuncStub
#endif
#ifdef __ELF__
.section .note.GNU-stack,"",@progbits
.section .note.GNU-split-stack,"",@progbits
.section .note.GNU-no-split-stack,"",@progbits
#endif

View file

@ -0,0 +1,12 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64
// Dummy function for processors without makefunc support.
void makeFuncStub () __asm__ ("reflect.makeFuncStub");
void makeFuncStub ()
{
}

View file

@ -0,0 +1,487 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// MakeFunc amd64 implementation.
package reflect
import "unsafe"
// The assembler stub will pass a pointer to this structure.
// This will come in holding all the registers that might hold
// function parameters. On return we will set the registers that
// might hold result values.
type amd64Regs struct {
rax uint64
rdi uint64
rsi uint64
rdx uint64
rcx uint64
r8 uint64
r9 uint64
rsp uint64
xmm0 [2]uint64
xmm1 [2]uint64
xmm2 [2]uint64
xmm3 [2]uint64
xmm4 [2]uint64
xmm5 [2]uint64
xmm6 [2]uint64
xmm7 [2]uint64
}
// Argument classifications. The amd64 ELF ABI uses several more, but
// these are the only ones that arise for Go types.
type amd64Class int
const (
amd64Integer amd64Class = iota
amd64SSE
amd64NoClass
amd64Memory
)
// amd64Classify returns the one or two register classes needed to
// pass the value of type. Go types never need more than two
// registers. amd64Memory means the value is stored in memory.
// amd64NoClass means the register is not used.
func amd64Classify(typ *rtype) (amd64Class, amd64Class) {
switch typ.Kind() {
default:
panic("internal error--unknown kind in amd64Classify")
case Bool, Int, Int8, Int16, Int32, Int64,
Uint, Uint8, Uint16, Uint32, Uint64,
Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
return amd64Integer, amd64NoClass
case Float32, Float64, Complex64:
return amd64SSE, amd64NoClass
case Complex128:
return amd64SSE, amd64SSE
case Array:
if typ.size == 0 {
return amd64NoClass, amd64NoClass
} else if typ.size > 16 {
return amd64Memory, amd64NoClass
}
atyp := (*arrayType)(unsafe.Pointer(typ))
eclass1, eclass2 := amd64Classify(atyp.elem)
if eclass1 == amd64Memory {
return amd64Memory, amd64NoClass
}
if eclass2 == amd64NoClass && typ.size > 8 {
eclass2 = eclass1
}
return eclass1, eclass2
case Interface:
return amd64Integer, amd64Integer
case Slice:
return amd64Memory, amd64NoClass
case String:
return amd64Integer, amd64Integer
case Struct:
if typ.size == 0 {
return amd64NoClass, amd64NoClass
} else if typ.size > 16 {
return amd64Memory, amd64NoClass
}
var first, second amd64Class
f := amd64NoClass
onFirst := true
styp := (*structType)(unsafe.Pointer(typ))
for _, field := range styp.fields {
if onFirst && field.offset >= 8 {
first = f
f = amd64NoClass
onFirst = false
}
fclass1, fclass2 := amd64Classify(field.typ)
f = amd64MergeClasses(f, fclass1)
if fclass2 != amd64NoClass {
if !onFirst {
panic("amd64Classify inconsistent")
}
first = f
f = fclass2
onFirst = false
}
}
if onFirst {
first = f
second = amd64NoClass
} else {
second = f
}
if first == amd64Memory || second == amd64Memory {
return amd64Memory, amd64NoClass
}
return first, second
}
}
// amd64MergeClasses merges two register classes as described in the
// amd64 ELF ABI.
func amd64MergeClasses(c1, c2 amd64Class) amd64Class {
switch {
case c1 == c2:
return c1
case c1 == amd64NoClass:
return c2
case c2 == amd64NoClass:
return c1
case c1 == amd64Memory || c2 == amd64Memory:
return amd64Memory
case c1 == amd64Integer || c2 == amd64Integer:
return amd64Integer
default:
return amd64SSE
}
}
// MakeFuncStubGo implements the amd64 calling convention for
// MakeFunc. This should not be called. It is exported so that
// assembly code can call it.
func MakeFuncStubGo(regs *amd64Regs, c *makeFuncImpl) {
ftyp := c.typ
// See if the result requires a struct. If it does, the first
// parameter is a pointer to the struct.
var ret1, ret2 amd64Class
switch len(ftyp.out) {
case 0:
ret1, ret2 = amd64NoClass, amd64NoClass
case 1:
ret1, ret2 = amd64Classify(ftyp.out[0])
default:
off := uintptr(0)
f := amd64NoClass
onFirst := true
for _, rt := range ftyp.out {
off = align(off, uintptr(rt.fieldAlign))
if onFirst && off >= 8 {
ret1 = f
f = amd64NoClass
onFirst = false
}
off += rt.size
if off > 16 {
break
}
fclass1, fclass2 := amd64Classify(rt)
f = amd64MergeClasses(f, fclass1)
if fclass2 != amd64NoClass {
if !onFirst {
panic("amd64Classify inconsistent")
}
ret1 = f
f = fclass2
onFirst = false
}
}
if off > 16 {
ret1, ret2 = amd64Memory, amd64NoClass
} else {
if onFirst {
ret1, ret2 = f, amd64NoClass
} else {
ret2 = f
}
}
if ret1 == amd64Memory || ret2 == amd64Memory {
ret1, ret2 = amd64Memory, amd64NoClass
}
}
in := make([]Value, 0, len(ftyp.in))
intreg := 0
ssereg := 0
ap := uintptr(regs.rsp)
maxIntregs := 6 // When we support Windows, this would be 4.
maxSSEregs := 8
if ret1 == amd64Memory {
// We are returning a value in memory, which means
// that the first argument is a hidden parameter
// pointing to that return area.
intreg++
}
argloop:
for _, rt := range ftyp.in {
c1, c2 := amd64Classify(rt)
fl := flag(rt.Kind()) << flagKindShift
if c2 == amd64NoClass {
// Argument is passed in a single register or
// in memory.
switch c1 {
case amd64NoClass:
v := Value{rt, nil, fl | flagIndir}
in = append(in, v)
continue argloop
case amd64Integer:
if intreg < maxIntregs {
reg := amd64IntregVal(regs, intreg)
iw := unsafe.Pointer(reg)
if k := rt.Kind(); k != Ptr && k != UnsafePointer {
iw = unsafe.Pointer(&reg)
fl |= flagIndir
}
v := Value{rt, iw, fl}
in = append(in, v)
intreg++
continue argloop
}
case amd64SSE:
if ssereg < maxSSEregs {
reg := amd64SSEregVal(regs, ssereg)
v := Value{rt, unsafe.Pointer(&reg), fl | flagIndir}
in = append(in, v)
ssereg++
continue argloop
}
}
in, ap = amd64Memarg(in, ap, rt)
continue argloop
}
// Argument is passed in two registers.
nintregs := 0
nsseregs := 0
switch c1 {
case amd64Integer:
nintregs++
case amd64SSE:
nsseregs++
default:
panic("inconsistent")
}
switch c2 {
case amd64Integer:
nintregs++
case amd64SSE:
nsseregs++
default:
panic("inconsistent")
}
// If the whole argument does not fit in registers, it
// is passed in memory.
if intreg+nintregs > maxIntregs || ssereg+nsseregs > maxSSEregs {
in, ap = amd64Memarg(in, ap, rt)
continue argloop
}
var word1, word2 uintptr
switch c1 {
case amd64Integer:
word1 = amd64IntregVal(regs, intreg)
intreg++
case amd64SSE:
word1 = amd64SSEregVal(regs, ssereg)
ssereg++
}
switch c2 {
case amd64Integer:
word2 = amd64IntregVal(regs, intreg)
intreg++
case amd64SSE:
word2 = amd64SSEregVal(regs, ssereg)
ssereg++
}
p := unsafe_New(rt)
*(*uintptr)(p) = word1
*(*uintptr)(unsafe.Pointer(uintptr(p) + ptrSize)) = word2
v := Value{rt, p, fl | flagIndir}
in = append(in, v)
}
// All the real arguments have been found and turned into
// Value's. Call the real function.
out := c.fn(in)
if len(out) != len(ftyp.out) {
panic("reflect: wrong return count from function created by MakeFunc")
}
for i, typ := range ftyp.out {
v := out[i]
if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
" returned wrong type: have " +
out[i].typ.String() + " for " + typ.String())
}
if v.flag&flagRO != 0 {
panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
" returned value obtained from unexported field")
}
}
if ret1 == amd64NoClass {
return
}
if ret1 == amd64Memory {
// The address of the memory area was passed as a
// hidden parameter in %rdi.
ptr := unsafe.Pointer(uintptr(regs.rdi))
off := uintptr(0)
for i, typ := range ftyp.out {
v := out[i]
off = align(off, uintptr(typ.fieldAlign))
addr := unsafe.Pointer(uintptr(ptr) + off)
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
storeIword(addr, iword(v.val), typ.size)
} else {
memmove(addr, v.val, typ.size)
}
off += typ.size
}
return
}
if len(out) == 1 && ret2 == amd64NoClass {
v := out[0]
w := v.iword()
if v.Kind() != Ptr && v.Kind() != UnsafePointer {
w = loadIword(unsafe.Pointer(w), v.typ.size)
}
switch ret1 {
case amd64Integer:
regs.rax = uint64(uintptr(w))
case amd64SSE:
regs.xmm0[0] = uint64(uintptr(w))
regs.xmm0[1] = 0
default:
panic("inconsistency")
}
return
}
var buf [2]unsafe.Pointer
ptr := unsafe.Pointer(&buf[0])
off := uintptr(0)
for i, typ := range ftyp.out {
v := out[i]
off = align(off, uintptr(typ.fieldAlign))
addr := unsafe.Pointer(uintptr(ptr) + off)
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
storeIword(addr, iword(v.val), typ.size)
} else {
memmove(addr, v.val, typ.size)
}
off += uintptr(typ.size)
}
switch ret1 {
case amd64Integer:
regs.rax = *(*uint64)(unsafe.Pointer(&buf[0]))
case amd64SSE:
regs.xmm0[0] = *(*uint64)(unsafe.Pointer(&buf[0]))
regs.xmm0[1] = 0
default:
panic("inconsistency")
}
switch ret2 {
case amd64Integer:
reg := *(*uint64)(unsafe.Pointer(&buf[1]))
if ret1 == amd64Integer {
regs.rdx = reg
} else {
regs.rax = reg
}
case amd64SSE:
reg := *(*uint64)(unsafe.Pointer(&buf[1]))
if ret1 == amd64Integer {
regs.xmm0[0] = reg
regs.xmm0[1] = 0
} else {
regs.xmm1[0] = reg
regs.xmm1[1] = 0
}
case amd64NoClass:
default:
panic("inconsistency")
}
}
// The amd64Memarg function adds an argument passed in memory.
func amd64Memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
ap = align(ap, ptrSize)
ap = align(ap, uintptr(rt.align))
p := Value{rt, unsafe.Pointer(ap), flag(rt.Kind()<<flagKindShift) | flagIndir}
in = append(in, p)
ap += rt.size
return in, ap
}
// The amd64IntregVal function returns the value of integer register i.
func amd64IntregVal(regs *amd64Regs, i int) uintptr {
var r uint64
switch i {
case 0:
r = regs.rdi
case 1:
r = regs.rsi
case 2:
r = regs.rdx
case 3:
r = regs.rcx
case 4:
r = regs.r8
case 5:
r = regs.r9
default:
panic("amd64IntregVal: bad index")
}
return uintptr(r)
}
// The amd64SSEregVal function returns the value of SSE register i.
// Note that although SSE registers can hold two uinptr's, for the
// types we use in Go we only ever use the least significant one. The
// most significant one would only be used for 128 bit types.
func amd64SSEregVal(regs *amd64Regs, i int) uintptr {
var r uint64
switch i {
case 0:
r = regs.xmm0[0]
case 1:
r = regs.xmm1[0]
case 2:
r = regs.xmm2[0]
case 3:
r = regs.xmm3[0]
case 4:
r = regs.xmm4[0]
case 5:
r = regs.xmm5[0]
case 6:
r = regs.xmm6[0]
case 7:
r = regs.xmm7[0]
}
return uintptr(r)
}

View file

@ -509,75 +509,6 @@ func isMethod(t *rtype) bool {
return params > 2
}
// callReflect is the call implementation used by a function
// returned by MakeFunc. In many ways it is the opposite of the
// method Value.call above. The method above converts a call using Values
// into a call of a function with a concrete argument frame, while
// callReflect converts a call of a function with a concrete argument
// frame into a call using Values.
// It is in this file so that it can be next to the call method above.
// The remainder of the MakeFunc implementation is in makefunc.go.
func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
ftyp := ctxt.typ
f := ctxt.fn
// Copy argument frame into Values.
ptr := frame
off := uintptr(0)
in := make([]Value, 0, len(ftyp.in))
for _, arg := range ftyp.in {
typ := arg
off += -off & uintptr(typ.align-1)
v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
if typ.size <= ptrSize {
// value fits in word.
v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
} else {
// value does not fit in word.
// Must make a copy, because f might keep a reference to it,
// and we cannot let f keep a reference to the stack frame
// after this function returns, not even a read-only reference.
v.val = unsafe_New(typ)
memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
v.flag |= flagIndir
}
in = append(in, v)
off += typ.size
}
// Call underlying function.
out := f(in)
if len(out) != len(ftyp.out) {
panic("reflect: wrong return count from function created by MakeFunc")
}
// Copy results back into argument frame.
if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1)
for i, arg := range ftyp.out {
typ := arg
v := out[i]
if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(f) +
" returned wrong type: have " +
out[i].typ.String() + " for " + typ.String())
}
if v.flag&flagRO != 0 {
panic("reflect: function created by MakeFunc using " + funcName(f) +
" returned value obtained from unexported field")
}
off += -off & uintptr(typ.align-1)
addr := unsafe.Pointer(uintptr(ptr) + off)
if v.flag&flagIndir == 0 {
storeIword(addr, iword(v.val), typ.size)
} else {
memmove(addr, v.val, typ.size)
}
off += typ.size
}
}
}
// methodReceiver returns information about the receiver
// described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should