github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/reflect/makefunc.go (about)

     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  
     7  package reflect
     8  
     9  import (
    10  	"unsafe"
    11  )
    12  
    13  // makeFuncImpl is the closure value implementing the function
    14  // returned by MakeFunc.
    15  type makeFuncImpl struct {
    16  	code  uintptr
    17  	stack *bitVector // stack bitmap for args - offset known to runtime
    18  	typ   *funcType
    19  	fn    func([]Value) []Value
    20  }
    21  
    22  // MakeFunc returns a new function of the given Type
    23  // that wraps the function fn. When called, that new function
    24  // does the following:
    25  //
    26  //	- converts its arguments to a slice of Values.
    27  //	- runs results := fn(args).
    28  //	- returns the results as a slice of Values, one per formal result.
    29  //
    30  // The implementation fn can assume that the argument Value slice
    31  // has the number and type of arguments given by typ.
    32  // If typ describes a variadic function, the final Value is itself
    33  // a slice representing the variadic arguments, as in the
    34  // body of a variadic function. The result Value slice returned by fn
    35  // must have the number and type of results given by typ.
    36  //
    37  // The Value.Call method allows the caller to invoke a typed function
    38  // in terms of Values; in contrast, MakeFunc allows the caller to implement
    39  // a typed function in terms of Values.
    40  //
    41  // The Examples section of the documentation includes an illustration
    42  // of how to use MakeFunc to build a swap function for different types.
    43  //
    44  func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
    45  	if typ.Kind() != Func {
    46  		panic("reflect: call of MakeFunc with non-Func type")
    47  	}
    48  
    49  	t := typ.common()
    50  	ftyp := (*funcType)(unsafe.Pointer(t))
    51  
    52  	// Indirect Go func value (dummy) to obtain
    53  	// actual code address. (A Go func value is a pointer
    54  	// to a C function pointer. https://golang.org/s/go11func.)
    55  	dummy := makeFuncStub
    56  	code := **(**uintptr)(unsafe.Pointer(&dummy))
    57  
    58  	// makeFuncImpl contains a stack map for use by the runtime
    59  	_, _, _, stack, _ := funcLayout(t, nil)
    60  
    61  	impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
    62  
    63  	return Value{t, unsafe.Pointer(impl), flag(Func)}
    64  }
    65  
    66  // makeFuncStub is an assembly function that is the code half of
    67  // the function returned from MakeFunc. It expects a *callReflectFunc
    68  // as its context register, and its job is to invoke callReflect(ctxt, frame)
    69  // where ctxt is the context register and frame is a pointer to the first
    70  // word in the passed-in argument frame.
    71  func makeFuncStub()
    72  
    73  // This type is partially duplicated as runtime.reflectMethodValue.
    74  // Any changes should be reflected in both.
    75  type methodValue struct {
    76  	fn     uintptr
    77  	stack  *bitVector // stack bitmap for args - offset known to runtime
    78  	method int
    79  	rcvr   Value
    80  }
    81  
    82  // makeMethodValue converts v from the rcvr+method index representation
    83  // of a method value to an actual method func value, which is
    84  // basically the receiver value with a special bit set, into a true
    85  // func value - a value holding an actual func. The output is
    86  // semantically equivalent to the input as far as the user of package
    87  // reflect can tell, but the true func representation can be handled
    88  // by code like Convert and Interface and Assign.
    89  func makeMethodValue(op string, v Value) Value {
    90  	if v.flag&flagMethod == 0 {
    91  		panic("reflect: internal error: invalid use of makeMethodValue")
    92  	}
    93  
    94  	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
    95  	fl := v.flag & (flagRO | flagAddr | flagIndir)
    96  	fl |= flag(v.typ.Kind())
    97  	rcvr := Value{v.typ, v.ptr, fl}
    98  
    99  	// v.Type returns the actual type of the method value.
   100  	funcType := v.Type().(*rtype)
   101  
   102  	// Indirect Go func value (dummy) to obtain
   103  	// actual code address. (A Go func value is a pointer
   104  	// to a C function pointer. https://golang.org/s/go11func.)
   105  	dummy := methodValueCall
   106  	code := **(**uintptr)(unsafe.Pointer(&dummy))
   107  
   108  	// methodValue contains a stack map for use by the runtime
   109  	_, _, _, stack, _ := funcLayout(funcType, nil)
   110  
   111  	fv := &methodValue{
   112  		fn:     code,
   113  		stack:  stack,
   114  		method: int(v.flag) >> flagMethodShift,
   115  		rcvr:   rcvr,
   116  	}
   117  
   118  	// Cause panic if method is not appropriate.
   119  	// The panic would still happen during the call if we omit this,
   120  	// but we want Interface() and other operations to fail early.
   121  	methodReceiver(op, fv.rcvr, fv.method)
   122  
   123  	return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
   124  }
   125  
   126  // methodValueCall is an assembly function that is the code half of
   127  // the function returned from makeMethodValue. It expects a *methodValue
   128  // as its context register, and its job is to invoke callMethod(ctxt, frame)
   129  // where ctxt is the context register and frame is a pointer to the first
   130  // word in the passed-in argument frame.
   131  func methodValueCall()