mirror of
https://github.com/golang/go
synced 2024-11-18 19:54:44 -07:00
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
This commit is contained in:
parent
bf6a1e674e
commit
118786e3d6
@ -196,10 +196,15 @@ func NewFunc(pos token.Pos, pkg *Package, name string, typ Type) *Func {
|
|||||||
return &Func{object{nil, pos, pkg, name, typ}}
|
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
|
var buf bytes.Buffer
|
||||||
|
obj.fullname(&buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
buf.WriteString("func ")
|
func (obj *Func) fullname(buf *bytes.Buffer) {
|
||||||
sig := obj.typ.(*Signature)
|
sig := obj.typ.(*Signature)
|
||||||
if recv := sig.Recv(); recv != nil {
|
if recv := sig.Recv(); recv != nil {
|
||||||
buf.WriteByte('(')
|
buf.WriteByte('(')
|
||||||
@ -210,17 +215,22 @@ func (obj *Func) String() string {
|
|||||||
// Don't print it in full.
|
// Don't print it in full.
|
||||||
buf.WriteString("interface")
|
buf.WriteString("interface")
|
||||||
} else {
|
} else {
|
||||||
writeType(&buf, recv.Type())
|
writeType(buf, recv.Type())
|
||||||
}
|
}
|
||||||
buf.WriteByte(')')
|
buf.WriteByte(')')
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte('.')
|
||||||
}
|
} else if obj.pkg != nil {
|
||||||
if obj.pkg != nil {
|
|
||||||
buf.WriteString(obj.pkg.name)
|
buf.WriteString(obj.pkg.name)
|
||||||
buf.WriteByte('.')
|
buf.WriteByte('.')
|
||||||
}
|
}
|
||||||
buf.WriteString(obj.name)
|
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()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@ func jumpThreading(f *Function, b *BasicBlock) bool {
|
|||||||
return false // don't apply to entry block
|
return false // don't apply to entry block
|
||||||
}
|
}
|
||||||
if b.Instrs == nil {
|
if b.Instrs == nil {
|
||||||
fmt.Println("empty block ", b)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if _, ok := b.Instrs[0].(*Jump); !ok {
|
if _, ok := b.Instrs[0].(*Jump); !ok {
|
||||||
|
@ -778,7 +778,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
|||||||
// e.Fun is not a selector.
|
// e.Fun is not a selector.
|
||||||
// Evaluate it in the usual way.
|
// Evaluate it in the usual way.
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Func = b.expr(fn, e.Fun)
|
c.Value = b.expr(fn, e.Fun)
|
||||||
return
|
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.
|
// e.Fun refers to a package-level func or var.
|
||||||
// Evaluate it in the usual way.
|
// Evaluate it in the usual way.
|
||||||
if selKind == token.PACKAGE {
|
if selKind == token.PACKAGE {
|
||||||
c.Func = b.expr(fn, e.Fun)
|
c.Value = b.expr(fn, e.Fun)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,7 +802,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
|||||||
// interface wrapper function, or promotion wrapper.
|
// interface wrapper function, or promotion wrapper.
|
||||||
//
|
//
|
||||||
// For now, we evaluate it in the usual way.
|
// 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
|
// TODO(adonovan): opt: inline expr() here, to make
|
||||||
// the call static and to avoid generation of
|
// 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)
|
v = emitLoad(fn, v)
|
||||||
}
|
}
|
||||||
// Invoke-mode call.
|
// Invoke-mode call.
|
||||||
c.Recv = v
|
c.Value = v
|
||||||
c.Method = obj
|
c.Method = obj
|
||||||
} else {
|
} else {
|
||||||
// "Call"-mode call.
|
// "Call"-mode call.
|
||||||
c.Func = fn.Prog.concreteMethod(obj)
|
c.Value = fn.Prog.concreteMethod(obj)
|
||||||
c.Args = append(c.Args, v)
|
c.Args = append(c.Args, v)
|
||||||
}
|
}
|
||||||
return
|
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
|
// Field access: x.f() where x.f is a function value
|
||||||
// in a struct field f; not a method call.
|
// in a struct field f; not a method call.
|
||||||
// Evaluate it in the usual way.
|
// Evaluate it in the usual way.
|
||||||
c.Func = b.expr(fn, e.Fun)
|
c.Value = b.expr(fn, e.Fun)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1731,7 +1731,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
|
|||||||
} else {
|
} else {
|
||||||
// length = len(x).
|
// length = len(x).
|
||||||
var c Call
|
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.Call.Args = []Value{x}
|
||||||
c.setType(tInt)
|
c.setType(tInt)
|
||||||
length = fn.emit(&c)
|
length = fn.emit(&c)
|
||||||
@ -2336,7 +2336,7 @@ func (p *Package) Build() {
|
|||||||
// Call the init() function of each package we import.
|
// Call the init() function of each package we import.
|
||||||
for _, obj := range p.info.Imports() {
|
for _, obj := range p.info.Imports() {
|
||||||
var v Call
|
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.Call.pos = init.pos
|
||||||
v.setType(types.NewTuple())
|
v.setType(types.NewTuple())
|
||||||
init.emit(&v)
|
init.emit(&v)
|
||||||
|
@ -382,12 +382,13 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
|
|||||||
// interface method lookup if needed.
|
// interface method lookup if needed.
|
||||||
//
|
//
|
||||||
func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
|
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.
|
// Function call.
|
||||||
fn = fr.get(call.Func)
|
fn = v
|
||||||
} else {
|
} else {
|
||||||
// Interface method invocation.
|
// Interface method invocation.
|
||||||
recv := fr.get(call.Recv).(iface)
|
recv := v.(iface)
|
||||||
if recv.t == nil {
|
if recv.t == nil {
|
||||||
panic("method invoked on nil interface")
|
panic("method invoked on nil interface")
|
||||||
}
|
}
|
||||||
|
@ -111,9 +111,9 @@ func printCall(v *CallCommon, prefix string, instr Instruction) string {
|
|||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.WriteString(prefix)
|
b.WriteString(prefix)
|
||||||
if !v.IsInvoke() {
|
if !v.IsInvoke() {
|
||||||
b.WriteString(relName(v.Func, instr))
|
b.WriteString(relName(v.Value, instr))
|
||||||
} else {
|
} 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("(")
|
b.WriteString("(")
|
||||||
for i, arg := range v.Args {
|
for i, arg := range v.Args {
|
||||||
|
@ -51,8 +51,8 @@ func (prog *Program) MethodSet(typ types.Type) MethodSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// populateMethodSet returns the method set for typ, ensuring that it
|
// populateMethodSet returns the method set for typ, ensuring that it
|
||||||
// contains at least the value for obj, if that is a key.
|
// contains at least the function for meth, if that is a key.
|
||||||
// If id is empty, the entire method set is populated.
|
// If meth is nil, the entire method set is populated.
|
||||||
//
|
//
|
||||||
// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
|
// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
|
||||||
//
|
//
|
||||||
@ -106,8 +106,9 @@ func methodSet(typ types.Type) *types.MethodSet {
|
|||||||
return typ.MethodSet()
|
return typ.MethodSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupMethod returns the method id of type typ, building wrapper
|
// LookupMethod returns the Function for the specified method object,
|
||||||
// methods on demand. It returns nil if the typ has no such method.
|
// building wrapper methods on demand. It returns nil if the typ has
|
||||||
|
// no such method.
|
||||||
//
|
//
|
||||||
// Thread-safe.
|
// Thread-safe.
|
||||||
//
|
//
|
||||||
@ -146,7 +147,6 @@ func findMethod(prog *Program, meth *types.Method) *Function {
|
|||||||
return interfaceMethodWrapper(prog, meth.Recv(), meth.Func)
|
return interfaceMethodWrapper(prog, meth.Recv(), meth.Func)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invariant: fn.Signature.Recv().Type() == recvType(meth.Func)
|
|
||||||
return prog.concreteMethod(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)
|
old := meth.Func.Type().(*types.Signature)
|
||||||
sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
|
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 {
|
if prog.mode&LogSource != 0 {
|
||||||
defer logStack("make %s to (%s)", description, typ)()
|
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()) {
|
if !isPointer(old.Recv().Type()) {
|
||||||
v = emitLoad(fn, v)
|
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)
|
c.Call.Args = append(c.Call.Args, v)
|
||||||
} else {
|
} else {
|
||||||
c.Call.Method = meth.Func
|
c.Call.Method = meth.Func
|
||||||
c.Call.Recv = emitLoad(fn, v)
|
c.Call.Value = emitLoad(fn, v)
|
||||||
}
|
}
|
||||||
for _, arg := range fn.Params[1:] {
|
for _, arg := range fn.Params[1:] {
|
||||||
c.Call.Args = append(c.Call.Args, arg)
|
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
|
var c Call
|
||||||
|
|
||||||
c.Call.Method = obj
|
c.Call.Method = obj
|
||||||
c.Call.Recv = fn.Params[0]
|
c.Call.Value = fn.Params[0]
|
||||||
for _, arg := range fn.Params[1:] {
|
for _, arg := range fn.Params[1:] {
|
||||||
c.Call.Args = append(c.Call.Args, arg)
|
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)
|
s := obj.Type().(*types.Signature)
|
||||||
fn = &Function{
|
fn = &Function{
|
||||||
name: "bound$" + obj.String(),
|
name: "bound$" + obj.FullName(),
|
||||||
Signature: types.NewSignature(nil, nil, s.Params(), s.Results(), s.IsVariadic()), // drop recv
|
Signature: types.NewSignature(nil, nil, s.Params(), s.Results(), s.IsVariadic()),
|
||||||
Synthetic: description,
|
Synthetic: description,
|
||||||
Prog: prog,
|
Prog: prog,
|
||||||
pos: obj.Pos(),
|
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.FreeVars = []*Capture{cap}
|
||||||
fn.startBody()
|
fn.startBody()
|
||||||
createParams(fn)
|
createParams(fn)
|
||||||
var c Call
|
var c Call
|
||||||
|
|
||||||
if _, ok := recvType(obj).Underlying().(*types.Interface); !ok { // concrete
|
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}
|
c.Call.Args = []Value{cap}
|
||||||
} else {
|
} else {
|
||||||
c.Call.Recv = cap
|
c.Call.Value = cap
|
||||||
c.Call.Method = obj
|
c.Call.Method = obj
|
||||||
}
|
}
|
||||||
for _, arg := range fn.Params {
|
for _, arg := range fn.Params {
|
||||||
|
36
ssa/ssa.go
36
ssa/ssa.go
@ -1182,19 +1182,18 @@ type anInstruction struct {
|
|||||||
// interface method invocation, or "call" and "invoke" for short.
|
// interface method invocation, or "call" and "invoke" for short.
|
||||||
//
|
//
|
||||||
// 1. "call" mode: when Method is nil (!IsInvoke), a CallCommon
|
// 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
|
// statically dispatched call to a package-level function, an
|
||||||
// anonymous function, or a method of a named type. Also statically
|
// 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
|
// 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.
|
// call. The StaticCallee method returns the callee in these cases.
|
||||||
//
|
//
|
||||||
// Args contains the arguments to the call. If Func is a method,
|
// Args contains the arguments to the call. If Value is a method,
|
||||||
// Args[0] contains the receiver parameter. Recv and Method are not
|
// Args[0] contains the receiver parameter.
|
||||||
// used in this mode.
|
|
||||||
//
|
//
|
||||||
// Example printed form:
|
// Example printed form:
|
||||||
// t2 = println(t0, t1)
|
// t2 = println(t0, t1)
|
||||||
@ -1203,13 +1202,12 @@ type anInstruction struct {
|
|||||||
//
|
//
|
||||||
// 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon
|
// 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon
|
||||||
// represents a dynamically dispatched call to an interface method.
|
// 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.
|
// 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
|
// as the receiver parameter; in other words, Args[0] holds not the
|
||||||
// receiver but the first true argument. Func is not used in this
|
// receiver but the first true argument.
|
||||||
// mode.
|
|
||||||
//
|
//
|
||||||
// Example printed form:
|
// Example printed form:
|
||||||
// t1 = invoke t0.String()
|
// t1 = invoke t0.String()
|
||||||
@ -1223,11 +1221,9 @@ type anInstruction struct {
|
|||||||
// readability of the printed form.)
|
// readability of the printed form.)
|
||||||
//
|
//
|
||||||
type CallCommon struct {
|
type CallCommon struct {
|
||||||
// TODO(adonovan): combine Recv/Func fields since Method now discriminates.
|
Value Value // receiver (invoke mode) or func value (call mode)
|
||||||
Recv Value // receiver (in "invoke" mode)
|
Method *types.Func // abstract method (invoke mode)
|
||||||
Method *types.Func // abstract method (in "invoke" mode)
|
Args []Value // actual parameters (in static method call, includes receiver)
|
||||||
Func Value // target of call (in "call" mode)
|
|
||||||
Args []Value // actual parameters, including receiver in invoke mode
|
|
||||||
HasEllipsis bool // true iff last Args is a slice of '...' args (needed?)
|
HasEllipsis bool // true iff last Args is a slice of '...' args (needed?)
|
||||||
pos token.Pos // position of CallExpr.Lparen, iff explicit in source
|
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 {
|
if c.Method != nil {
|
||||||
return c.Method.Type().(*types.Signature)
|
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
|
return sig
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticCallee returns the called function if this is a trivially
|
// StaticCallee returns the called function if this is a trivially
|
||||||
// static "call"-mode call.
|
// static "call"-mode call.
|
||||||
func (c *CallCommon) StaticCallee() *Function {
|
func (c *CallCommon) StaticCallee() *Function {
|
||||||
switch fn := c.Func.(type) {
|
switch fn := c.Value.(type) {
|
||||||
case *Function:
|
case *Function:
|
||||||
return fn
|
return fn
|
||||||
case *MakeClosure:
|
case *MakeClosure:
|
||||||
@ -1272,7 +1268,7 @@ func (c *CallCommon) StaticCallee() *Function {
|
|||||||
// Description returns a description of the mode of this call suitable
|
// Description returns a description of the mode of this call suitable
|
||||||
// for a user interface, e.g. "static method call".
|
// for a user interface, e.g. "static method call".
|
||||||
func (c *CallCommon) Description() string {
|
func (c *CallCommon) Description() string {
|
||||||
switch fn := c.Func.(type) {
|
switch fn := c.Value.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
return "dynamic method call" // ("invoke" mode)
|
return "dynamic method call" // ("invoke" mode)
|
||||||
case *MakeClosure:
|
case *MakeClosure:
|
||||||
@ -1429,7 +1425,7 @@ func (v *BinOp) Operands(rands []*Value) []*Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CallCommon) 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 {
|
for i := range c.Args {
|
||||||
rands = append(rands, &c.Args[i])
|
rands = append(rands, &c.Args[i])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user