diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-18 23:49:49 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-18 23:49:49 +0000 |
commit | 8381eda7ff1e5a2874d708573654e64a4efcfb4f (patch) | |
tree | 1a7d38cd8be5484451189338ed6f4b76d8521f31 /libgo/go | |
parent | 2851d736ebf1e8cceebb9106cab69d2c3fdc7624 (diff) | |
download | gcc-8381eda7ff1e5a2874d708573654e64a4efcfb4f.tar.gz |
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')
-rw-r--r-- | libgo/go/reflect/all_test.go | 3 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 6 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 39 | ||||
-rw-r--r-- | libgo/go/runtime/extern.go | 3 | ||||
-rw-r--r-- | libgo/go/runtime/parfor_test.go | 9 |
5 files changed, 46 insertions, 14 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 } diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 2a90113a3a9..6e91ef56b70 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -59,9 +59,6 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) { // implemented in symtab.c func funcline_go(*Func, uintptr) (string, int) -// mid returns the current OS thread (m) id. -func mid() uint32 - // SetFinalizer sets the finalizer associated with x to f. // When the garbage collector finds an unreachable block // with an associated finalizer, it clears the association and runs diff --git a/libgo/go/runtime/parfor_test.go b/libgo/go/runtime/parfor_test.go index b382b76a7b2..4c69a68ceea 100644 --- a/libgo/go/runtime/parfor_test.go +++ b/libgo/go/runtime/parfor_test.go @@ -13,6 +13,8 @@ import ( "unsafe" ) +var gdata []uint64 + // Simple serial sanity test for parallelfor. func TestParFor(t *testing.T) { const P = 1 @@ -22,7 +24,12 @@ func TestParFor(t *testing.T) { data[i] = i } desc := NewParFor(P) + // Avoid making func a closure: parfor cannot invoke them. + // Since it doesn't happen in the C code, it's not worth doing + // just for the test. + gdata = data ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) { + data := gdata data[i] = data[i]*data[i] + 1 }) ParForDo(desc) @@ -111,7 +118,9 @@ func TestParForParallel(t *testing.T) { P := GOMAXPROCS(-1) c := make(chan bool, P) desc := NewParFor(uint32(P)) + gdata = data ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) { + data := gdata data[i] = data[i]*data[i] + 1 }) for p := 1; p < P; p++ { |