summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-12 01:08:52 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-12 01:08:52 +0000
commita4a14eb29309a20c3b21ed4fc79d9f29abf162bc (patch)
tree6d22f3392a75c3aaa5aa1da655668fca943b1d10 /libgo
parentdc2977939ca7d738e1330c11deae1c97602a36ae (diff)
downloadgcc-a4a14eb29309a20c3b21ed4fc79d9f29abf162bc.tar.gz
compiler, reflect, runtime: Implement method values in reflect.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205913 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/reflect/all_test.go20
-rw-r--r--libgo/go/reflect/makefunc.go90
-rw-r--r--libgo/go/reflect/makefuncgo_386.go2
-rw-r--r--libgo/go/reflect/makefuncgo_amd64.go2
-rw-r--r--libgo/go/reflect/type.go2
-rw-r--r--libgo/go/reflect/value.go43
-rw-r--r--libgo/runtime/go-recover.c5
7 files changed, 120 insertions, 44 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 918adce887f..f9700ce2fb5 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -1631,9 +1631,13 @@ func TestMethod(t *testing.T) {
}
}
-/* Not yet implemented for gccgo
-
func TestMethodValue(t *testing.T) {
+ switch runtime.GOARCH {
+ case "amd64", "386":
+ default:
+ t.Skip("reflect method values not implemented for " + runtime.GOARCH)
+ }
+
p := Point{3, 4}
var i int64
@@ -1721,8 +1725,6 @@ func TestMethodValue(t *testing.T) {
}
}
-*/
-
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
@@ -1807,14 +1809,18 @@ type Tm4 struct {
func (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
func TestMethod5(t *testing.T) {
- /* Not yet used for gccgo
+ switch runtime.GOARCH {
+ case "amd64", "386":
+ default:
+ t.Skip("reflect method values not implemented for " + runtime.GOARCH)
+ }
+
CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
b, x := f(1000, 99)
if b != 99 || x != 1000+inc {
t.Errorf("%s(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc)
}
}
- */
CheckV := func(name string, i Value, inc int) {
bx := i.Method(0).Call([]Value{ValueOf(1000), ValueOf(byte(99))})
@@ -1824,9 +1830,7 @@ func TestMethod5(t *testing.T) {
t.Errorf("direct %s.M(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc)
}
- /* Not yet implemented for gccgo
CheckF(name+".M", i.Method(0).Interface().(func(int, byte) (byte, int)), inc)
- */
}
var TinterType = TypeOf(new(Tinter)).Elem()
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 505c543a082..935a3d3be02 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -17,6 +17,11 @@ type makeFuncImpl struct {
code uintptr
typ *funcType
fn func([]Value) []Value
+
+ // For gccgo we use the same entry point for functions and for
+ // method values.
+ method int
+ rcvr Value
}
// MakeFunc returns a new function of the given Type
@@ -61,7 +66,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
dummy := makeFuncStub
code := **(**uintptr)(unsafe.Pointer(&dummy))
- impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
+ impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn, method: -1}
return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
}
@@ -85,15 +90,94 @@ func makeMethodValue(op string, v Value) Value {
panic("reflect: internal error: invalid use of makePartialFunc")
}
+ switch runtime.GOARCH {
+ case "amd64", "386":
+ default:
+ panic("reflect.makeMethodValue not implemented for " + runtime.GOARCH)
+ }
+
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
fl := v.flag & (flagRO | flagAddr | flagIndir)
fl |= flag(v.typ.Kind()) << flagKindShift
rcvr := Value{v.typ, v.val, fl}
+ // v.Type returns the actual type of the method value.
+ ft := v.Type().(*rtype)
+
+ // 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))
+
// Cause panic if method is not appropriate.
// The panic would still happen during the call if we omit this,
// but we want Interface() and other operations to fail early.
- methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
+ t, _, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
+
+ fv := &makeFuncImpl{
+ code: code,
+ typ: (*funcType)(unsafe.Pointer(t)),
+ method: int(v.flag) >> flagMethodShift,
+ rcvr: rcvr,
+ }
+
+ return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
+}
+
+// makeValueMethod takes a method function and returns a function that
+// takes a value receiver and calls the real method with a pointer to
+// it.
+func makeValueMethod(v Value) Value {
+ typ := v.typ
+ if typ.Kind() != Func {
+ panic("reflect: call of makeValueMethod with non-Func type")
+ }
+ if v.flag&flagMethodFn == 0 {
+ panic("reflect: call of makeValueMethod with non-MethodFn")
+ }
- panic("reflect makeMethodValue not implemented")
+ switch runtime.GOARCH {
+ case "amd64", "386":
+ default:
+ panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
+ }
+
+ t := typ.common()
+ ftyp := (*funcType)(unsafe.Pointer(t))
+
+ // 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))
+
+ impl := &makeFuncImpl{
+ code: code,
+ typ: ftyp,
+ method: -2,
+ rcvr: v,
+ }
+
+ return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
+}
+
+// Call the function represented by a makeFuncImpl.
+func (c *makeFuncImpl) call(in []Value) []Value {
+ if c.method == -1 {
+ return c.fn(in)
+ } else if c.method == -2 {
+ if c.typ.IsVariadic() {
+ return c.rcvr.CallSlice(in)
+ } else {
+ return c.rcvr.Call(in)
+ }
+ } else {
+ m := c.rcvr.Method(c.method)
+ if c.typ.IsVariadic() {
+ return m.CallSlice(in)
+ } else {
+ return m.Call(in)
+ }
+ }
}
diff --git a/libgo/go/reflect/makefuncgo_386.go b/libgo/go/reflect/makefuncgo_386.go
index 7559af6f6ac..71957b61b3d 100644
--- a/libgo/go/reflect/makefuncgo_386.go
+++ b/libgo/go/reflect/makefuncgo_386.go
@@ -80,7 +80,7 @@ func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
// Call the real function.
- out := c.fn(in)
+ out := c.call(in)
if len(out) != len(ftyp.out) {
panic("reflect: wrong return count from function created by MakeFunc")
diff --git a/libgo/go/reflect/makefuncgo_amd64.go b/libgo/go/reflect/makefuncgo_amd64.go
index ecc50a42520..42fe03a9310 100644
--- a/libgo/go/reflect/makefuncgo_amd64.go
+++ b/libgo/go/reflect/makefuncgo_amd64.go
@@ -319,7 +319,7 @@ argloop:
// All the real arguments have been found and turned into
// Value's. Call the real function.
- out := c.fn(in)
+ out := c.call(in)
if len(out) != len(ftyp.out) {
panic("reflect: wrong return count from function created by MakeFunc")
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index aaac2c3487f..a930d64607a 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -517,7 +517,7 @@ func (t *uncommonType) Method(i int) (m Method) {
m.Type = toType(mt)
x := new(unsafe.Pointer)
*x = unsafe.Pointer(&p.tfn)
- m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir}
+ m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir | flagMethodFn}
m.Index = i
return
}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 216ee3f1ca2..fc7dfae23d2 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -98,6 +98,7 @@ const (
flagIndir
flagAddr
flagMethod
+ flagMethodFn // gccgo: first fn parameter is always pointer
flagKindShift = iota
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
@@ -433,7 +434,7 @@ func (v Value) call(op string, in []Value) []Value {
if v.flag&flagMethod != 0 {
nin++
}
- firstPointer := len(in) > 0 && t.In(0).Kind() != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ)
+ firstPointer := len(in) > 0 && t.In(0).Kind() != Ptr && v.flag&flagMethodFn != 0
params := make([]unsafe.Pointer, nin)
off := 0
if v.flag&flagMethod != 0 {
@@ -484,33 +485,6 @@ func (v Value) call(op string, in []Value) []Value {
return ret
}
-// gccgo specific test to see if typ is a method. We can tell by
-// looking at the string to see if there is a receiver. We need this
-// because for gccgo all methods take pointer receivers.
-func isMethod(t *rtype) bool {
- if Kind(t.kind) != Func {
- return false
- }
- s := *t.string
- parens := 0
- params := 0
- sawRet := false
- for i, c := range s {
- if c == '(' {
- if parens == 0 {
- params++
- }
- parens++
- } else if c == ')' {
- parens--
- } else if parens == 0 && c == ' ' && s[i+1] != '(' && !sawRet {
- params++
- sawRet = true
- }
- }
- return params > 2
-}
-
// methodReceiver returns information about the receiver
// described by v. The Value v may or may not have the
// flagMethod bit set, so the kind cached in v.flag should
@@ -873,6 +847,16 @@ func valueInterface(v Value, safe bool) interface{} {
v = makeMethodValue("Interface", v)
}
+ if v.flag&flagMethodFn != 0 {
+ if v.typ.Kind() != Func {
+ panic("reflect: MethodFn of non-Func")
+ }
+ ft := (*funcType)(unsafe.Pointer(v.typ))
+ if ft.in[0].Kind() != Ptr {
+ v = makeValueMethod(v)
+ }
+ }
+
k := v.kind()
if k == Interface {
// Special case: return the element inside the interface.
@@ -1187,8 +1171,7 @@ func (v Value) Pointer() uintptr {
// created via reflect have the same underlying code pointer,
// so their Pointers are equal. The function used here must
// match the one used in makeMethodValue.
- // This is not properly implemented for gccgo.
- f := Zero
+ f := makeFuncStub
return **(**uintptr)(unsafe.Pointer(&f))
}
p := v.val
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
index 6cef2660ea4..ceb9b572582 100644
--- a/libgo/runtime/go-recover.c
+++ b/libgo/runtime/go-recover.c
@@ -84,6 +84,11 @@ __go_can_recover (const void *retaddr)
if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
return 1;
+ /* We may also be called by reflect.makeFuncImpl.call, for a
+ function created by reflect.MakeFunc. */
+ if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL)
+ return 1;
+
return 0;
}