From 22806403ec9dff3f819ac87298aca28a7e795cb0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 3 Oct 2014 15:51:38 +0000 Subject: [PATCH] re PR go/61877 (reflect: cannot use []string as type string in Call) PR go/61877 refect: fix direct call of variadic method value As reported in bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61877 gcc mainline has regressed in this. This CL adds the tests proposed for the main Go repository: https://codereview.appspot.com/151280043/ https://codereview.appspot.com/152060043/ restores the code from the amd64/386 path that makes this work and was lost when the Go 1.3 stdlib was merged and changes the FFI path to call into the same helper code as the amd64/386 path. I've only tested this on amd64 but I did test a version that was patched to unconditionally take the FFI path. From-SVN: r215859 --- libgo/go/reflect/all_test.go | 77 +++++++++++++++++++++++++++++++++--- libgo/go/reflect/makefunc.go | 59 ++++++++++++--------------- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index f888d648c19..3e107795bdf 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -1543,7 +1543,17 @@ func TestMakeFuncVariadic(t *testing.T) { fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] }) ValueOf(&fn).Elem().Set(fv) - r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) + r := fn(1, 2, 3) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + + r = fn(1, []int{2, 3}...) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + + r = fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) if r[0] != 2 || r[1] != 3 { t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) } @@ -1552,6 +1562,17 @@ func TestMakeFuncVariadic(t *testing.T) { if r[0] != 2 || r[1] != 3 { t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) } + + f := fv.Interface().(func(int, ...int) []int) + + r = f(1, 2, 3) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + r = f(1, []int{2, 3}...) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } } type Point struct { @@ -1569,6 +1590,24 @@ func (p Point) Dist(scale int) int { return p.x*p.x*scale + p.y*p.y*scale } +// This will be index 2. +func (p Point) GCMethod(k int) int { + runtime.GC() + return k + p.x +} + +// This will be index 3. +func (p Point) TotalDist(points ...Point) int { + tot := 0 + for _, q := range points { + dx := q.x - p.x + dy := q.y - p.y + tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test. + + } + return tot +} + func TestMethod(t *testing.T) { // Non-curried method of type. p := Point{3, 4} @@ -1751,6 +1790,37 @@ func TestMethodValue(t *testing.T) { } } +func TestVariadicMethodValue(t *testing.T) { + p := Point{3, 4} + points := []Point{{20, 21}, {22, 23}, {24, 25}} + want := int64(p.TotalDist(points[0], points[1], points[2])) + + // Curried method of value. + tfunc := TypeOf((func(...Point) int)(nil)) + v := ValueOf(p).Method(3) + if tt := v.Type(); tt != tfunc { + t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc) + } + i := ValueOf(v.Interface()).Call([]Value{ValueOf(points[0]), ValueOf(points[1]), ValueOf(points[2])})[0].Int() + if i != want { + t.Errorf("Variadic Method returned %d; want %d", i, want) + } + i = ValueOf(v.Interface()).CallSlice([]Value{ValueOf(points)})[0].Int() + if i != want { + t.Errorf("Variadic Method CallSlice returned %d; want %d", i, want) + } + + f := v.Interface().(func(...Point) int) + i = int64(f(points[0], points[1], points[2])) + if i != want { + t.Errorf("Variadic Method Interface returned %d; want %d", i, want) + } + i = int64(f(points...)) + if i != want { + t.Errorf("Variadic Method Interface Slice returned %d; want %d", i, want) + } +} + // Reflect version of $GOROOT/test/method5.go // Concrete types implementing M method. @@ -3718,11 +3788,6 @@ func TestReflectFuncTraceback(t *testing.T) { f.Call([]Value{}) } -func (p Point) GCMethod(k int) int { - runtime.GC() - return k + p.x -} - func TestReflectMethodTraceback(t *testing.T) { p := Point{3, 4} m := ValueOf(p).MethodByName("GCMethod") diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index 736ac36ade7..977aacfd438 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -117,29 +117,21 @@ func makeMethodValue(op string, v Value) Value { ftyp := (*funcType)(unsafe.Pointer(t)) method := int(v.flag) >> flagMethodShift - var code uintptr - var ffi *ffiData + fv := &makeFuncImpl{ + typ: ftyp, + method: method, + rcvr: rcvr, + } + switch runtime.GOARCH { case "amd64", "386": // 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)) + fv.code = **(**uintptr)(unsafe.Pointer(&dummy)) default: - code, ffi = makeFuncFFI(ftyp, - func(in []Value) []Value { - m := rcvr.Method(method) - return m.Call(in) - }) - } - - fv := &makeFuncImpl{ - code: code, - typ: ftyp, - method: method, - rcvr: rcvr, - ffi: ffi, + fv.code, fv.ffi = makeFuncFFI(ftyp, fv.call) } return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<