@@ -2261,26 +2261,9 @@
++p;
go_assert(p->is_field_name("typ"));
- if (!only_value_methods && m->is_value_method())
- {
- // This is a value method on a pointer type. Change the type of
- // the method to use a pointer receiver. The implementation
- // always uses a pointer receiver anyhow.
- Type* rtype = mtype->receiver()->type();
- Type* prtype = Type::make_pointer_type(rtype);
- Typed_identifier* receiver =
- new Typed_identifier(mtype->receiver()->name(), prtype,
- mtype->receiver()->location());
- mtype = Type::make_function_type(receiver,
- (mtype->parameters() == NULL
- ? NULL
- : mtype->parameters()->copy()),
- (mtype->results() == NULL
- ? NULL
- : mtype->results()->copy()),
- mtype->location());
- }
- vals->push_back(Expression::make_type_descriptor(mtype, bloc));
+ bool want_pointer_receiver = !only_value_methods && m->is_value_method();
+ nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver);
+ vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc));
++p;
go_assert(p->is_field_name("tfn"));
@@ -4008,6 +3991,32 @@
return ret;
}
+// Make a copy of a function type with the receiver as the first
+// parameter.
+
+Function_type*
+Function_type::copy_with_receiver_as_param(bool want_pointer_receiver) const
+{
+ go_assert(this->is_method());
+ Typed_identifier_list* new_params = new Typed_identifier_list();
+ Type* rtype = this->receiver_->type();
+ if (want_pointer_receiver)
+ rtype = Type::make_pointer_type(rtype);
+ Typed_identifier receiver(this->receiver_->name(), rtype,
+ this->receiver_->location());
+ new_params->push_back(receiver);
+ const Typed_identifier_list* orig_params = this->parameters_;
+ if (orig_params != NULL && !orig_params->empty())
+ {
+ for (Typed_identifier_list::const_iterator p = orig_params->begin();
+ p != orig_params->end();
+ ++p)
+ new_params->push_back(*p);
+ }
+ return Type::make_function_type(NULL, new_params, this->results_,
+ this->location_);
+}
+
// Make a copy of a function type ignoring any receiver and adding a
// closure parameter.
@@ -1797,6 +1797,12 @@
Function_type*
copy_with_receiver(Type*) const;
+ // Return a copy of this type with the receiver treated as the first
+ // parameter. If WANT_POINTER_RECEIVER is true, the receiver is
+ // forced to be a pointer.
+ Function_type*
+ copy_with_receiver_as_param(bool want_pointer_receiver) const;
+
// Return a copy of this type ignoring any receiver and using dummy
// names for all parameters. This is used for thunks for method
// values.
@@ -1631,9 +1631,13 @@
}
}
-/* 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 @@
}
}
-*/
-
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
@@ -1807,14 +1809,18 @@
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 @@
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()
@@ -17,6 +17,11 @@
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 @@
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 @@
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)
- panic("reflect makeMethodValue not implemented")
+ 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")
+ }
+
+ 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)
+ }
+ }
+}
@@ -80,7 +80,7 @@
// 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")
@@ -319,7 +319,7 @@
// 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")
@@ -517,7 +517,7 @@
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
}
@@ -98,6 +98,7 @@
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 @@
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 @@
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 @@
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 @@
// 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
@@ -84,6 +84,11 @@
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;
}