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  	"unsafe"
    12  )
    13  
    14  // makeFuncImpl is the closure value implementing the function
    15  // returned by MakeFunc.
    16  // The first three words of this type must be kept in sync with
    17  // methodValue and runtime.reflectMethodValue.
    18  // Any changes should be reflected in all three.
    19  type makeFuncImpl struct {
    20  	makeFuncCtxt
    21  	ftyp *funcType
    22  	fn   func([]Value) []Value
    23  }
    24  
    25  // MakeFunc returns a new function of the given Type
    26  // that wraps the function fn. When called, that new function
    27  // does the following:
    28  //
    29  //	- converts its arguments to a slice of Values.
    30  //	- runs results := fn(args).
    31  //	- returns the results as a slice of Values, one per formal result.
    32  //
    33  // The implementation fn can assume that the argument Value slice
    34  // has the number and type of arguments given by typ.
    35  // If typ describes a variadic function, the final Value is itself
    36  // a slice representing the variadic arguments, as in the
    37  // body of a variadic function. The result Value slice returned by fn
    38  // must have the number and type of results given by typ.
    39  //
    40  // The Value.Call method allows the caller to invoke a typed function
    41  // in terms of Values; in contrast, MakeFunc allows the caller to implement
    42  // a typed function in terms of Values.
    43  //
    44  // The Examples section of the documentation includes an illustration
    45  // of how to use MakeFunc to build a swap function for different types.
    46  //
    47  func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
    48  	if typ.Kind() != Func {
    49  		panic("reflect: call of MakeFunc with non-Func type")
    50  	}
    51  
    52  	t := typ.common()
    53  	ftyp := (*funcType)(unsafe.Pointer(t))
    54  
    55  	code := abi.FuncPCABI0(makeFuncStub)
    56  
    57  	// makeFuncImpl contains a stack map for use by the runtime
    58  	_, _, abi := funcLayout(ftyp, nil)
    59  
    60  	impl := &makeFuncImpl{
    61  		makeFuncCtxt: makeFuncCtxt{
    62  			fn:      code,
    63  			stack:   abi.stackPtrs,
    64  			argLen:  abi.stackCallArgsSize,
    65  			regPtrs: abi.inRegPtrs,
    66  		},
    67  		ftyp: ftyp,
    68  		fn:   fn,
    69  	}
    70  
    71  	return Value{t, unsafe.Pointer(impl), flag(Func)}
    72  }
    73  
    74  // makeFuncStub is an assembly function that is the code half of
    75  // the function returned from MakeFunc. It expects a *callReflectFunc
    76  // as its context register, and its job is to invoke callReflect(ctxt, frame)
    77  // where ctxt is the context register and frame is a pointer to the first
    78  // word in the passed-in argument frame.
    79  func makeFuncStub()
    80  
    81  // The first 3 words of this type must be kept in sync with
    82  // makeFuncImpl and runtime.reflectMethodValue.
    83  // Any changes should be reflected in all three.
    84  type methodValue struct {
    85  	makeFuncCtxt
    86  	method int
    87  	rcvr   Value
    88  }
    89  
    90  // makeMethodValue converts v from the rcvr+method index representation
    91  // of a method value to an actual method func value, which is
    92  // basically the receiver value with a special bit set, into a true
    93  // func value - a value holding an actual func. The output is
    94  // semantically equivalent to the input as far as the user of package
    95  // reflect can tell, but the true func representation can be handled
    96  // by code like Convert and Interface and Assign.
    97  func makeMethodValue(op string, v Value) Value {
    98  	if v.flag&flagMethod == 0 {
    99  		panic("reflect: internal error: invalid use of makeMethodValue")
   100  	}
   101  
   102  	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
   103  	fl := v.flag & (flagRO | flagAddr | flagIndir)
   104  	fl |= flag(v.typ.Kind())
   105  	rcvr := Value{v.typ, v.ptr, fl}
   106  
   107  	// v.Type returns the actual type of the method value.
   108  	ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
   109  
   110  	code := methodValueCallCodePtr()
   111  
   112  	// methodValue contains a stack map for use by the runtime
   113  	_, _, abi := funcLayout(ftyp, nil)
   114  	fv := &methodValue{
   115  		makeFuncCtxt: makeFuncCtxt{
   116  			fn:      code,
   117  			stack:   abi.stackPtrs,
   118  			argLen:  abi.stackCallArgsSize,
   119  			regPtrs: abi.inRegPtrs,
   120  		},
   121  		method: int(v.flag) >> flagMethodShift,
   122  		rcvr:   rcvr,
   123  	}
   124  
   125  	// Cause panic if method is not appropriate.
   126  	// The panic would still happen during the call if we omit this,
   127  	// but we want Interface() and other operations to fail early.
   128  	methodReceiver(op, fv.rcvr, fv.method)
   129  
   130  	return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
   131  }
   132  
   133  func methodValueCallCodePtr() uintptr {
   134  	return abi.FuncPCABI0(methodValueCall)
   135  }
   136  
   137  // methodValueCall is an assembly function that is the code half of
   138  // the function returned from makeMethodValue. It expects a *methodValue
   139  // as its context register, and its job is to invoke callMethod(ctxt, frame)
   140  // where ctxt is the context register and frame is a pointer to the first
   141  // word in the passed-in argument frame.
   142  func methodValueCall()
   143  
   144  // This structure must be kept in sync with runtime.reflectMethodValue.
   145  // Any changes should be reflected in all both.
   146  type makeFuncCtxt struct {
   147  	fn      uintptr
   148  	stack   *bitVector // ptrmap for both stack args and results
   149  	argLen  uintptr    // just args
   150  	regPtrs abi.IntArgRegBitmap
   151  }
   152  
   153  // moveMakeFuncArgPtrs uses ctxt.regPtrs to copy integer pointer arguments
   154  // in args.Ints to args.Ptrs where the GC can see them.
   155  //
   156  // This is similar to what reflectcallmove does in the runtime, except
   157  // that happens on the return path, whereas this happens on the call path.
   158  //
   159  // nosplit because pointers are being held in uintptr slots in args, so
   160  // having our stack scanned now could lead to accidentally freeing
   161  // memory.
   162  //go:nosplit
   163  func moveMakeFuncArgPtrs(ctxt *makeFuncCtxt, args *abi.RegArgs) {
   164  	for i, arg := range args.Ints {
   165  		// Avoid write barriers! Because our write barrier enqueues what
   166  		// was there before, we might enqueue garbage.
   167  		if ctxt.regPtrs.Get(i) {
   168  			*(*uintptr)(unsafe.Pointer(&args.Ptrs[i])) = arg
   169  		} else {
   170  			// We *must* zero this space ourselves because it's defined in
   171  			// assembly code and the GC will scan these pointers. Otherwise,
   172  			// there will be garbage here.
   173  			*(*uintptr)(unsafe.Pointer(&args.Ptrs[i])) = 0
   174  		}
   175  	}
   176  }
   177  

View as plain text