diff options
author | Ian Lance Taylor <iant@google.com> | 2013-06-18 23:49:49 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-06-18 23:49:49 +0000 |
commit | fdbc38a6e8d7c920eea6c6231c7fe2c987fa8aa2 (patch) | |
tree | 1a7d38cd8be5484451189338ed6f4b76d8521f31 /libgo/go/reflect/value.go | |
parent | 25e00ab67444a01dce446e95308521d1a73f8232 (diff) | |
download | gcc-fdbc38a6e8d7c920eea6c6231c7fe2c987fa8aa2.zip gcc-fdbc38a6e8d7c920eea6c6231c7fe2c987fa8aa2.tar.gz gcc-fdbc38a6e8d7c920eea6c6231c7fe2c987fa8aa2.tar.bz2 |
compiler, runtime: Use function descriptors.
This changes the representation of a Go value of function type
from being a pointer to function code (like a C function
pointer) to being a pointer to a struct. The first field of
the struct points to the function code. The remaining fields,
if any, are the addresses of variables referenced in enclosing
functions. For each call to a function, the address of the
function descriptor is passed as the last argument.
This lets us avoid generating trampolines, and removes the use
of writable/executable sections of the heap.
From-SVN: r200181
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 15f5715..f8126e6 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 } |