reflect: Implement MakeFunc for 386.
From-SVN: r202993
This commit is contained in:
parent
ea89b2482f
commit
a84dbde7fc
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
111
libgo/go/reflect/makefunc_386.S
Normal file
111
libgo/go/reflect/makefunc_386.S
Normal 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
|
135
libgo/go/reflect/makefuncgo_386.go
Normal file
135
libgo/go/reflect/makefuncgo_386.go
Normal 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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user