mirror of git://gcc.gnu.org/git/gcc.git
compiler, reflect, runtime: Implement method values in reflect.
From-SVN: r205913
This commit is contained in:
parent
24fd676aa8
commit
547a416879
|
|
@ -2261,26 +2261,9 @@ Type::method_constructor(Gogo*, Type* method_type,
|
||||||
|
|
||||||
++p;
|
++p;
|
||||||
go_assert(p->is_field_name("typ"));
|
go_assert(p->is_field_name("typ"));
|
||||||
if (!only_value_methods && m->is_value_method())
|
bool want_pointer_receiver = !only_value_methods && m->is_value_method();
|
||||||
{
|
nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver);
|
||||||
// This is a value method on a pointer type. Change the type of
|
vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc));
|
||||||
// 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));
|
|
||||||
|
|
||||||
++p;
|
++p;
|
||||||
go_assert(p->is_field_name("tfn"));
|
go_assert(p->is_field_name("tfn"));
|
||||||
|
|
@ -4008,6 +3991,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const
|
||||||
return ret;
|
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
|
// Make a copy of a function type ignoring any receiver and adding a
|
||||||
// closure parameter.
|
// closure parameter.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1797,6 +1797,12 @@ class Function_type : public Type
|
||||||
Function_type*
|
Function_type*
|
||||||
copy_with_receiver(Type*) const;
|
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
|
// Return a copy of this type ignoring any receiver and using dummy
|
||||||
// names for all parameters. This is used for thunks for method
|
// names for all parameters. This is used for thunks for method
|
||||||
// values.
|
// values.
|
||||||
|
|
|
||||||
|
|
@ -1631,9 +1631,13 @@ func TestMethod(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not yet implemented for gccgo
|
|
||||||
|
|
||||||
func TestMethodValue(t *testing.T) {
|
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}
|
p := Point{3, 4}
|
||||||
var i int64
|
var i int64
|
||||||
|
|
||||||
|
|
@ -1721,8 +1725,6 @@ func TestMethodValue(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Reflect version of $GOROOT/test/method5.go
|
// Reflect version of $GOROOT/test/method5.go
|
||||||
|
|
||||||
// Concrete types implementing M method.
|
// 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 (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
|
||||||
|
|
||||||
func TestMethod5(t *testing.T) {
|
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) {
|
CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
|
||||||
b, x := f(1000, 99)
|
b, x := f(1000, 99)
|
||||||
if b != 99 || x != 1000+inc {
|
if b != 99 || x != 1000+inc {
|
||||||
t.Errorf("%s(1000, 99) = %v, %v, want 99, %v", name, b, 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) {
|
CheckV := func(name string, i Value, inc int) {
|
||||||
bx := i.Method(0).Call([]Value{ValueOf(1000), ValueOf(byte(99))})
|
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)
|
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)
|
CheckF(name+".M", i.Method(0).Interface().(func(int, byte) (byte, int)), inc)
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var TinterType = TypeOf(new(Tinter)).Elem()
|
var TinterType = TypeOf(new(Tinter)).Elem()
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ type makeFuncImpl struct {
|
||||||
code uintptr
|
code uintptr
|
||||||
typ *funcType
|
typ *funcType
|
||||||
fn func([]Value) []Value
|
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
|
// 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
|
dummy := makeFuncStub
|
||||||
code := **(**uintptr)(unsafe.Pointer(&dummy))
|
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}
|
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")
|
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.
|
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
|
||||||
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
||||||
fl |= flag(v.typ.Kind()) << flagKindShift
|
fl |= flag(v.typ.Kind()) << flagKindShift
|
||||||
rcvr := Value{v.typ, v.val, fl}
|
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.
|
// Cause panic if method is not appropriate.
|
||||||
// The panic would still happen during the call if we omit this,
|
// The panic would still happen during the call if we omit this,
|
||||||
// but we want Interface() and other operations to fail early.
|
// 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 @@ func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
|
||||||
|
|
||||||
// Call the real function.
|
// Call the real function.
|
||||||
|
|
||||||
out := c.fn(in)
|
out := c.call(in)
|
||||||
|
|
||||||
if len(out) != len(ftyp.out) {
|
if len(out) != len(ftyp.out) {
|
||||||
panic("reflect: wrong return count from function created by MakeFunc")
|
panic("reflect: wrong return count from function created by MakeFunc")
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ argloop:
|
||||||
// All the real arguments have been found and turned into
|
// All the real arguments have been found and turned into
|
||||||
// Value's. Call the real function.
|
// Value's. Call the real function.
|
||||||
|
|
||||||
out := c.fn(in)
|
out := c.call(in)
|
||||||
|
|
||||||
if len(out) != len(ftyp.out) {
|
if len(out) != len(ftyp.out) {
|
||||||
panic("reflect: wrong return count from function created by MakeFunc")
|
panic("reflect: wrong return count from function created by MakeFunc")
|
||||||
|
|
|
||||||
|
|
@ -517,7 +517,7 @@ func (t *uncommonType) Method(i int) (m Method) {
|
||||||
m.Type = toType(mt)
|
m.Type = toType(mt)
|
||||||
x := new(unsafe.Pointer)
|
x := new(unsafe.Pointer)
|
||||||
*x = unsafe.Pointer(&p.tfn)
|
*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
|
m.Index = i
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ const (
|
||||||
flagIndir
|
flagIndir
|
||||||
flagAddr
|
flagAddr
|
||||||
flagMethod
|
flagMethod
|
||||||
|
flagMethodFn // gccgo: first fn parameter is always pointer
|
||||||
flagKindShift = iota
|
flagKindShift = iota
|
||||||
flagKindWidth = 5 // there are 27 kinds
|
flagKindWidth = 5 // there are 27 kinds
|
||||||
flagKindMask flag = 1<<flagKindWidth - 1
|
flagKindMask flag = 1<<flagKindWidth - 1
|
||||||
|
|
@ -433,7 +434,7 @@ func (v Value) call(op string, in []Value) []Value {
|
||||||
if v.flag&flagMethod != 0 {
|
if v.flag&flagMethod != 0 {
|
||||||
nin++
|
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)
|
params := make([]unsafe.Pointer, nin)
|
||||||
off := 0
|
off := 0
|
||||||
if v.flag&flagMethod != 0 {
|
if v.flag&flagMethod != 0 {
|
||||||
|
|
@ -484,33 +485,6 @@ func (v Value) call(op string, in []Value) []Value {
|
||||||
return ret
|
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
|
// methodReceiver returns information about the receiver
|
||||||
// described by v. The Value v may or may not have the
|
// described by v. The Value v may or may not have the
|
||||||
// flagMethod bit set, so the kind cached in v.flag should
|
// 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)
|
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()
|
k := v.kind()
|
||||||
if k == Interface {
|
if k == Interface {
|
||||||
// Special case: return the element inside the 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,
|
// created via reflect have the same underlying code pointer,
|
||||||
// so their Pointers are equal. The function used here must
|
// so their Pointers are equal. The function used here must
|
||||||
// match the one used in makeMethodValue.
|
// match the one used in makeMethodValue.
|
||||||
// This is not properly implemented for gccgo.
|
f := makeFuncStub
|
||||||
f := Zero
|
|
||||||
return **(**uintptr)(unsafe.Pointer(&f))
|
return **(**uintptr)(unsafe.Pointer(&f))
|
||||||
}
|
}
|
||||||
p := v.val
|
p := v.val
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,11 @@ __go_can_recover (const void *retaddr)
|
||||||
if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
|
if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue