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