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