From 118786e3d67de12a1f0dbb4a34e30b55dfb75448 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 26 Jul 2013 14:06:26 -0400 Subject: [PATCH] go.tools/ssa: combine CallCommon.{Recv,Func} as Value. Also: - add types.Func.FullName() (e.g. "fmt.Println", "(main.S).f") - remove rogue print stmt. - fix bad docstrings. R=gri CC=golang-dev https://golang.org/cl/11936044 --- go/types/objects.go | 24 +++++++++++++++++------- ssa/blockopt.go | 1 - ssa/builder.go | 16 ++++++++-------- ssa/interp/interp.go | 7 ++++--- ssa/print.go | 4 ++-- ssa/promote.go | 28 ++++++++++++++-------------- ssa/ssa.go | 36 ++++++++++++++++-------------------- 7 files changed, 61 insertions(+), 55 deletions(-) diff --git a/go/types/objects.go b/go/types/objects.go index 69423f46..a5bf00c4 100644 --- a/go/types/objects.go +++ b/go/types/objects.go @@ -196,10 +196,15 @@ func NewFunc(pos token.Pos, pkg *Package, name string, typ Type) *Func { return &Func{object{nil, pos, pkg, name, typ}} } -func (obj *Func) String() string { +// FullName returns the package- or receiver-type-qualified name of +// function or method obj. +func (obj *Func) FullName() string { var buf bytes.Buffer + obj.fullname(&buf) + return buf.String() +} - buf.WriteString("func ") +func (obj *Func) fullname(buf *bytes.Buffer) { sig := obj.typ.(*Signature) if recv := sig.Recv(); recv != nil { buf.WriteByte('(') @@ -210,17 +215,22 @@ func (obj *Func) String() string { // Don't print it in full. buf.WriteString("interface") } else { - writeType(&buf, recv.Type()) + writeType(buf, recv.Type()) } buf.WriteByte(')') - buf.WriteByte(' ') - } - if obj.pkg != nil { + buf.WriteByte('.') + } else if obj.pkg != nil { buf.WriteString(obj.pkg.name) buf.WriteByte('.') } buf.WriteString(obj.name) - writeSignature(&buf, sig) +} + +func (obj *Func) String() string { + var buf bytes.Buffer + buf.WriteString("func ") + obj.fullname(&buf) + writeSignature(&buf, obj.typ.(*Signature)) return buf.String() } diff --git a/ssa/blockopt.go b/ssa/blockopt.go index 71b5e564..95036335 100644 --- a/ssa/blockopt.go +++ b/ssa/blockopt.go @@ -60,7 +60,6 @@ func jumpThreading(f *Function, b *BasicBlock) bool { return false // don't apply to entry block } if b.Instrs == nil { - fmt.Println("empty block ", b) return false } if _, ok := b.Instrs[0].(*Jump); !ok { diff --git a/ssa/builder.go b/ssa/builder.go index d9921838..8fc5de6a 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -778,7 +778,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // e.Fun is not a selector. // Evaluate it in the usual way. if !ok { - c.Func = b.expr(fn, e.Fun) + c.Value = b.expr(fn, e.Fun) return } @@ -787,7 +787,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // e.Fun refers to a package-level func or var. // Evaluate it in the usual way. if selKind == token.PACKAGE { - c.Func = b.expr(fn, e.Fun) + c.Value = b.expr(fn, e.Fun) return } @@ -802,7 +802,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // interface wrapper function, or promotion wrapper. // // For now, we evaluate it in the usual way. - c.Func = b.expr(fn, e.Fun) + c.Value = b.expr(fn, e.Fun) // TODO(adonovan): opt: inline expr() here, to make // the call static and to avoid generation of @@ -841,11 +841,11 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { v = emitLoad(fn, v) } // Invoke-mode call. - c.Recv = v + c.Value = v c.Method = obj } else { // "Call"-mode call. - c.Func = fn.Prog.concreteMethod(obj) + c.Value = fn.Prog.concreteMethod(obj) c.Args = append(c.Args, v) } return @@ -854,7 +854,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { // Field access: x.f() where x.f is a function value // in a struct field f; not a method call. // Evaluate it in the usual way. - c.Func = b.expr(fn, e.Fun) + c.Value = b.expr(fn, e.Fun) return } @@ -1731,7 +1731,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value } else { // length = len(x). var c Call - c.Call.Func = fn.Prog.builtins[types.Universe.Lookup("len")] + c.Call.Value = fn.Prog.builtins[types.Universe.Lookup("len")] c.Call.Args = []Value{x} c.setType(tInt) length = fn.emit(&c) @@ -2336,7 +2336,7 @@ func (p *Package) Build() { // Call the init() function of each package we import. for _, obj := range p.info.Imports() { var v Call - v.Call.Func = p.Prog.packages[obj].init + v.Call.Value = p.Prog.packages[obj].init v.Call.pos = init.pos v.setType(types.NewTuple()) init.emit(&v) diff --git a/ssa/interp/interp.go b/ssa/interp/interp.go index 131d45b8..b1aee540 100644 --- a/ssa/interp/interp.go +++ b/ssa/interp/interp.go @@ -382,12 +382,13 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation { // interface method lookup if needed. // func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) { - if call.Func != nil { + v := fr.get(call.Value) + if call.Method == nil { // Function call. - fn = fr.get(call.Func) + fn = v } else { // Interface method invocation. - recv := fr.get(call.Recv).(iface) + recv := v.(iface) if recv.t == nil { panic("method invoked on nil interface") } diff --git a/ssa/print.go b/ssa/print.go index 27d2474a..0ced85dc 100644 --- a/ssa/print.go +++ b/ssa/print.go @@ -111,9 +111,9 @@ func printCall(v *CallCommon, prefix string, instr Instruction) string { var b bytes.Buffer b.WriteString(prefix) if !v.IsInvoke() { - b.WriteString(relName(v.Func, instr)) + b.WriteString(relName(v.Value, instr)) } else { - fmt.Fprintf(&b, "invoke %s.%s", relName(v.Recv, instr), v.Method.Name()) + fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name()) } b.WriteString("(") for i, arg := range v.Args { diff --git a/ssa/promote.go b/ssa/promote.go index b65a7c92..00fe78c4 100644 --- a/ssa/promote.go +++ b/ssa/promote.go @@ -51,8 +51,8 @@ func (prog *Program) MethodSet(typ types.Type) MethodSet { } // populateMethodSet returns the method set for typ, ensuring that it -// contains at least the value for obj, if that is a key. -// If id is empty, the entire method set is populated. +// contains at least the function for meth, if that is a key. +// If meth is nil, the entire method set is populated. // // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) // @@ -106,8 +106,9 @@ func methodSet(typ types.Type) *types.MethodSet { return typ.MethodSet() } -// LookupMethod returns the method id of type typ, building wrapper -// methods on demand. It returns nil if the typ has no such method. +// LookupMethod returns the Function for the specified method object, +// building wrapper methods on demand. It returns nil if the typ has +// no such method. // // Thread-safe. // @@ -146,7 +147,6 @@ func findMethod(prog *Program, meth *types.Method) *Function { return interfaceMethodWrapper(prog, meth.Recv(), meth.Func) } - // Invariant: fn.Signature.Recv().Type() == recvType(meth.Func) return prog.concreteMethod(meth.Func) } @@ -175,7 +175,7 @@ func makeWrapper(prog *Program, typ types.Type, meth *types.Method) *Function { old := meth.Func.Type().(*types.Signature) sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic()) - description := fmt.Sprintf("wrapper for (%s).%s", old.Recv(), meth.Func.Name()) + description := fmt.Sprintf("wrapper for %s", meth.Func) if prog.mode&LogSource != 0 { defer logStack("make %s to (%s)", description, typ)() } @@ -218,11 +218,11 @@ func makeWrapper(prog *Program, typ types.Type, meth *types.Method) *Function { if !isPointer(old.Recv().Type()) { v = emitLoad(fn, v) } - c.Call.Func = prog.concreteMethod(meth.Func) + c.Call.Value = prog.concreteMethod(meth.Func) c.Call.Args = append(c.Call.Args, v) } else { c.Call.Method = meth.Func - c.Call.Recv = emitLoad(fn, v) + c.Call.Value = emitLoad(fn, v) } for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) @@ -298,7 +298,7 @@ func interfaceMethodWrapper(prog *Program, typ types.Type, obj *types.Func) *Fun var c Call c.Call.Method = obj - c.Call.Recv = fn.Params[0] + c.Call.Value = fn.Params[0] for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) } @@ -341,24 +341,24 @@ func boundMethodWrapper(prog *Program, obj *types.Func) *Function { } s := obj.Type().(*types.Signature) fn = &Function{ - name: "bound$" + obj.String(), - Signature: types.NewSignature(nil, nil, s.Params(), s.Results(), s.IsVariadic()), // drop recv + name: "bound$" + obj.FullName(), + Signature: types.NewSignature(nil, nil, s.Params(), s.Results(), s.IsVariadic()), Synthetic: description, Prog: prog, pos: obj.Pos(), } - cap := &Capture{name: "recv", typ: s.Recv().Type(), parent: fn} + 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.Func = prog.concreteMethod(obj) + c.Call.Value = prog.concreteMethod(obj) c.Call.Args = []Value{cap} } else { - c.Call.Recv = cap + c.Call.Value = cap c.Call.Method = obj } for _, arg := range fn.Params { diff --git a/ssa/ssa.go b/ssa/ssa.go index 7a739131..4e2bfc22 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -1182,19 +1182,18 @@ type anInstruction struct { // interface method invocation, or "call" and "invoke" for short. // // 1. "call" mode: when Method is nil (!IsInvoke), a CallCommon -// represents an ordinary function call of the value in Func. +// represents an ordinary function call of the value in Value. // -// In the common case in which Func is a *Function, this indicates a +// In the common case in which Value is a *Function, this indicates a // statically dispatched call to a package-level function, an // anonymous function, or a method of a named type. Also statically -// dispatched, but less common, Func may be a *MakeClosure, indicating +// dispatched, but less common, Value may be a *MakeClosure, indicating // an immediately applied function literal with free variables. Any -// other Value of Func indicates a dynamically dispatched function +// other value of Value indicates a dynamically dispatched function // call. The StaticCallee method returns the callee in these cases. // -// Args contains the arguments to the call. If Func is a method, -// Args[0] contains the receiver parameter. Recv and Method are not -// used in this mode. +// Args contains the arguments to the call. If Value is a method, +// Args[0] contains the receiver parameter. // // Example printed form: // t2 = println(t0, t1) @@ -1203,13 +1202,12 @@ type anInstruction struct { // // 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon // represents a dynamically dispatched call to an interface method. -// In this mode, Recv is the interface value and Method is the +// In this mode, Value is the interface value and Method is the // interface's abstract method. // -// Recv is implicitly supplied to the concrete method implementation +// Value is implicitly supplied to the concrete method implementation // as the receiver parameter; in other words, Args[0] holds not the -// receiver but the first true argument. Func is not used in this -// mode. +// receiver but the first true argument. // // Example printed form: // t1 = invoke t0.String() @@ -1223,11 +1221,9 @@ type anInstruction struct { // readability of the printed form.) // type CallCommon struct { - // TODO(adonovan): combine Recv/Func fields since Method now discriminates. - Recv Value // receiver (in "invoke" mode) - Method *types.Func // abstract method (in "invoke" mode) - Func Value // target of call (in "call" mode) - Args []Value // actual parameters, including receiver in invoke mode + Value Value // receiver (invoke mode) or func value (call mode) + Method *types.Func // abstract method (invoke mode) + Args []Value // actual parameters (in static method call, includes receiver) HasEllipsis bool // true iff last Args is a slice of '...' args (needed?) pos token.Pos // position of CallExpr.Lparen, iff explicit in source } @@ -1253,14 +1249,14 @@ func (c *CallCommon) Signature() *types.Signature { if c.Method != nil { return c.Method.Type().(*types.Signature) } - sig, _ := c.Func.Type().Underlying().(*types.Signature) // nil for *Builtin + sig, _ := c.Value.Type().Underlying().(*types.Signature) // nil for *Builtin return sig } // StaticCallee returns the called function if this is a trivially // static "call"-mode call. func (c *CallCommon) StaticCallee() *Function { - switch fn := c.Func.(type) { + switch fn := c.Value.(type) { case *Function: return fn case *MakeClosure: @@ -1272,7 +1268,7 @@ func (c *CallCommon) StaticCallee() *Function { // Description returns a description of the mode of this call suitable // for a user interface, e.g. "static method call". func (c *CallCommon) Description() string { - switch fn := c.Func.(type) { + switch fn := c.Value.(type) { case nil: return "dynamic method call" // ("invoke" mode) case *MakeClosure: @@ -1429,7 +1425,7 @@ func (v *BinOp) Operands(rands []*Value) []*Value { } func (c *CallCommon) Operands(rands []*Value) []*Value { - rands = append(rands, &c.Recv, &c.Func) + rands = append(rands, &c.Value) for i := range c.Args { rands = append(rands, &c.Args[i]) }