]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
reflect: Implement MakeFunc for 386.
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 27 Sep 2013 21:34:24 +0000 (21:34 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 27 Sep 2013 21:34:24 +0000 (21:34 +0000)
From-SVN: r202993

libgo/Makefile.am
libgo/Makefile.in
libgo/go/reflect/all_test.go
libgo/go/reflect/makefunc.go
libgo/go/reflect/makefunc_386.S [new file with mode: 0644]
libgo/go/reflect/makefuncgo_386.go [new file with mode: 0644]

index 6d452f4f5cde8004596b03403f717ea251a6bbf1..c81c66cb07f18e9966f16898b4d764d2bc735e92 100644 (file)
@@ -901,10 +901,17 @@ go_reflect_makefunc_file = \
 go_reflect_makefunc_s_file = \
        go/reflect/makefunc_amd64.S
 else
+if LIBGO_IS_386
+go_reflect_makefunc_file = \
+       go/reflect/makefuncgo_386.go
+go_reflect_makefunc_s_file = \
+       go/reflect/makefunc_386.S
+else
 go_reflect_makefunc_file =
 go_reflect_makefunc_s_file = \
        go/reflect/makefunc_dummy.c
 endif
+endif
 
 go_reflect_files = \
        go/reflect/deepequal.go \
index b72e8aa559a2eb2305c662169d37b511824fa6c0..9e31e8ca28ec9806764905a06f0299ff59ff6ba7 100644 (file)
@@ -1087,12 +1087,18 @@ go_path_files = \
        go/path/match.go \
        go/path/path.go
 
-@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = 
+@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
+@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@     go/reflect/makefuncgo_386.go
+
 @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_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@    go/reflect/makefunc_dummy.c
+
+@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
+@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@     go/reflect/makefunc_386.S
 
 @LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_s_file = \
 @LIBGO_IS_X86_64_TRUE@ go/reflect/makefunc_amd64.S
index fb25130e835701404deeb74d725d924fc4c6f8af..1fed58570f27219466c870fb871ff1c092416263 100644 (file)
@@ -1432,7 +1432,7 @@ func TestFunc(t *testing.T) {
 
 func TestMakeFunc(t *testing.T) {
        switch runtime.GOARCH {
-       case "amd64":
+       case "amd64", "386":
        default:
                t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
        }
index 7253a6398a640492c17ef24361cce4253f3f9aca..3e0a79258e6b7698d6c741532397740127599e37 100644 (file)
@@ -47,7 +47,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
        }
 
        switch runtime.GOARCH {
-       case "amd64":
+       case "amd64", "386":
        default:
                panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
        }
diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S
new file mode 100644 (file)
index 0000000..f2f2fbe
--- /dev/null
@@ -0,0 +1,111 @@
+# 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 386 assembly code.
+
+       .global reflect.makeFuncStub
+
+#ifdef __ELF__
+       .type reflect.makeFuncStub,@function
+#endif
+
+reflect.makeFuncStub:
+       .cfi_startproc
+
+       # Go does not provide any equivalent to the regparm function
+       # attribute, so on Go we do not need to worry about passing
+       # parameters in registers.  We just pass a pointer to the
+       # arguments on the stack.
+       #
+       # We do need to pick up the return values, though, so we pass
+       # a pointer to a struct that looks like this.
+       # struct {
+       #   esp uint32          // 0x0
+       #   eax uint32          // 0x4
+       #   st0 uint64          // 0x8
+       # }
+
+       pushl   %ebp
+       .cfi_def_cfa_offset 8
+       .cfi_offset %ebp, -8
+       movl    %esp, %ebp
+       .cfi_def_cfa_register %ebp
+
+       pushl   %ebx            # In case this is PIC.
+
+       subl    $36, %esp       # Enough for args and to align stack.
+       .cfi_offset %ebx, -12
+
+#ifdef __PIC__
+       call    __x86.get_pc_thunk.bx
+       addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+#endif
+
+       leal    8(%ebp), %eax   # Set esp field in struct.
+       movl    %eax, -24(%ebp)
+
+#ifdef __PIC__
+       call    __go_get_closure@PLT
+#else
+       call    __go_get_closure
+#endif
+
+       movl    %eax, 4(%esp)
+
+       leal    -24(%ebp), %eax
+       movl    %eax, (%esp)
+
+#ifdef __PIC__
+       call    reflect.MakeFuncStubGo@PLT
+#else
+       call    reflect.MakeFuncStubGo
+#endif
+
+       # Set return registers.
+
+       movl    -20(%ebp), %eax
+       fldl    -16(%ebp)
+
+#ifdef __SSE2__
+       # In case we are compiling with -msseregparm.  This won't work
+       # correctly if only SSE1 is supported, but that seems unlikely.
+       movsd   -16(%ebp), %xmm0
+#endif
+
+       addl    $36, %esp
+       popl    %ebx
+       .cfi_restore %ebx
+       popl    %ebp
+       .cfi_restore %ebp
+       .cfi_def_cfa %esp, 4
+
+       ret
+       .cfi_endproc
+
+#ifdef __ELF__
+       .size   reflect.makeFuncStub, . - reflect.makeFuncStub
+#endif
+
+#ifdef __PIC__
+       .section        .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+       .globl  __x86.get_pc_thunk.bx
+       .hidden __x86.get_pc_thunk.bx
+#ifdef __ELF__
+       .type   __x86.get_pc_thunk.bx, @function
+#endif
+__x86.get_pc_thunk.bx:
+       .cfi_startproc
+       movl    (%esp), %ebx
+       ret
+       .cfi_endproc
+#ifdef __ELF__
+       .size   __x86.get_pc_thunk.bx, . - __x86.get_pc_thunk.bx
+#endif
+#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/makefuncgo_386.go b/libgo/go/reflect/makefuncgo_386.go
new file mode 100644 (file)
index 0000000..0fac1f4
--- /dev/null
@@ -0,0 +1,135 @@
+// 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 386 implementation.
+
+package reflect
+
+import "unsafe"
+
+// The assembler stub will pass a pointer to this structure.  We
+// assume that no parameters are passed in registers--that is, we do
+// not support the -mregparm option.  On return we will set the
+// registers that might hold result values.
+type i386Regs struct {
+       esp uint32
+       eax uint32 // Value to return in %eax.
+       st0 uint64 // Value to return in %st(0).
+}
+
+// MakeFuncStubGo implements the 386 calling convention for MakeFunc.
+// This should not be called.  It is exported so that assembly code
+// can call it.
+
+func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
+       ftyp := c.typ
+
+       // See if the result requires a struct.  If it does, the first
+       // parameter is a pointer to the struct.
+       retStruct := false
+       retEmpty := false
+       switch len(ftyp.out) {
+       case 0:
+               retEmpty = true
+       case 1:
+               if ftyp.out[0].size == 0 {
+                       retEmpty = true
+               } else {
+                       switch ftyp.out[0].Kind() {
+                       case Complex64, Complex128, Array, Interface, Slice, String, Struct:
+                               retStruct = true
+                       }
+               }
+       default:
+               size := uintptr(0)
+               for _, typ := range ftyp.out {
+                       size += typ.size
+               }
+               if size == 0 {
+                       retEmpty = true
+               } else {
+                       retStruct = true
+               }
+       }
+
+       in := make([]Value, 0, len(ftyp.in))
+       ap := uintptr(regs.esp)
+
+       var retPtr unsafe.Pointer
+       if retStruct {
+               retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap))
+               ap += ptrSize
+       }
+
+       for _, rt := range ftyp.in {
+               ap = align(ap, ptrSize)
+
+               // We have to copy the argument onto the heap in case
+               // the function hangs on the reflect.Value we pass it.
+               p := unsafe_New(rt)
+               memmove(p, unsafe.Pointer(ap), rt.size)
+
+               v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+               in = append(in, v)
+               ap += rt.size
+       }
+
+       // 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 retEmpty {
+               return
+       }
+
+       if retStruct {
+               off := uintptr(0)
+               for i, typ := range ftyp.out {
+                       v := out[i]
+                       off = align(off, uintptr(typ.fieldAlign))
+                       addr := unsafe.Pointer(uintptr(retPtr) + 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
+               }
+               regs.eax = uint32(uintptr(retPtr))
+               return
+       }
+
+       if len(ftyp.out) != 1 {
+               panic("inconsistency")
+       }
+
+       v := out[0]
+       w := v.iword()
+       if v.Kind() != Ptr && v.Kind() != UnsafePointer {
+               w = loadIword(unsafe.Pointer(w), v.typ.size)
+       }
+       switch v.Kind() {
+       case Float32, Float64:
+               regs.st0 = uint64(uintptr(w))
+       default:
+               regs.eax = uint32(uintptr(w))
+       }
+}