Commit 8bcd5487 by Ian Lance Taylor

reflect: Implement MakeFunc for amd64.

From-SVN: r202982
parent f6113c27
...@@ -895,9 +895,21 @@ go_path_files = \ ...@@ -895,9 +895,21 @@ go_path_files = \
go/path/match.go \ go/path/match.go \
go/path/path.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_files = \
go/reflect/deepequal.go \ go/reflect/deepequal.go \
go/reflect/makefunc.go \ go/reflect/makefunc.go \
$(go_reflect_makefunc_file) \
go/reflect/type.go \ go/reflect/type.go \
go/reflect/value.go go/reflect/value.go
...@@ -1761,6 +1773,7 @@ libgo_go_objs = \ ...@@ -1761,6 +1773,7 @@ libgo_go_objs = \
os.lo \ os.lo \
path.lo \ path.lo \
reflect-go.lo \ reflect-go.lo \
reflect/makefunc.lo \
regexp.lo \ regexp.lo \
runtime-go.lo \ runtime-go.lo \
sort.lo \ sort.lo \
...@@ -2147,6 +2160,9 @@ reflect-go.lo: $(go_reflect_files) ...@@ -2147,6 +2160,9 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE) $(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS) reflect/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check .PHONY: reflect/check
@go_include@ regexp.lo.dep @go_include@ regexp.lo.dep
......
...@@ -134,17 +134,17 @@ am__DEPENDENCIES_1 = ...@@ -134,17 +134,17 @@ am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \ 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 \ 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 \ 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 \ reflect-go.lo reflect/makefunc.lo regexp.lo runtime-go.lo \
strings.lo sync.lo syscall.lo syscall/errno.lo \ sort.lo strconv.lo strings.lo sync.lo syscall.lo \
syscall/signame.lo syscall/wait.lo testing.lo time-go.lo \ syscall/errno.lo syscall/signame.lo syscall/wait.lo testing.lo \
unicode.lo archive/tar.lo archive/zip.lo compress/bzip2.lo \ time-go.lo unicode.lo archive/tar.lo archive/zip.lo \
compress/flate.lo compress/gzip.lo compress/lzw.lo \ compress/bzip2.lo compress/flate.lo compress/gzip.lo \
compress/zlib.lo container/heap.lo container/list.lo \ compress/lzw.lo compress/zlib.lo container/heap.lo \
container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \ container/list.lo container/ring.lo crypto/aes.lo \
crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \ crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \ crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \ crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
crypto/subtle.lo crypto/tls.lo crypto/x509.lo \ crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
crypto/x509/pkix.lo database/sql.lo database/sql/driver.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/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \ debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
...@@ -1087,9 +1087,20 @@ go_path_files = \ ...@@ -1087,9 +1087,20 @@ go_path_files = \
go/path/match.go \ go/path/match.go \
go/path/path.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_files = \
go/reflect/deepequal.go \ go/reflect/deepequal.go \
go/reflect/makefunc.go \ go/reflect/makefunc.go \
$(go_reflect_makefunc_file) \
go/reflect/type.go \ go/reflect/type.go \
go/reflect/value.go go/reflect/value.go
...@@ -1846,6 +1857,7 @@ libgo_go_objs = \ ...@@ -1846,6 +1857,7 @@ libgo_go_objs = \
os.lo \ os.lo \
path.lo \ path.lo \
reflect-go.lo \ reflect-go.lo \
reflect/makefunc.lo \
regexp.lo \ regexp.lo \
runtime-go.lo \ runtime-go.lo \
sort.lo \ sort.lo \
...@@ -4499,6 +4511,9 @@ reflect-go.lo: $(go_reflect_files) ...@@ -4499,6 +4511,9 @@ reflect-go.lo: $(go_reflect_files)
$(BUILDPACKAGE) $(BUILDPACKAGE)
reflect/check: $(CHECK_DEPS) reflect/check: $(CHECK_DEPS)
@$(CHECK) @$(CHECK)
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
@$(MKDIR_P) reflect
$(LTCOMPILE) -c -o $@ $<
.PHONY: reflect/check .PHONY: reflect/check
@go_include@ regexp.lo.dep @go_include@ regexp.lo.dep
......
...@@ -1430,11 +1430,13 @@ func TestFunc(t *testing.T) { ...@@ -1430,11 +1430,13 @@ func TestFunc(t *testing.T) {
} }
} }
/*
Not yet implemented for gccgo.
func TestMakeFunc(t *testing.T) { func TestMakeFunc(t *testing.T) {
switch runtime.GOARCH {
case "amd64":
default:
t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
}
f := dummy f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in }) fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
ValueOf(&f).Elem().Set(fv) ValueOf(&f).Elem().Set(fv)
...@@ -1452,8 +1454,6 @@ func TestMakeFunc(t *testing.T) { ...@@ -1452,8 +1454,6 @@ func TestMakeFunc(t *testing.T) {
} }
} }
*/
type Point struct { type Point struct {
x, y int x, y int
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package reflect package reflect
import ( import (
"runtime"
"unsafe" "unsafe"
) )
...@@ -45,14 +46,33 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { ...@@ -45,14 +46,33 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
panic("reflect: call of MakeFunc with non-Func type") 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() t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t)) 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 // makeMethodValue converts v from the rcvr+method index representation
// of a method value to an actual method func value, which is // of a method value to an actual method func value, which is
// basically the receiver value with a special bit set, into a true // basically the receiver value with a special bit set, into a true
......
# 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
// 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 ()
{
}
...@@ -509,75 +509,6 @@ func isMethod(t *rtype) bool { ...@@ -509,75 +509,6 @@ func isMethod(t *rtype) bool {
return params > 2 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 // methodReceiver returns information about the receiver
// described by v. The Value v may or may not have the // described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should // flagMethod bit set, so the kind cached in v.flag should
......
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