Source file src/reflect/makefunc.go

     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  	"internal/abi"
    11  	"internal/goarch"
    12  	"unsafe"
    13  )
    14  
    15  // makeFuncImpl is the closure value implementing the function
    16  // returned by MakeFunc.
    17  // The first three words of this type must be kept in sync with
    18  // methodValue and runtime.reflectMethodValue.
    19  // Any changes should be reflected in all three.
    20  type makeFuncImpl struct {
    21  	makeFuncCtxt
    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  func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
    48  	t := typ.common()
    49  	typ = toType(t) // for #80332, ensure t's exported methods are not shadowed
    50  	if typ.Kind() != Func {
    51  		panic("reflect: call of MakeFunc with non-Func type")
    52  	}
    53  
    54  	ftyp := (*funcType)(unsafe.Pointer(t))
    55  
    56  	code := abi.FuncPCABI0(makeFuncStub)
    57  
    58  	// makeFuncImpl contains a stack map for use by the runtime
    59  	_, _, abid := funcLayout(ftyp, nil)
    60  
    61  	impl := &makeFuncImpl{
    62  		makeFuncCtxt: makeFuncCtxt{
    63  			fn:      code,
    64  			stack:   abid.stackPtrs,
    65  			argLen:  abid.stackCallArgsSize,
    66  			regPtrs: abid.inRegPtrs,
    67  		},
    68  		ftyp: ftyp,
    69  		fn:   fn,
    70  	}
    71  
    72  	return Value{t, unsafe.Pointer(impl), flag(Func)}
    73  }
    74  
    75  // makeFuncStub is an assembly function that is the code half of
    76  // the function returned from MakeFunc. It expects a *callReflectFunc
    77  // as its context register, and its job is to invoke callReflect(ctxt, frame)
    78  // where ctxt is the context register and frame is a pointer to the first
    79  // word in the passed-in argument frame.
    80  func makeFuncStub()
    81  
    82  // The first 3 words of this type must be kept in sync with
    83  // makeFuncImpl and runtime.reflectMethodValue.
    84  // Any changes should be reflected in all three.
    85  type methodValue struct {
    86  	makeFuncCtxt
    87  	method int
    88  	rcvr   Value
    89  }
    90  
    91  // makeMethodValue converts v from the rcvr+method index representation
    92  // of a method value to an actual method func value, which is
    93  // basically the receiver value with a special bit set, into a true
    94  // func value - a value holding an actual func. The output is
    95  // semantically equivalent to the input as far as the user of package
    96  // reflect can tell, but the true func representation can be handled
    97  // by code like Convert and Interface and Assign.
    98  func makeMethodValue(op string, v Value) Value {
    99  	if v.flag&flagMethod == 0 {
   100  		panic("reflect: internal error: invalid use of makeMethodValue")
   101  	}
   102  
   103  	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
   104  	fl := v.flag & (flagRO | flagAddr | flagIndir)
   105  	fl |= flag(v.typ().Kind())
   106  	rcvr := Value{v.typ(), v.ptr, fl}
   107  
   108  	// v.Type returns the actual type of the method value.
   109  	ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
   110  
   111  	code := methodValueCallCodePtr()
   112  
   113  	// methodValue contains a stack map for use by the runtime
   114  	_, _, abid := funcLayout(ftyp, nil)
   115  	fv := &methodValue{
   116  		makeFuncCtxt: makeFuncCtxt{
   117  			fn:      code,
   118  			stack:   abid.stackPtrs,
   119  			argLen:  abid.stackCallArgsSize,
   120  			regPtrs: abid.inRegPtrs,
   121  		},
   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.Common(), unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
   132  }
   133  
   134  func methodValueCallCodePtr() uintptr {
   135  	return abi.FuncPCABI0(methodValueCall)
   136  }
   137  
   138  // methodValueCall is an assembly function that is the code half of
   139  // the function returned from makeMethodValue. It expects a *methodValue
   140  // as its context register, and its job is to invoke callMethod(ctxt, frame)
   141  // where ctxt is the context register and frame is a pointer to the first
   142  // word in the passed-in argument frame.
   143  func methodValueCall()
   144  
   145  // This structure must be kept in sync with runtime.reflectMethodValue.
   146  // Any changes should be reflected in all both.
   147  type makeFuncCtxt struct {
   148  	fn      uintptr
   149  	stack   *bitVector // ptrmap for both stack args and results
   150  	argLen  uintptr    // just args
   151  	regPtrs abi.IntArgRegBitmap
   152  }
   153  
   154  // moveMakeFuncArgPtrs uses ctxt.regPtrs to copy integer pointer arguments
   155  // in args.Ints to args.Ptrs where the GC can see them.
   156  //
   157  // This is similar to what reflectcallmove does in the runtime, except
   158  // that happens on the return path, whereas this happens on the call path.
   159  //
   160  // nosplit because pointers are being held in uintptr slots in args, so
   161  // having our stack scanned now could lead to accidentally freeing
   162  // memory.
   163  //
   164  //go:nosplit
   165  func moveMakeFuncArgPtrs(ctxt *makeFuncCtxt, args *abi.RegArgs) {
   166  	for i, arg := range args.Ints {
   167  		// Avoid write barriers! Because our write barrier enqueues what
   168  		// was there before, we might enqueue garbage.
   169  		// Also avoid bounds checks, we don't have the stack space for it.
   170  		// (Normally the prove pass removes them, but for -N builds we
   171  		// use too much stack.)
   172  		// ptr := &args.Ptrs[i] (but cast from *unsafe.Pointer to *uintptr)
   173  		ptr := (*uintptr)(add(unsafe.Pointer(unsafe.SliceData(args.Ptrs[:])), uintptr(i)*goarch.PtrSize, "always in [0:IntArgRegs]"))
   174  		if ctxt.regPtrs.Get(i) {
   175  			*ptr = arg
   176  		} else {
   177  			// We *must* zero this space ourselves because it's defined in
   178  			// assembly code and the GC will scan these pointers. Otherwise,
   179  			// there will be garbage here.
   180  			*ptr = 0
   181  		}
   182  	}
   183  }
   184  

View as plain text