return buf.String()
}
+type two [2]uintptr
+
// Difficult test for function call because of
// implicit padding between arguments.
-func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
- return b, c, d
+func dummy(b byte, c int, d byte, e two, f byte, g float32, h byte) (i byte, j int, k byte, l two, m byte, n float32, o byte) {
+ return b, c, d, e, f, g, h
}
func TestFunc(t *testing.T) {
- ret := ValueOf(dummy).Call([]Value{ValueOf(byte(10)), ValueOf(20), ValueOf(byte(30))})
- if len(ret) != 3 {
- t.Fatalf("Call returned %d values, want 3", len(ret))
+ ret := ValueOf(dummy).Call([]Value{
+ ValueOf(byte(10)),
+ ValueOf(20),
+ ValueOf(byte(30)),
+ ValueOf(two{40, 50}),
+ ValueOf(byte(60)),
+ ValueOf(float32(70)),
+ ValueOf(byte(80)),
+ })
+ if len(ret) != 7 {
+ t.Fatalf("Call returned %d values, want 7", len(ret))
}
i := byte(ret[0].Uint())
j := int(ret[1].Int())
k := byte(ret[2].Uint())
- if i != 10 || j != 20 || k != 30 {
- t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
+ l := ret[3].Interface().(two)
+ m := byte(ret[4].Uint())
+ n := float32(ret[5].Float())
+ o := byte(ret[6].Uint())
+
+ if i != 10 || j != 20 || k != 30 || l != (two{40, 50}) || m != 60 || n != 70 || o != 80 {
+ t.Errorf("Call returned %d, %d, %d, %v, %d, %g, %d; want 10, 20, 30, [40, 50], 60, 70, 80", i, j, k, l, m, n, o)
+ }
+}
+
+func TestMakeFunc(t *testing.T) {
+ f := dummy
+ fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
+ ValueOf(&f).Elem().Set(fv)
+
+ // Call g with small arguments so that there is
+ // something predictable (and different from the
+ // correct results) in those positions on the stack.
+ g := dummy
+ g(1, 2, 3, two{4, 5}, 6, 7, 8)
+
+ // Call constructed function f.
+ i, j, k, l, m, n, o := f(10, 20, 30, two{40, 50}, 60, 70, 80)
+ if i != 10 || j != 20 || k != 30 || l != (two{40, 50}) || m != 60 || n != 70 || o != 80 {
+ t.Errorf("Call returned %d, %d, %d, %v, %d, %g, %d; want 10, 20, 30, [40, 50], 60, 70, 80", i, j, k, l, m, n, o)
}
}
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// makeFuncStub is jumped to by the code generated by MakeFunc.
+// The code sets AX = type, BX = fn, CX = frame before the jump.
+// See the comment on the declaration of makeFuncStub in value.go
+// for more details.
+TEXT ·makeFuncStub(SB),7,$12
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL CX, 8(SP)
+ CALL ·callReflect(SB)
+ RET
+
+// unused
+TEXT ·cacheflush(SB),7,$0
+ RET
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// makeFuncStub is jumped to by the code generated by MakeFunc.
+// The code sets AX = type, BX = fn, CX = frame before the jump.
+// See the comment on the declaration of makeFuncStub in value.go
+// for more details.
+TEXT ·makeFuncStub(SB),7,$24
+ MOVQ AX, 0(SP)
+ MOVQ BX, 8(SP)
+ MOVQ CX, 16(SP)
+ CALL ·callReflect(SB)
+ RET
+
+// unused
+TEXT ·cacheflush(SB),7,$0
+ RET
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// makeFuncStub is jumped to by the code generated by MakeFunc.
+// The code sets R0 = type, R1 = fn, R2 = frame before the jump.
+// See the comment on the declaration of makeFuncStub in value.go
+// for more details.
+TEXT ·makeFuncStub(SB),7,$12
+ MOVW R0, 4(R13)
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ BL ·callReflect(SB)
+ RET
+
+TEXT ·cacheflush(SB),7,$-4
+ B runtime·cacheflush(SB)
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect_test
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func ExampleMakeFunc() {
+ // swap is the implementation passed to MakeFunc.
+ // It must work in terms of reflect.Values so that it is possible
+ // to write code without knowing beforehand what the types
+ // will be.
+ swap := func(in []reflect.Value) []reflect.Value {
+ return []reflect.Value{in[1], in[0]}
+ }
+
+ // makeSwap expects fptr to be a pointer to a nil function.
+ // It sets that pointer to a new function created with MakeFunc.
+ // When the function is invoked, reflect turns the arguments
+ // into Values, calls swap, and then turns swap's result slice
+ // into the values returned by the new function.
+ makeSwap := func(fptr interface{}) {
+ // fptr is a pointer to a function.
+ // Obtain the function value itself (likely nil) as a reflect.Value
+ // so that we can query its type and then set the value.
+ fn := reflect.ValueOf(fptr).Elem()
+
+ // Make a function of the right type.
+ v := reflect.MakeFunc(fn.Type(), swap)
+
+ // Assign it to the value fn represents.
+ fn.Set(v)
+ }
+
+ // Make and call a swap function for ints.
+ var intSwap func(int, int) (int, int)
+ makeSwap(&intSwap)
+ fmt.Println(intSwap(0, 1))
+
+ // Make and call a swap function for float64s.
+ var floatSwap func(float64, float64) (float64, float64)
+ makeSwap(&floatSwap)
+ fmt.Println(floatSwap(2.72, 3.14))
+
+ // Output:
+ // 1 0
+ // 3.14 2.72
+}
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MakeFunc implementation.
+
+package reflect
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// makeFuncImpl is the closure value implementing the function
+// returned by MakeFunc.
+type makeFuncImpl struct {
+ // References visible to the garbage collector.
+ // The code array below contains the same references
+ // embedded in the machine code.
+ typ *commonType
+ fn func([]Value) []Value
+
+ // code is the actual machine code invoked for the closure.
+ code [40]byte
+}
+
+// MakeFunc returns a new function of the given Type
+// that wraps the function fn. When called, that new function
+// does the following:
+//
+// - converts its arguments to a list of Values args.
+// - runs results := fn(args).
+// - returns the results as a slice of Values, one per formal result.
+//
+// The implementation fn can assume that the argument Value slice
+// has the number and type of arguments given by typ.
+// If typ describes a variadic function, the final Value is itself
+// a slice representing the variadic arguments, as in the
+// body of a variadic function. The result Value slice returned by fn
+// must have the number and type of results given by typ.
+//
+// The Value.Call method allows the caller to invoke a typed function
+// in terms of Values; in contrast, MakeFunc allows the caller to implement
+// a typed function in terms of Values.
+//
+// The Examples section of the documentation includes an illustration
+// of how to use MakeFunc to build a swap function for different types.
+//
+func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
+ if typ.Kind() != Func {
+ panic("reflect: call of MakeFunc with non-Func type")
+ }
+
+ // Gather type pointer and function pointers
+ // for use in hand-assembled closure.
+ t := typ.common()
+
+ // Create function impl.
+ // We don't need to save a pointer to makeFuncStub, because it is in
+ // the text segment and cannot be garbage collected.
+ impl := &makeFuncImpl{
+ typ: t,
+ fn: fn,
+ }
+
+ tptr := unsafe.Pointer(t)
+ fptr := *(*unsafe.Pointer)(unsafe.Pointer(&fn))
+ tmp := makeFuncStub
+ stub := *(*unsafe.Pointer)(unsafe.Pointer(&tmp))
+
+ // Create code. Copy template and fill in pointer values.
+ switch runtime.GOARCH {
+ default:
+ panic("reflect.MakeFunc: unexpected GOARCH: " + runtime.GOARCH)
+
+ case "amd64":
+ copy(impl.code[:], amd64CallStub)
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[2])) = tptr
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[12])) = fptr
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[22])) = stub
+
+ case "386":
+ copy(impl.code[:], _386CallStub)
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[1])) = tptr
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[6])) = fptr
+ *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[11])) = stub
+
+ case "arm":
+ code := (*[10]uintptr)(unsafe.Pointer(&impl.code[0]))
+ copy(code[:], armCallStub)
+ code[len(armCallStub)] = uintptr(tptr)
+ code[len(armCallStub)+1] = uintptr(fptr)
+ code[len(armCallStub)+2] = uintptr(stub)
+
+ cacheflush(&impl.code[0], &impl.code[len(impl.code)-1])
+ }
+
+ return Value{t, unsafe.Pointer(&impl.code[0]), flag(Func) << flagKindShift}
+}
+
+func cacheflush(start, end *byte)
+
+// makeFuncStub is an assembly function used by the code generated
+// and returned from MakeFunc. The code returned from makeFunc
+// does, schematically,
+//
+// MOV $typ, R0
+// MOV $fn, R1
+// MOV $0(FP), R2
+// JMP makeFuncStub
+//
+// That is, it copies the type and function pointer passed to MakeFunc
+// into the first two machine registers and then copies the argument frame
+// pointer into the third. Then it jumps to makeFuncStub, which calls callReflect
+// with those arguments. Using a jmp to makeFuncStub instead of making the
+// call directly keeps the allocated code simpler but, perhaps more
+// importantly, also keeps the allocated PCs off the call stack.
+// Nothing ever returns to the allocated code.
+func makeFuncStub()
+
+// amd64CallStub is the MakeFunc code template for amd64 machines.
+var amd64CallStub = []byte{
+ // MOVQ $constant, AX
+ 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // MOVQ $constant, BX
+ 0x48, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // MOVQ $constant, DX
+ 0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // LEAQ 8(SP), CX (argument frame)
+ 0x48, 0x8d, 0x4c, 0x24, 0x08,
+ // JMP *DX
+ 0xff, 0xe2,
+}
+
+// _386CallStub is the MakeFunc code template for 386 machines.
+var _386CallStub = []byte{
+ // MOVL $constant, AX
+ 0xb8, 0x00, 0x00, 0x00, 0x00,
+ // MOVL $constant, BX
+ 0xbb, 0x00, 0x00, 0x00, 0x00,
+ // MOVL $constant, DX
+ 0xba, 0x00, 0x00, 0x00, 0x00,
+ // LEAL 4(SP), CX (argument frame)
+ 0x8d, 0x4c, 0x24, 0x04,
+ // JMP *DX
+ 0xff, 0xe2,
+}
+
+// armCallStub is the MakeFunc code template for arm machines.
+var armCallStub = []uintptr{
+ 0xe59f000c, // MOVW 0x14(PC), R0
+ 0xe59f100c, // MOVW 0x14(PC), R1
+ 0xe28d2004, // MOVW $4(SP), R2
+ 0xe59ff008, // MOVW 0x10(PC), PC
+ 0xeafffffe, // B 0(PC), just in case
+}
return ret
}
+// callReflect is the call implementation used by a function
+// returned by MakeFunc. In many ways it is the opposite of the
+// method Value.call above. The method above converts a call using Values
+// into a call of a function with a concrete argument frame, while
+// callReflect converts a call of a function with a concrete argument
+// frame into a call using Values.
+// It is in this file so that it can be next to the call method above.
+// The remainder of the MakeFunc implementation is in makefunc.go.
+func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) {
+ // Copy argument frame into Values.
+ ptr := frame
+ off := uintptr(0)
+ in := make([]Value, 0, len(ftyp.in))
+ for _, arg := range ftyp.in {
+ typ := toCommonType(arg)
+ off += -off & uintptr(typ.align-1)
+ v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
+ if typ.size <= ptrSize {
+ // value fits in word.
+ v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
+ } else {
+ // value does not fit in word.
+ // Must make a copy, because f might keep a reference to it,
+ // and we cannot let f keep a reference to the stack frame
+ // after this function returns, not even a read-only reference.
+ v.val = unsafe_New(typ)
+ memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
+ v.flag |= flagIndir
+ }
+ in = append(in, v)
+ off += typ.size
+ }
+
+ // Call underlying function.
+ out := f(in)
+ if len(out) != len(ftyp.out) {
+ panic("reflect: wrong return count from function created by MakeFunc")
+ }
+
+ // Copy results back into argument frame.
+ if len(ftyp.out) > 0 {
+ off += -off & (ptrSize - 1)
+ for i, arg := range ftyp.out {
+ typ := toCommonType(arg)
+ v := out[i]
+ if v.typ != typ {
+ panic("reflect: function created by MakeFunc using " + funcName(f) +
+ " returned wrong type: have " +
+ out[i].typ.String() + " for " + typ.String())
+ }
+ if v.flag&flagRO != 0 {
+ panic("reflect: function created by MakeFunc using " + funcName(f) +
+ " returned value obtained from unexported field")
+ }
+ off += -off & uintptr(typ.align-1)
+ addr := unsafe.Pointer(uintptr(ptr) + off)
+ if v.flag&flagIndir == 0 {
+ storeIword(addr, iword(v.val), typ.size)
+ } else {
+ memmove(addr, v.val, typ.size)
+ }
+ off += typ.size
+ }
+ }
+}
+
+// funcName returns the name of f, for use in error messages.
+func funcName(f func([]Value) []Value) string {
+ pc := *(*uintptr)(unsafe.Pointer(&f))
+ rf := runtime.FuncForPC(pc)
+ if rf != nil {
+ return rf.Name()
+ }
+ return "closure"
+}
+
// Cap returns v's capacity.
// It panics if v's Kind is not Array, Chan, or Slice.
func (v Value) Cap() int {