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
7package reflect
8
9import (
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.
19type 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.
46func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
47	if typ.Kind() != Func {
48		panic("reflect: call of MakeFunc with non-Func type")
49	}
50
51	t := typ.common()
52	ftyp := (*funcType)(unsafe.Pointer(t))
53
54	code := abi.FuncPCABI0(makeFuncStub)
55
56	// makeFuncImpl contains a stack map for use by the runtime
57	_, _, abid := funcLayout(ftyp, nil)
58
59	impl := &makeFuncImpl{
60		makeFuncCtxt: makeFuncCtxt{
61			fn:      code,
62			stack:   abid.stackPtrs,
63			argLen:  abid.stackCallArgsSize,
64			regPtrs: abid.inRegPtrs,
65		},
66		ftyp: ftyp,
67		fn:   fn,
68	}
69
70	return Value{t, unsafe.Pointer(impl), flag(Func)}
71}
72
73// makeFuncStub is an assembly function that is the code half of
74// the function returned from MakeFunc. It expects a *callReflectFunc
75// as its context register, and its job is to invoke callReflect(ctxt, frame)
76// where ctxt is the context register and frame is a pointer to the first
77// word in the passed-in argument frame.
78func makeFuncStub()
79
80// The first 3 words of this type must be kept in sync with
81// makeFuncImpl and runtime.reflectMethodValue.
82// Any changes should be reflected in all three.
83type methodValue struct {
84	makeFuncCtxt
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.
96func 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	code := methodValueCallCodePtr()
110
111	// methodValue contains a stack map for use by the runtime
112	_, _, abid := funcLayout(ftyp, nil)
113	fv := &methodValue{
114		makeFuncCtxt: makeFuncCtxt{
115			fn:      code,
116			stack:   abid.stackPtrs,
117			argLen:  abid.stackCallArgsSize,
118			regPtrs: abid.inRegPtrs,
119		},
120		method: int(v.flag) >> flagMethodShift,
121		rcvr:   rcvr,
122	}
123
124	// Cause panic if method is not appropriate.
125	// The panic would still happen during the call if we omit this,
126	// but we want Interface() and other operations to fail early.
127	methodReceiver(op, fv.rcvr, fv.method)
128
129	return Value{ftyp.Common(), unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
130}
131
132func methodValueCallCodePtr() uintptr {
133	return abi.FuncPCABI0(methodValueCall)
134}
135
136// methodValueCall is an assembly function that is the code half of
137// the function returned from makeMethodValue. It expects a *methodValue
138// as its context register, and its job is to invoke callMethod(ctxt, frame)
139// where ctxt is the context register and frame is a pointer to the first
140// word in the passed-in argument frame.
141func methodValueCall()
142
143// This structure must be kept in sync with runtime.reflectMethodValue.
144// Any changes should be reflected in all both.
145type makeFuncCtxt struct {
146	fn      uintptr
147	stack   *bitVector // ptrmap for both stack args and results
148	argLen  uintptr    // just args
149	regPtrs abi.IntArgRegBitmap
150}
151
152// moveMakeFuncArgPtrs uses ctxt.regPtrs to copy integer pointer arguments
153// in args.Ints to args.Ptrs where the GC can see them.
154//
155// This is similar to what reflectcallmove does in the runtime, except
156// that happens on the return path, whereas this happens on the call path.
157//
158// nosplit because pointers are being held in uintptr slots in args, so
159// having our stack scanned now could lead to accidentally freeing
160// memory.
161//
162//go:nosplit
163func 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