Re: libgo patch committed: Implement reflect.MakeFunc for amd64
On Fri, Sep 27, 2013 at 10:54 AM, Ian Lance Taylor i...@google.com wrote: The Go standard library has an interesting function named reflect.MakeFunc. It takes a Go function F that accepts and returns a slice of reflect.Value, and a function type T, and returns a pointer to a function of type T that converts its arguments to reflect.Value, calls F, and converts the returned reflect.Value into the appropriate return types. In effect this is the reverse of libffi: instead of describing a function and calling it, we describe a function and permit it to be called. For gccgo I tried to implement this generically using the builtin varargs functions, but that failed because I had no way to handle the return type. Many Go functions return multiple values, which in gccgo is represented as returning a struct, and, of course, in some cases a struct is returned by passing a hidden pointer as the first argument, and in other cases is handled by splitting up the struct into different register classes. So handling this generically is essentially impossible, at least without adding some more builtin functions to somehow handle the return value, builtin functions that I couldn't figure out how to even represent. So I gave up and went for a processor-specific approach. The idea is that processor-specific assembly code will save all the relevant registers into a struct, and pass them to processor-specific Go code which will implement the calling convention. This has the advantage that I only need to deal with Go types, which in particular means no worries about vector types. This patch implements this approach for x86_64. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Hi Ian, TestMakeFunc failed on x32: FAIL: TestMakeFunc (0.00 seconds) all_test.go:1457: Call returned 10, 20, 30, [40 0], 60, 70, 80; want 10, 20, 30, [40, 50], 60, 70, 80 The difference in x32 is x32 puts 2 pointers (32-bit) in one 64-git register. Somehow, the second pointer in type two [2]uintptr isn't returned properly.. Do you know what I should check for x32? Thanks. -- H.J.
Re: libgo patch committed: Implement reflect.MakeFunc for amd64
On Tue, Nov 12, 2013 at 1:40 PM, H.J. Lu hjl.to...@gmail.com wrote: On Fri, Sep 27, 2013 at 10:54 AM, Ian Lance Taylor i...@google.com wrote: The Go standard library has an interesting function named reflect.MakeFunc. It takes a Go function F that accepts and returns a slice of reflect.Value, and a function type T, and returns a pointer to a function of type T that converts its arguments to reflect.Value, calls F, and converts the returned reflect.Value into the appropriate return types. In effect this is the reverse of libffi: instead of describing a function and calling it, we describe a function and permit it to be called. For gccgo I tried to implement this generically using the builtin varargs functions, but that failed because I had no way to handle the return type. Many Go functions return multiple values, which in gccgo is represented as returning a struct, and, of course, in some cases a struct is returned by passing a hidden pointer as the first argument, and in other cases is handled by splitting up the struct into different register classes. So handling this generically is essentially impossible, at least without adding some more builtin functions to somehow handle the return value, builtin functions that I couldn't figure out how to even represent. So I gave up and went for a processor-specific approach. The idea is that processor-specific assembly code will save all the relevant registers into a struct, and pass them to processor-specific Go code which will implement the calling convention. This has the advantage that I only need to deal with Go types, which in particular means no worries about vector types. This patch implements this approach for x86_64. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Hi Ian, TestMakeFunc failed on x32: FAIL: TestMakeFunc (0.00 seconds) all_test.go:1457: Call returned 10, 20, 30, [40 0], 60, 70, 80; want 10, 20, 30, [40, 50], 60, 70, 80 The difference in x32 is x32 puts 2 pointers (32-bit) in one 64-git register. Somehow, the second pointer in type two [2]uintptr isn't returned properly.. Do you know what I should check for x32? type two [2]uintptr is an array. It should pass and return in memory for x32. -- H.J.
Re: [gofrontend-dev] Re: libgo patch committed: Implement reflect.MakeFunc for amd64
On Tue, Nov 12, 2013 at 1:40 PM, H.J. Lu hjl.to...@gmail.com wrote: TestMakeFunc failed on x32: FAIL: TestMakeFunc (0.00 seconds) all_test.go:1457: Call returned 10, 20, 30, [40 0], 60, 70, 80; want 10, 20, 30, [40, 50], 60, 70, 80 The difference in x32 is x32 puts 2 pointers (32-bit) in one 64-git register. Somehow, the second pointer in type two [2]uintptr isn't returned properly.. Do you know what I should check for x32? We'll need some code for x32 support in libgo. Right now there is none. For this specific problem we'll need files makefunc_x32.S and makefuncgo_x32.go. I don't know how the x32 ABI differs from the x86_64 ABI, but those changes will need to be reflected there. Please open a entry for this in bugzilla. Ian
Re: [gofrontend-dev] Re: libgo patch committed: Implement reflect.MakeFunc for amd64
On Tue, Nov 12, 2013 at 2:23 PM, Ian Lance Taylor i...@google.com wrote: On Tue, Nov 12, 2013 at 1:40 PM, H.J. Lu hjl.to...@gmail.com wrote: TestMakeFunc failed on x32: FAIL: TestMakeFunc (0.00 seconds) all_test.go:1457: Call returned 10, 20, 30, [40 0], 60, 70, 80; want 10, 20, 30, [40, 50], 60, 70, 80 The difference in x32 is x32 puts 2 pointers (32-bit) in one 64-git register. Somehow, the second pointer in type two [2]uintptr isn't returned properly.. Do you know what I should check for x32? We'll need some code for x32 support in libgo. Right now there is none. For this specific problem we'll need files makefunc_x32.S and makefuncgo_x32.go. I don't know how the x32 ABI differs from the x86_64 ABI, but those changes will need to be reflected there. X32 info can be found at https://sites.google.com/site/x32abi/ X32 is very close to x86-64. The main difference is pointer and long are 32 bits in x32. Please open a entry for this in bugzilla. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59095 Thanks. -- H.J.
libgo patch committed: Implement reflect.MakeFunc for amd64
The Go standard library has an interesting function named reflect.MakeFunc. It takes a Go function F that accepts and returns a slice of reflect.Value, and a function type T, and returns a pointer to a function of type T that converts its arguments to reflect.Value, calls F, and converts the returned reflect.Value into the appropriate return types. In effect this is the reverse of libffi: instead of describing a function and calling it, we describe a function and permit it to be called. For gccgo I tried to implement this generically using the builtin varargs functions, but that failed because I had no way to handle the return type. Many Go functions return multiple values, which in gccgo is represented as returning a struct, and, of course, in some cases a struct is returned by passing a hidden pointer as the first argument, and in other cases is handled by splitting up the struct into different register classes. So handling this generically is essentially impossible, at least without adding some more builtin functions to somehow handle the return value, builtin functions that I couldn't figure out how to even represent. So I gave up and went for a processor-specific approach. The idea is that processor-specific assembly code will save all the relevant registers into a struct, and pass them to processor-specific Go code which will implement the calling convention. This has the advantage that I only need to deal with Go types, which in particular means no worries about vector types. This patch implements this approach for x86_64. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Ian diff -r 024105249263 libgo/Makefile.am --- a/libgo/Makefile.am Tue Sep 24 20:26:38 2013 -0700 +++ b/libgo/Makefile.am Fri Sep 27 08:06:13 2013 -0700 @@ -895,9 +895,21 @@ go/path/match.go \ go/path/path.go +if LIBGO_IS_X86_64 +go_reflect_makefunc_file = \ + go/reflect/makefuncgo_amd64.go +go_reflect_makefunc_s_file = \ + go/reflect/makefunc_amd64.S +else +go_reflect_makefunc_file = +go_reflect_makefunc_s_file = \ + go/reflect/makefunc_dummy.c +endif + go_reflect_files = \ go/reflect/deepequal.go \ go/reflect/makefunc.go \ + $(go_reflect_makefunc_file) \ go/reflect/type.go \ go/reflect/value.go @@ -1761,6 +1773,7 @@ os.lo \ path.lo \ reflect-go.lo \ + reflect/makefunc.lo \ regexp.lo \ runtime-go.lo \ sort.lo \ @@ -2147,6 +2160,9 @@ $(BUILDPACKAGE) reflect/check: $(CHECK_DEPS) @$(CHECK) +reflect/makefunc.lo: $(go_reflect_makefunc_s_file) + @$(MKDIR_P) reflect + $(LTCOMPILE) -c -o $@ $ .PHONY: reflect/check @go_include@ regexp.lo.dep diff -r 024105249263 libgo/go/reflect/all_test.go --- a/libgo/go/reflect/all_test.go Tue Sep 24 20:26:38 2013 -0700 +++ b/libgo/go/reflect/all_test.go Fri Sep 27 08:06:13 2013 -0700 @@ -1430,11 +1430,13 @@ } } -/* - -Not yet implemented for gccgo. - func TestMakeFunc(t *testing.T) { + switch runtime.GOARCH { + case amd64: + default: + t.Skip(MakeFunc not implemented for + runtime.GOARCH) + } + f := dummy fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in }) ValueOf(f).Elem().Set(fv) @@ -1452,8 +1454,6 @@ } } -*/ - type Point struct { x, y int } diff -r 024105249263 libgo/go/reflect/makefunc.go --- a/libgo/go/reflect/makefunc.go Tue Sep 24 20:26:38 2013 -0700 +++ b/libgo/go/reflect/makefunc.go Fri Sep 27 08:06:13 2013 -0700 @@ -7,6 +7,7 @@ package reflect import ( + runtime unsafe ) @@ -45,14 +46,33 @@ panic(reflect: call of MakeFunc with non-Func type) } + switch runtime.GOARCH { + case amd64: + default: + panic(reflect.MakeFunc not implemented for + runtime.GOARCH) + } + t := typ.common() ftyp := (*funcType)(unsafe.Pointer(t)) - _, _ = t, ftyp + // Indirect Go func value (dummy) to obtain + // actual code address. (A Go func value is a pointer + // to a C function pointer. http://golang.org/s/go11func.) + dummy := makeFuncStub + code := **(**uintptr)(unsafe.Pointer(dummy)) - panic(reflect MakeFunc not implemented) + impl := makeFuncImpl{code: code, typ: ftyp, fn: fn} + + return Value{t, unsafe.Pointer(impl), flag(Func) flagKindShift} } +// makeFuncStub is an assembly function that is the code half of +// the function returned from MakeFunc. It expects a *callReflectFunc +// as its context register, and its job is to invoke callReflect(ctxt, frame) +// where ctxt is the context register and frame is a pointer to the first +// word in the passed-in argument frame. +func makeFuncStub() + // makeMethodValue converts v from the rcvr+method index representation // of a method value to an actual method func value, which is // basically the receiver value with a special bit set, into a true diff -r 024105249263 libgo/go/reflect/makefunc_amd64.S --- /dev/null Thu Jan 01 00:00:00 1970 + +++ b/libgo/go/reflect/makefunc_amd64.S Fri Sep 27 08:06:13 2013 -0700 @@ -0,0 +1,107 @@ +# Copyright 2013 The Go Authors. All rights reserved. +# Use of