5302cd0250
As we move toward the Go 1.7 garbage collector, it's essential that all allocation of values that can contain Go pointers be done using the correct type descriptor. That is simplest if we do all such allocation in Go code. This rewrites the code that converts from a Go type to a libffi CIF into Go. Reviewed-on: https://go-review.googlesource.com/33353 From-SVN: r242578
155 lines
4.4 KiB
Go
155 lines
4.4 KiB
Go
// Copyright 2012 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.
|
|
|
|
// MakeFunc implementation.
|
|
|
|
package reflect
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// makeFuncImpl is the closure value implementing the function
|
|
// returned by MakeFunc.
|
|
type makeFuncImpl struct {
|
|
// These first three words are layed out like ffi_go_closure.
|
|
code uintptr
|
|
ffi_cif unsafe.Pointer
|
|
ffi_fun func(unsafe.Pointer, unsafe.Pointer)
|
|
|
|
typ *funcType
|
|
fn func([]Value) []Value
|
|
|
|
// For gccgo we use the same entry point for functions and for
|
|
// method values.
|
|
method int
|
|
rcvr Value
|
|
}
|
|
|
|
// MakeFunc returns a new function of the given Type
|
|
// that wraps the function fn. When called, that new function
|
|
// does the following:
|
|
//
|
|
// - converts its arguments to a slice of Values.
|
|
// - runs results := fn(args).
|
|
// - returns the results as a slice of Values, one per formal result.
|
|
//
|
|
// The implementation fn can assume that the argument Value slice
|
|
// has the number and type of arguments given by typ.
|
|
// If typ describes a variadic function, the final Value is itself
|
|
// a slice representing the variadic arguments, as in the
|
|
// body of a variadic function. The result Value slice returned by fn
|
|
// must have the number and type of results given by typ.
|
|
//
|
|
// The Value.Call method allows the caller to invoke a typed function
|
|
// in terms of Values; in contrast, MakeFunc allows the caller to implement
|
|
// a typed function in terms of Values.
|
|
//
|
|
// The Examples section of the documentation includes an illustration
|
|
// of how to use MakeFunc to build a swap function for different types.
|
|
//
|
|
func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
|
|
if typ.Kind() != Func {
|
|
panic("reflect: call of MakeFunc with non-Func type")
|
|
}
|
|
|
|
t := typ.common()
|
|
ftyp := (*funcType)(unsafe.Pointer(t))
|
|
|
|
impl := &makeFuncImpl{
|
|
typ: ftyp,
|
|
fn: fn,
|
|
method: -1,
|
|
}
|
|
|
|
makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl))
|
|
|
|
return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir}
|
|
}
|
|
|
|
// makeMethodValue converts v from the rcvr+method index representation
|
|
// of a method value to an actual method func value, which is
|
|
// basically the receiver value with a special bit set, into a true
|
|
// func value - a value holding an actual func. The output is
|
|
// semantically equivalent to the input as far as the user of package
|
|
// reflect can tell, but the true func representation can be handled
|
|
// by code like Convert and Interface and Assign.
|
|
func makeMethodValue(op string, v Value) Value {
|
|
if v.flag&flagMethod == 0 {
|
|
panic("reflect: internal error: invalid use of makeMethodValue")
|
|
}
|
|
|
|
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
|
|
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
|
fl |= flag(v.typ.Kind())
|
|
rcvr := Value{v.typ, v.ptr, fl}
|
|
|
|
// v.Type returns the actual type of the method value.
|
|
ft := v.Type().(*rtype)
|
|
|
|
// Cause panic if method is not appropriate.
|
|
// The panic would still happen during the call if we omit this,
|
|
// but we want Interface() and other operations to fail early.
|
|
_, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
|
|
|
|
ftyp := (*funcType)(unsafe.Pointer(t))
|
|
method := int(v.flag) >> flagMethodShift
|
|
|
|
fv := &makeFuncImpl{
|
|
typ: ftyp,
|
|
method: method,
|
|
rcvr: rcvr,
|
|
}
|
|
|
|
makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(fv))
|
|
|
|
return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir}
|
|
}
|
|
|
|
// makeValueMethod takes a method function and returns a function that
|
|
// takes a value receiver and calls the real method with a pointer to
|
|
// it.
|
|
func makeValueMethod(v Value) Value {
|
|
typ := v.typ
|
|
if typ.Kind() != Func {
|
|
panic("reflect: call of makeValueMethod with non-Func type")
|
|
}
|
|
if v.flag&flagMethodFn == 0 {
|
|
panic("reflect: call of makeValueMethod with non-MethodFn")
|
|
}
|
|
|
|
t := typ.common()
|
|
ftyp := (*funcType)(unsafe.Pointer(t))
|
|
|
|
impl := &makeFuncImpl{
|
|
typ: ftyp,
|
|
method: -2,
|
|
rcvr: v,
|
|
}
|
|
|
|
makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl))
|
|
|
|
return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir}
|
|
}
|
|
|
|
// Call the function represented by a makeFuncImpl.
|
|
func (c *makeFuncImpl) call(in []Value) []Value {
|
|
if c.method == -1 {
|
|
return c.fn(in)
|
|
} else if c.method == -2 {
|
|
if c.typ.IsVariadic() {
|
|
return c.rcvr.CallSlice(in)
|
|
} else {
|
|
return c.rcvr.Call(in)
|
|
}
|
|
} else {
|
|
m := c.rcvr.Method(c.method)
|
|
if c.typ.IsVariadic() {
|
|
return m.CallSlice(in)
|
|
} else {
|
|
return m.Call(in)
|
|
}
|
|
}
|
|
}
|