]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
reflect: Implement MakeFunc for amd64.
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 27 Sep 2013 17:53:46 +0000 (17:53 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 27 Sep 2013 17:53:46 +0000 (17:53 +0000)
From-SVN: r202982

libgo/Makefile.am
libgo/Makefile.in
libgo/go/reflect/all_test.go
libgo/go/reflect/makefunc.go
libgo/go/reflect/makefunc_amd64.S [new file with mode: 0644]
libgo/go/reflect/makefunc_dummy.c [new file with mode: 0644]
libgo/go/reflect/makefuncgo_amd64.go [new file with mode: 0644]
libgo/go/reflect/value.go

index 6a81d336819cdd68282253e0540fcbc35b312796..6d452f4f5cde8004596b03403f717ea251a6bbf1 100644 (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
index eccc72d2e3caa58b5ccf7e5ea7c6b4924fc960b8..b72e8aa559a2eb2305c662169d37b511824fa6c0 100644 (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
index 6528e60459bd2ca1b6a78a84dcd015056ecf6145..fb25130e835701404deeb74d725d924fc4c6f8af 100644 (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
 }
index f03beb344837925c145683028b80ea1bd44f0795..7253a6398a640492c17ef24361cce4253f3f9aca 100644 (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
diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S
new file mode 100644 (file)
index 0000000..319aa18
--- /dev/null
@@ -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 (file)
index 0000000..aba48df
--- /dev/null
@@ -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 (file)
index 0000000..bdc6556
--- /dev/null
@@ -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)
+}
index 69a87031e56683e23415c87b7398abaec6a153cb..9901ed6a4c6eb3fcb489299cbcb84528e1b9a1da 100644 (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