summaryrefslogtreecommitdiffstats
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-18 23:49:49 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-18 23:49:49 +0000
commit8381eda7ff1e5a2874d708573654e64a4efcfb4f (patch)
tree1a7d38cd8be5484451189338ed6f4b76d8521f31 /libgo/go/reflect
parent2851d736ebf1e8cceebb9106cab69d2c3fdc7624 (diff)
downloadppe42-gcc-8381eda7ff1e5a2874d708573654e64a4efcfb4f.tar.gz
ppe42-gcc-8381eda7ff1e5a2874d708573654e64a4efcfb4f.zip
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@200181 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/all_test.go3
-rw-r--r--libgo/go/reflect/type.go6
-rw-r--r--libgo/go/reflect/value.go39
3 files changed, 37 insertions, 11 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 8a3602347fd..5a2ae2eee72 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -1891,6 +1891,7 @@ func (*inner) m() {}
func (*outer) m() {}
func TestNestedMethods(t *testing.T) {
+ t.Skip("fails on gccgo due to function wrappers")
typ := TypeOf((*outer)(nil))
if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
@@ -1915,6 +1916,7 @@ func (i *InnerInt) M() int {
}
func TestEmbeddedMethods(t *testing.T) {
+ /* This part of the test fails on gccgo due to function wrappers.
typ := TypeOf((*OuterInt)(nil))
if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() {
t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
@@ -1923,6 +1925,7 @@ func TestEmbeddedMethods(t *testing.T) {
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
}
}
+ */
i := &InnerInt{3}
if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 {
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 9e65870990f..b909177a42a 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -243,8 +243,8 @@ type rtype struct {
size uintptr // size in bytes
hash uint32 // hash of type; avoids computation in hash tables
- hashfn func(unsafe.Pointer, uintptr) // hash function
- equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) // equality function
+ hashfn uintptr // hash function code
+ equalfn uintptr // equality function code
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
@@ -485,7 +485,7 @@ func (t *uncommonType) Method(i int) (m Method) {
mt := p.typ
m.Type = toType(mt)
x := new(unsafe.Pointer)
- *x = p.tfn
+ *x = unsafe.Pointer(&p.tfn)
m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir}
m.Index = i
return
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
}
OpenPOWER on IntegriCloud