diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/reflect/makefunc.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/reflect/makefunc.go')
-rw-r--r-- | src/reflect/makefunc.go | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go new file mode 100644 index 000000000..d89f7f681 --- /dev/null +++ b/src/reflect/makefunc.go @@ -0,0 +1,129 @@ +// 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 ( + "unsafe" +) + +// makeFuncImpl is the closure value implementing the function +// returned by MakeFunc. +type makeFuncImpl struct { + code uintptr + stack *bitVector // stack bitmap for args - offset known to runtime + typ *funcType + fn func([]Value) []Value +} + +// 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 slice of Values. +// - 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") + } + + t := typ.common() + ftyp := (*funcType)(unsafe.Pointer(t)) + + // Indirect Go func value (dummy) to obtain + // actual code address. (A Go func value is a pointer + // to a C function pointer. http://golang.org/s/go11func.) + dummy := makeFuncStub + code := **(**uintptr)(unsafe.Pointer(&dummy)) + + // makeFuncImpl contains a stack map for use by the runtime + _, _, _, stack := funcLayout(t, nil) + + impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn} + + return Value{t, unsafe.Pointer(impl), flag(Func)} +} + +// makeFuncStub is an assembly function that is the code half of +// the function returned from MakeFunc. It expects a *callReflectFunc +// as its context register, and its job is to invoke callReflect(ctxt, frame) +// where ctxt is the context register and frame is a pointer to the first +// word in the passed-in argument frame. +func makeFuncStub() + +type methodValue struct { + fn uintptr + stack *bitVector // stack bitmap for args - offset known to runtime + method int + rcvr Value +} + +// makeMethodValue converts v from the rcvr+method index representation +// of a method value to an actual method func value, which is +// basically the receiver value with a special bit set, into a true +// func value - a value holding an actual func. The output is +// semantically equivalent to the input as far as the user of package +// reflect can tell, but the true func representation can be handled +// by code like Convert and Interface and Assign. +func makeMethodValue(op string, v Value) Value { + if v.flag&flagMethod == 0 { + panic("reflect: internal error: invalid use of makeMethodValue") + } + + // Ignoring the flagMethod bit, v describes the receiver, not the method type. + fl := v.flag & (flagRO | flagAddr | flagIndir) + fl |= flag(v.typ.Kind()) + rcvr := Value{v.typ, v.ptr, fl} + + // v.Type returns the actual type of the method value. + funcType := v.Type().(*rtype) + + // Indirect Go func value (dummy) to obtain + // actual code address. (A Go func value is a pointer + // to a C function pointer. http://golang.org/s/go11func.) + dummy := methodValueCall + code := **(**uintptr)(unsafe.Pointer(&dummy)) + + // methodValue contains a stack map for use by the runtime + _, _, _, stack := funcLayout(funcType, nil) + + fv := &methodValue{ + fn: code, + stack: stack, + method: int(v.flag) >> flagMethodShift, + rcvr: rcvr, + } + + // Cause panic if method is not appropriate. + // The panic would still happen during the call if we omit this, + // but we want Interface() and other operations to fail early. + methodReceiver(op, fv.rcvr, fv.method) + + return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)} +} + +// methodValueCall is an assembly function that is the code half of +// the function returned from makeMethodValue. It expects a *methodValue +// as its context register, and its job is to invoke callMethod(ctxt, frame) +// where ctxt is the context register and frame is a pointer to the first +// word in the passed-in argument frame. +func methodValueCall() |