From a84dbde7fc88361e23609be162ba138f96ef18e4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 27 Sep 2013 21:34:24 +0000 Subject: [PATCH] reflect: Implement MakeFunc for 386. From-SVN: r202993 --- libgo/Makefile.am | 7 ++ libgo/Makefile.in | 12 ++- libgo/go/reflect/all_test.go | 2 +- libgo/go/reflect/makefunc.go | 2 +- libgo/go/reflect/makefunc_386.S | 111 ++++++++++++++++++++++++ libgo/go/reflect/makefuncgo_386.go | 135 +++++++++++++++++++++++++++++ 6 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 libgo/go/reflect/makefunc_386.S create mode 100644 libgo/go/reflect/makefuncgo_386.go diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 6d452f4f5cd..c81c66cb07f 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 b72e8aa559a..9e31e8ca28e 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 fb25130e835..1fed58570f2 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 7253a6398a6..3e0a79258e6 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 00000000000..f2f2fbe1a95 --- /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 00000000000..0fac1f488a4 --- /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()<