1// Copyright 2012 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// MakeFunc implementation. 6 7package reflect 8 9import ( 10 "unsafe" 11) 12 13// makeFuncImpl is the closure value implementing the function 14// returned by MakeFunc. 15// The first three words are layed out like ffi_go_closure. 16type makeFuncImpl struct { 17 code uintptr 18 ffi_cif unsafe.Pointer 19 ffi_fun func(unsafe.Pointer, unsafe.Pointer) 20 21 typ *funcType 22 fn func([]Value) []Value 23 24 // For gccgo we use the same entry point for functions and for 25 // method values. 26 method int 27 rcvr Value 28} 29 30// MakeFunc returns a new function of the given Type 31// that wraps the function fn. When called, that new function 32// does the following: 33// 34// - converts its arguments to a slice of Values. 35// - runs results := fn(args). 36// - returns the results as a slice of Values, one per formal result. 37// 38// The implementation fn can assume that the argument Value slice 39// has the number and type of arguments given by typ. 40// If typ describes a variadic function, the final Value is itself 41// a slice representing the variadic arguments, as in the 42// body of a variadic function. The result Value slice returned by fn 43// must have the number and type of results given by typ. 44// 45// The Value.Call method allows the caller to invoke a typed function 46// in terms of Values; in contrast, MakeFunc allows the caller to implement 47// a typed function in terms of Values. 48// 49// The Examples section of the documentation includes an illustration 50// of how to use MakeFunc to build a swap function for different types. 51// 52func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { 53 if typ.Kind() != Func { 54 panic("reflect: call of MakeFunc with non-Func type") 55 } 56 57 t := typ.common() 58 ftyp := (*funcType)(unsafe.Pointer(t)) 59 60 impl := &makeFuncImpl{ 61 typ: ftyp, 62 fn: fn, 63 method: -1, 64 } 65 66 makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl)) 67 68 return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir} 69} 70 71// makeMethodValue converts v from the rcvr+method index representation 72// of a method value to an actual method func value, which is 73// basically the receiver value with a special bit set, into a true 74// func value - a value holding an actual func. The output is 75// semantically equivalent to the input as far as the user of package 76// reflect can tell, but the true func representation can be handled 77// by code like Convert and Interface and Assign. 78func makeMethodValue(op string, v Value) Value { 79 if v.flag&flagMethod == 0 { 80 panic("reflect: internal error: invalid use of makeMethodValue") 81 } 82 83 // Ignoring the flagMethod bit, v describes the receiver, not the method type. 84 fl := v.flag & (flagRO | flagAddr | flagIndir) 85 fl |= flag(v.typ.Kind()) 86 rcvr := Value{v.typ, v.ptr, fl} 87 88 // v.Type returns the actual type of the method value. 89 ft := v.Type().(*rtype) 90 91 // Cause panic if method is not appropriate. 92 // The panic would still happen during the call if we omit this, 93 // but we want Interface() and other operations to fail early. 94 _, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) 95 96 ftyp := (*funcType)(unsafe.Pointer(t)) 97 method := int(v.flag) >> flagMethodShift 98 99 fv := &makeFuncImpl{ 100 typ: ftyp, 101 method: method, 102 rcvr: rcvr, 103 } 104 105 makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(fv)) 106 107 return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir} 108} 109 110// makeValueMethod takes a method function and returns a function that 111// takes a value receiver and calls the real method with a pointer to 112// it. 113func makeValueMethod(v Value) Value { 114 typ := v.typ 115 if typ.Kind() != Func { 116 panic("reflect: call of makeValueMethod with non-Func type") 117 } 118 if v.flag&flagMethodFn == 0 { 119 panic("reflect: call of makeValueMethod with non-MethodFn") 120 } 121 122 t := typ.common() 123 ftyp := (*funcType)(unsafe.Pointer(t)) 124 125 impl := &makeFuncImpl{ 126 typ: ftyp, 127 method: -2, 128 rcvr: v, 129 } 130 131 makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl)) 132 133 return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir} 134} 135 136// Call the function represented by a makeFuncImpl. 137func (c *makeFuncImpl) call(in []Value) []Value { 138 if c.method == -1 { 139 return c.fn(in) 140 } else if c.method == -2 { 141 if c.typ.IsVariadic() { 142 return c.rcvr.CallSlice(in) 143 } else { 144 return c.rcvr.Call(in) 145 } 146 } else { 147 m := c.rcvr.Method(c.method) 148 if c.typ.IsVariadic() { 149 return m.CallSlice(in) 150 } else { 151 return m.Call(in) 152 } 153 } 154} 155