diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-09-27 17:53:46 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-09-27 17:53:46 +0000 |
commit | 6f65ddb59cbf7de3de9b14095f2f88f02fe2d2af (patch) | |
tree | 133857cd0c49e652d0d0f10641c67369221de3f9 /libgo | |
parent | 0b284b3e4617dd740687a8c0356522eb5db0b132 (diff) | |
download | gcc-6f65ddb59cbf7de3de9b14095f2f88f02fe2d2af.tar.gz |
reflect: Implement MakeFunc for amd64.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202982 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r-- | libgo/Makefile.am | 16 | ||||
-rw-r--r-- | libgo/Makefile.in | 37 | ||||
-rw-r--r-- | libgo/go/reflect/all_test.go | 12 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc.go | 24 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_amd64.S | 107 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_dummy.c | 12 | ||||
-rw-r--r-- | libgo/go/reflect/makefuncgo_amd64.go | 487 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 69 |
8 files changed, 676 insertions, 88 deletions
diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 6a81d336819..6d452f4f5cd 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -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 diff --git a/libgo/Makefile.in b/libgo/Makefile.in index eccc72d2e3c..b72e8aa559a 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -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 diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 6528e60459b..fb25130e835 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -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 } diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index f03beb34483..7253a6398a6 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -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 diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S new file mode 100644 index 00000000000..319aa18505c --- /dev/null +++ b/libgo/go/reflect/makefunc_amd64.S @@ -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 diff --git a/libgo/go/reflect/makefunc_dummy.c b/libgo/go/reflect/makefunc_dummy.c new file mode 100644 index 00000000000..aba48df3eb8 --- /dev/null +++ b/libgo/go/reflect/makefunc_dummy.c @@ -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 () +{ +} diff --git a/libgo/go/reflect/makefuncgo_amd64.go b/libgo/go/reflect/makefuncgo_amd64.go new file mode 100644 index 00000000000..bdc65560506 --- /dev/null +++ b/libgo/go/reflect/makefuncgo_amd64.go @@ -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(®) + 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(®), 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) +} diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 69a87031e56..9901ed6a4c6 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -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 |