diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-09-27 21:34:24 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-09-27 21:34:24 +0000 |
commit | a84dbde7fc88361e23609be162ba138f96ef18e4 (patch) | |
tree | 5739741126da531c10676b0207ba687b63462abc /libgo/go/reflect | |
parent | ea89b2482f97aa55e4d3fa4c57e0a6b2cdb69f64 (diff) | |
download | gcc-a84dbde7fc88361e23609be162ba138f96ef18e4.tar.gz |
reflect: Implement MakeFunc for 386.
From-SVN: r202993
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_386.S | 111 | ||||
-rw-r--r-- | libgo/go/reflect/makefuncgo_386.go | 135 |
4 files changed, 248 insertions, 2 deletions
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()<<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)) + } +} |