Home | History | Annotate | Download | only in 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 	"unsafe"
     11 )
     12 
     13 // makeFuncImpl is the closure value implementing the function
     14 // returned by MakeFunc.
     15 // The first two words of this type must be kept in sync with
     16 // methodValue and runtime.reflectMethodValue.
     17 // Any changes should be reflected in all three.
     18 type makeFuncImpl struct {
     19 	code  uintptr
     20 	stack *bitVector
     21 	typ   *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 	_, _, _, stack, _ := funcLayout(t, nil)
     63 
     64 	impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
     65 
     66 	return Value{t, unsafe.Pointer(impl), flag(Func)}
     67 }
     68 
     69 // makeFuncStub is an assembly function that is the code half of
     70 // the function returned from MakeFunc. It expects a *callReflectFunc
     71 // as its context register, and its job is to invoke callReflect(ctxt, frame)
     72 // where ctxt is the context register and frame is a pointer to the first
     73 // word in the passed-in argument frame.
     74 func makeFuncStub()
     75 
     76 // The first two words of this type must be kept in sync with
     77 // makeFuncImpl and runtime.reflectMethodValue.
     78 // Any changes should be reflected in all three.
     79 type methodValue struct {
     80 	fn     uintptr
     81 	stack  *bitVector
     82 	method int
     83 	rcvr   Value
     84 }
     85 
     86 // makeMethodValue converts v from the rcvr+method index representation
     87 // of a method value to an actual method func value, which is
     88 // basically the receiver value with a special bit set, into a true
     89 // func value - a value holding an actual func. The output is
     90 // semantically equivalent to the input as far as the user of package
     91 // reflect can tell, but the true func representation can be handled
     92 // by code like Convert and Interface and Assign.
     93 func makeMethodValue(op string, v Value) Value {
     94 	if v.flag&flagMethod == 0 {
     95 		panic("reflect: internal error: invalid use of makeMethodValue")
     96 	}
     97 
     98 	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
     99 	fl := v.flag & (flagRO | flagAddr | flagIndir)
    100 	fl |= flag(v.typ.Kind())
    101 	rcvr := Value{v.typ, v.ptr, fl}
    102 
    103 	// v.Type returns the actual type of the method value.
    104 	funcType := v.Type().(*rtype)
    105 
    106 	// Indirect Go func value (dummy) to obtain
    107 	// actual code address. (A Go func value is a pointer
    108 	// to a C function pointer. https://golang.org/s/go11func.)
    109 	dummy := methodValueCall
    110 	code := **(**uintptr)(unsafe.Pointer(&dummy))
    111 
    112 	// methodValue contains a stack map for use by the runtime
    113 	_, _, _, stack, _ := funcLayout(funcType, nil)
    114 
    115 	fv := &methodValue{
    116 		fn:     code,
    117 		stack:  stack,
    118 		method: int(v.flag) >> flagMethodShift,
    119 		rcvr:   rcvr,
    120 	}
    121 
    122 	// Cause panic if method is not appropriate.
    123 	// The panic would still happen during the call if we omit this,
    124 	// but we want Interface() and other operations to fail early.
    125 	methodReceiver(op, fv.rcvr, fv.method)
    126 
    127 	return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
    128 }
    129 
    130 // methodValueCall is an assembly function that is the code half of
    131 // the function returned from makeMethodValue. It expects a *methodValue
    132 // as its context register, and its job is to invoke callMethod(ctxt, frame)
    133 // where ctxt is the context register and frame is a pointer to the first
    134 // word in the passed-in argument frame.
    135 func methodValueCall()
    136