diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 21:36:26 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 21:36:26 +0000 |
commit | dffa7328356257772dc7c00fe73aeb315229b373 (patch) | |
tree | b56b22f6c7e733e05e3f634ca63f18e10bc1b304 /libgo/go/reflect/makefunc_ffi.go | |
parent | 0c92e4881a61a2483c2878f9953ff92188e9661e (diff) | |
download | gcc-dffa7328356257772dc7c00fe73aeb315229b373.zip gcc-dffa7328356257772dc7c00fe73aeb315229b373.tar.gz gcc-dffa7328356257772dc7c00fe73aeb315229b373.tar.bz2 |
reflect, runtime: Use libffi closures to implement reflect.MakeFunc.
Keep using the existing 386 and amd64 code on those archs,
since it is more efficient.
From-SVN: r212853
Diffstat (limited to 'libgo/go/reflect/makefunc_ffi.go')
-rw-r--r-- | libgo/go/reflect/makefunc_ffi.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go new file mode 100644 index 0000000..a13ef17 --- /dev/null +++ b/libgo/go/reflect/makefunc_ffi.go @@ -0,0 +1,88 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "runtime" + "unsafe" +) + +// The ffi function, written in C, allocates an FFI closure. It +// returns the code and data pointers. When the code pointer is +// called, it will call callback. CIF is an FFI data structure +// allocated as part of the closure, and is returned to ensure that +// the GC retains it. +func ffi(ftyp *funcType, callback func(unsafe.Pointer, unsafe.Pointer)) (code uintptr, data uintptr, cif unsafe.Pointer) + +// The ffiFree function, written in C, releases the FFI closure. +func ffiFree(uintptr) + +// An ffiData holds the information needed to preserve an FFI closure +// for the garbage collector. +type ffiData struct { + code uintptr + data uintptr + cif unsafe.Pointer + callback func(unsafe.Pointer, unsafe.Pointer) +} + +// The makeFuncFFI function uses libffi closures to implement +// reflect.MakeFunc. This is used for processors for which we don't +// have more efficient support. +func makeFuncFFI(ftyp *funcType, fn func(args []Value) (results []Value)) (uintptr, *ffiData) { + callback := func(params, results unsafe.Pointer) { + ffiCall(ftyp, fn, params, results) + } + + code, data, cif := ffi(ftyp, callback) + + c := &ffiData{code: code, data: data, cif: cif, callback: callback} + + runtime.SetFinalizer(c, + func(p *ffiData) { + ffiFree(p.data) + }) + + return code, c +} + +// ffiCall takes pointers to the parameters, calls the function, and +// stores the results back into memory. +func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, results unsafe.Pointer) { + in := make([]Value, 0, len(ftyp.in)) + ap := params + for _, rt := range ftyp.in { + p := unsafe_New(rt) + memmove(p, *(*unsafe.Pointer)(ap), rt.size) + v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir} + in = append(in, v) + ap = (unsafe.Pointer)(uintptr(ap) + ptrSize) + } + + out := fn(in) + + off := uintptr(0) + for i, typ := range ftyp.out { + v := out[i] + if v.typ != typ { + panic("reflect: function created by MakeFunc using " + funcName(fn) + + " returned wrong type: have " + + out[i].typ.String() + " for " + typ.String()) + } + if v.flag&flagRO != 0 { + panic("reflect: function created by MakeFunc using " + funcName(fn) + + " returned value obtained from unexported field") + } + + off = align(off, uintptr(typ.fieldAlign)) + addr := unsafe.Pointer(uintptr(results) + off) + if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { + *(*unsafe.Pointer)(addr) = v.ptr + } else { + memmove(addr, v.ptr, typ.size) + } + off += typ.size + } +} |