...

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

View as plain text