aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2013-09-27 21:34:24 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-09-27 21:34:24 +0000
commita84dbde7fc88361e23609be162ba138f96ef18e4 (patch)
tree5739741126da531c10676b0207ba687b63462abc
parentea89b2482f97aa55e4d3fa4c57e0a6b2cdb69f64 (diff)
downloadgcc-a84dbde7fc88361e23609be162ba138f96ef18e4.zip
gcc-a84dbde7fc88361e23609be162ba138f96ef18e4.tar.gz
gcc-a84dbde7fc88361e23609be162ba138f96ef18e4.tar.bz2
reflect: Implement MakeFunc for 386.
From-SVN: r202993
-rw-r--r--libgo/Makefile.am7
-rw-r--r--libgo/Makefile.in12
-rw-r--r--libgo/go/reflect/all_test.go2
-rw-r--r--libgo/go/reflect/makefunc.go2
-rw-r--r--libgo/go/reflect/makefunc_386.S111
-rw-r--r--libgo/go/reflect/makefuncgo_386.go135
6 files changed, 264 insertions, 5 deletions
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 6d452f4..c81c66cb 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -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 \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index b72e8aa..9e31e8c 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -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
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index fb25130..1fed585 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -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)
}
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 7253a63..3e0a792 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -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
index 0000000..f2f2fbe
--- /dev/null
+++ b/libgo/go/reflect/makefunc_386.S
@@ -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
index 0000000..0fac1f4
--- /dev/null
+++ b/libgo/go/reflect/makefuncgo_386.go
@@ -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))
+ }
+}