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
diff --git a/ssa/blockopt.go b/ssa/blockopt.go
index 71b5e56..9503633 100644
--- a/ssa/blockopt.go
+++ b/ssa/blockopt.go
@@ -60,7 +60,6 @@
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 d992183..8fc5de6 100644
--- a/ssa/builder.go
+++ b/ssa/builder.go
@@ -778,7 +778,7 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
} 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 @@
// 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 131d45b..b1aee54 100644
--- a/ssa/interp/interp.go
+++ b/ssa/interp/interp.go
@@ -382,12 +382,13 @@
// 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 27d2474..0ced85d 100644
--- a/ssa/print.go
+++ b/ssa/print.go
@@ -111,9 +111,9 @@
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 b65a7c9..00fe78c 100644
--- a/ssa/promote.go
+++ b/ssa/promote.go
@@ -51,8 +51,8 @@
}
// 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 @@
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 @@
return interfaceMethodWrapper(prog, meth.Recv(), meth.Func)
}
- // Invariant: fn.Signature.Recv().Type() == recvType(meth.Func)
return prog.concreteMethod(meth.Func)
}
@@ -175,7 +175,7 @@
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 @@
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 @@
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 @@
}
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 7a73913..4e2bfc2 100644
--- a/ssa/ssa.go
+++ b/ssa/ssa.go
@@ -1182,19 +1182,18 @@
// 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 @@
//
// 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 @@
// 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 @@
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 @@
// 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 (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])
}