示例#1
0
// boundMethodWrapper returns a synthetic wrapper function that
// delegates to a concrete or interface method.
// The wrapper has one free variable, the method's receiver.
// Use MakeClosure with such a wrapper to construct a bound-method
// closure.  e.g.:
//
//   type T int          or:  type T interface { meth() }
//   func (t T) meth()
//   var t T
//   f := t.meth
//   f() // calls t.meth()
//
// f is a closure of a synthetic wrapper defined as if by:
//
//   f := func() { return t.meth() }
//
// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
//
func boundMethodWrapper(prog *Program, obj *types.Func) *Function {
	prog.methodsMu.Lock()
	defer prog.methodsMu.Unlock()
	fn, ok := prog.boundMethodWrappers[obj]
	if !ok {
		description := fmt.Sprintf("bound method wrapper for %s", obj)
		if prog.mode&LogSource != 0 {
			defer logStack("%s", description)()
		}
		fn = &Function{
			name:      "bound$" + obj.FullName(),
			Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
			Synthetic: description,
			Prog:      prog,
			Pkg:       prog.packages[obj.Pkg()],
			pos:       obj.Pos(),
		}

		cap := &Capture{name: "recv", typ: recvType(obj), parent: fn}
		fn.FreeVars = []*Capture{cap}
		fn.startBody()
		createParams(fn)
		var c Call

		if _, ok := recvType(obj).Underlying().(*types.Interface); !ok { // concrete
			c.Call.Value = prog.declaredFunc(obj)
			c.Call.Args = []Value{cap}
		} else {
			c.Call.Value = cap
			c.Call.Method = obj
		}
		for _, arg := range fn.Params {
			c.Call.Args = append(c.Call.Args, arg)
		}
		emitTailCall(fn, &c)
		fn.finishBody()

		prog.boundMethodWrappers[obj] = fn
	}
	return fn
}