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