reflect: Implement MakeFunc for 386.

From-SVN: r202993
This commit is contained in:
Ian Lance Taylor 2013-09-27 21:34:24 +00:00
parent ea89b2482f
commit a84dbde7fc
6 changed files with 264 additions and 5 deletions

View 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 \

View 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

View 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)
}

View 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)
}

View File

@ -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

View File

@ -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))
}
}