diff options
Diffstat (limited to 'libgo/go/reflect/value.go')
-rw-r--r-- | libgo/go/reflect/value.go | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 15f571509b9..f8126e676d8 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -377,7 +377,7 @@ func (v Value) call(method string, in []Value) []Value { if iface.itab == nil { panic(method + " of method on nil interface value") } - fn = iface.itab.fun[i] + fn = unsafe.Pointer(&iface.itab.fun[i]) rcvr = iface.word } else { ut := v.typ.uncommon() @@ -388,7 +388,7 @@ func (v Value) call(method string, in []Value) []Value { if m.pkgPath != nil { panic(method + " of unexported method") } - fn = m.tfn + fn = unsafe.Pointer(&m.tfn) t = m.mtyp rcvr = v.iword() } @@ -462,6 +462,10 @@ func (v Value) call(method string, in []Value) []Value { if v.flag&flagMethod != 0 { nin++ } + firstPointer := len(in) > 0 && Kind(t.In(0).(*rtype).kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ) + if v.flag&flagMethod == 0 && !firstPointer { + nin++ + } params := make([]unsafe.Pointer, nin) off := 0 if v.flag&flagMethod != 0 { @@ -471,7 +475,6 @@ func (v Value) call(method string, in []Value) []Value { params[0] = unsafe.Pointer(p) off = 1 } - first_pointer := false for i, pv := range in { pv.mustBeExported() targ := t.In(i).(*rtype) @@ -483,14 +486,17 @@ func (v Value) call(method string, in []Value) []Value { } else { params[off] = pv.val } - if i == 0 && Kind(targ.kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ) { + if i == 0 && firstPointer { p := new(unsafe.Pointer) *p = params[off] params[off] = unsafe.Pointer(p) - first_pointer = true } off++ } + if v.flag&flagMethod == 0 && !firstPointer { + // Closure argument. + params[off] = unsafe.Pointer(&fn) + } ret := make([]Value, nout) results := make([]unsafe.Pointer, nout) @@ -509,7 +515,7 @@ func (v Value) call(method string, in []Value) []Value { pr = &results[0] } - call(t, fn, v.flag&flagMethod != 0, first_pointer, pp, pr) + call(t, fn, v.flag&flagMethod != 0, firstPointer, pp, pr) return ret } @@ -1209,18 +1215,35 @@ func (v Value) OverflowUint(x uint64) bool { // code using reflect cannot obtain unsafe.Pointers // without importing the unsafe package explicitly. // It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer. +// +// If v's Kind is Func, the returned pointer is an underlying +// code pointer, but not necessarily enough to identify a +// single function uniquely. The only guarantee is that the +// result is zero if and only if v is a nil func Value. func (v Value) Pointer() uintptr { k := v.kind() switch k { - case Chan, Func, Map, Ptr, UnsafePointer: - if k == Func && v.flag&flagMethod != 0 { + case Chan, Map, Ptr, UnsafePointer: + p := v.val + if v.flag&flagIndir != 0 { + p = *(*unsafe.Pointer)(p) + } + return uintptr(p) + case Func: + if v.flag&flagMethod != 0 { panic("reflect.Value.Pointer of method Value") } p := v.val if v.flag&flagIndir != 0 { p = *(*unsafe.Pointer)(p) } + // Non-nil func value points at data block. + // First word of data block is actual code. + if p != nil { + p = *(*unsafe.Pointer)(p) + } return uintptr(p) + case Slice: return (*SliceHeader)(v.val).Data } |