...

Source file src/reflect/makefunc.go

Documentation: reflect

		 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  	// Indirect Go func value (dummy) to obtain
		56  	// actual code address. (A Go func value is a pointer
		57  	// to a C function pointer. https://golang.org/s/go11func.)
		58  	dummy := makeFuncStub
		59  	code := **(**uintptr)(unsafe.Pointer(&dummy))
		60  
		61  	// makeFuncImpl contains a stack map for use by the runtime
		62  	_, _, abi := funcLayout(ftyp, nil)
		63  
		64  	impl := &makeFuncImpl{
		65  		makeFuncCtxt: makeFuncCtxt{
		66  			fn:			code,
		67  			stack:	 abi.stackPtrs,
		68  			argLen:	abi.stackCallArgsSize,
		69  			regPtrs: abi.inRegPtrs,
		70  		},
		71  		ftyp: ftyp,
		72  		fn:	 fn,
		73  	}
		74  
		75  	return Value{t, unsafe.Pointer(impl), flag(Func)}
		76  }
		77  
		78  // makeFuncStub is an assembly function that is the code half of
		79  // the function returned from MakeFunc. It expects a *callReflectFunc
		80  // as its context register, and its job is to invoke callReflect(ctxt, frame)
		81  // where ctxt is the context register and frame is a pointer to the first
		82  // word in the passed-in argument frame.
		83  func makeFuncStub()
		84  
		85  // The first 3 words of this type must be kept in sync with
		86  // makeFuncImpl and runtime.reflectMethodValue.
		87  // Any changes should be reflected in all three.
		88  type methodValue struct {
		89  	makeFuncCtxt
		90  	method int
		91  	rcvr	 Value
		92  }
		93  
		94  // makeMethodValue converts v from the rcvr+method index representation
		95  // of a method value to an actual method func value, which is
		96  // basically the receiver value with a special bit set, into a true
		97  // func value - a value holding an actual func. The output is
		98  // semantically equivalent to the input as far as the user of package
		99  // reflect can tell, but the true func representation can be handled
	 100  // by code like Convert and Interface and Assign.
	 101  func makeMethodValue(op string, v Value) Value {
	 102  	if v.flag&flagMethod == 0 {
	 103  		panic("reflect: internal error: invalid use of makeMethodValue")
	 104  	}
	 105  
	 106  	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
	 107  	fl := v.flag & (flagRO | flagAddr | flagIndir)
	 108  	fl |= flag(v.typ.Kind())
	 109  	rcvr := Value{v.typ, v.ptr, fl}
	 110  
	 111  	// v.Type returns the actual type of the method value.
	 112  	ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
	 113  
	 114  	// Indirect Go func value (dummy) to obtain
	 115  	// actual code address. (A Go func value is a pointer
	 116  	// to a C function pointer. https://golang.org/s/go11func.)
	 117  	dummy := methodValueCall
	 118  	code := **(**uintptr)(unsafe.Pointer(&dummy))
	 119  
	 120  	// methodValue contains a stack map for use by the runtime
	 121  	_, _, abi := funcLayout(ftyp, nil)
	 122  	fv := &methodValue{
	 123  		makeFuncCtxt: makeFuncCtxt{
	 124  			fn:			code,
	 125  			stack:	 abi.stackPtrs,
	 126  			argLen:	abi.stackCallArgsSize,
	 127  			regPtrs: abi.inRegPtrs,
	 128  		},
	 129  		method: int(v.flag) >> flagMethodShift,
	 130  		rcvr:	 rcvr,
	 131  	}
	 132  
	 133  	// Cause panic if method is not appropriate.
	 134  	// The panic would still happen during the call if we omit this,
	 135  	// but we want Interface() and other operations to fail early.
	 136  	methodReceiver(op, fv.rcvr, fv.method)
	 137  
	 138  	return Value{&ftyp.rtype, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
	 139  }
	 140  
	 141  // methodValueCall is an assembly function that is the code half of
	 142  // the function returned from makeMethodValue. It expects a *methodValue
	 143  // as its context register, and its job is to invoke callMethod(ctxt, frame)
	 144  // where ctxt is the context register and frame is a pointer to the first
	 145  // word in the passed-in argument frame.
	 146  func methodValueCall()
	 147  
	 148  // This structure must be kept in sync with runtime.reflectMethodValue.
	 149  // Any changes should be reflected in all both.
	 150  type makeFuncCtxt struct {
	 151  	fn			uintptr
	 152  	stack	 *bitVector // ptrmap for both stack args and results
	 153  	argLen	uintptr		// just args
	 154  	regPtrs abi.IntArgRegBitmap
	 155  }
	 156  
	 157  // moveMakeFuncArgPtrs uses ctxt.regPtrs to copy integer pointer arguments
	 158  // in args.Ints to args.Ptrs where the GC can see them.
	 159  //
	 160  // This is similar to what reflectcallmove does in the runtime, except
	 161  // that happens on the return path, whereas this happens on the call path.
	 162  //
	 163  // nosplit because pointers are being held in uintptr slots in args, so
	 164  // having our stack scanned now could lead to accidentally freeing
	 165  // memory.
	 166  //go:nosplit
	 167  func moveMakeFuncArgPtrs(ctxt *makeFuncCtxt, args *abi.RegArgs) {
	 168  	for i, arg := range args.Ints {
	 169  		// Avoid write barriers! Because our write barrier enqueues what
	 170  		// was there before, we might enqueue garbage.
	 171  		if ctxt.regPtrs.Get(i) {
	 172  			*(*uintptr)(unsafe.Pointer(&args.Ptrs[i])) = arg
	 173  		} else {
	 174  			// We *must* zero this space ourselves because it's defined in
	 175  			// assembly code and the GC will scan these pointers. Otherwise,
	 176  			// there will be garbage here.
	 177  			*(*uintptr)(unsafe.Pointer(&args.Ptrs[i])) = 0
	 178  		}
	 179  	}
	 180  }
	 181  

View as plain text