github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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. http://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  type methodValue struct {
    74  	fn     uintptr
    75  	stack  *bitVector // stack bitmap for args - offset known to runtime
    76  	method int
    77  	rcvr   Value
    78  }
    79  
    80  // makeMethodValue converts v from the rcvr+method index representation
    81  // of a method value to an actual method func value, which is
    82  // basically the receiver value with a special bit set, into a true
    83  // func value - a value holding an actual func. The output is
    84  // semantically equivalent to the input as far as the user of package
    85  // reflect can tell, but the true func representation can be handled
    86  // by code like Convert and Interface and Assign.
    87  func makeMethodValue(op string, v Value) Value {
    88  	if v.flag&flagMethod == 0 {
    89  		panic("reflect: internal error: invalid use of makeMethodValue")
    90  	}
    91  
    92  	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
    93  	fl := v.flag & (flagRO | flagAddr | flagIndir)
    94  	fl |= flag(v.typ.Kind())
    95  	rcvr := Value{v.typ, v.ptr, fl}
    96  
    97  	// v.Type returns the actual type of the method value.
    98  	funcType := v.Type().(*rtype)
    99  
   100  	// Indirect Go func value (dummy) to obtain
   101  	// actual code address. (A Go func value is a pointer
   102  	// to a C function pointer. http://golang.org/s/go11func.)
   103  	dummy := methodValueCall
   104  	code := **(**uintptr)(unsafe.Pointer(&dummy))
   105  
   106  	// methodValue contains a stack map for use by the runtime
   107  	_, _, _, stack := funcLayout(funcType, nil)
   108  
   109  	fv := &methodValue{
   110  		fn:     code,
   111  		stack:  stack,
   112  		method: int(v.flag) >> flagMethodShift,
   113  		rcvr:   rcvr,
   114  	}
   115  
   116  	// Cause panic if method is not appropriate.
   117  	// The panic would still happen during the call if we omit this,
   118  	// but we want Interface() and other operations to fail early.
   119  	methodReceiver(op, fv.rcvr, fv.method)
   120  
   121  	return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
   122  }
   123  
   124  // methodValueCall is an assembly function that is the code half of
   125  // the function returned from makeMethodValue. It expects a *methodValue
   126  // as its context register, and its job is to invoke callMethod(ctxt, frame)
   127  // where ctxt is the context register and frame is a pointer to the first
   128  // word in the passed-in argument frame.
   129  func methodValueCall()