...
Run Format

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		"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	

View as plain text