Commit 139160eb authored by Alan Donovan's avatar Alan Donovan

exp/ssa: fix bug in bridge method

Bridge methods for embedded interfaces were
passing the interface twice: once as receiver,
once as first param.
Covered by $GOROOT/test/ddd.go.

Also:
- invent names ("arg%d") for parameters if missing.
- refactoring: move common code for bridge methods into
  createParams and emitTailCall.

R=gri
CC=golang-dev
https://golang.org/cl/7437047
parent f5ceeb94
...@@ -23,7 +23,6 @@ package ssa ...@@ -23,7 +23,6 @@ package ssa
// TODO(adonovan): // TODO(adonovan):
// - fix: support f(g()) where g has multiple result parameters. // - fix: support f(g()) where g has multiple result parameters.
// - fix: multiple labels on same statement.
import ( import (
"fmt" "fmt"
......
...@@ -221,11 +221,17 @@ func emitExtract(f *Function, tuple Value, index int, typ types.Type) Value { ...@@ -221,11 +221,17 @@ func emitExtract(f *Function, tuple Value, index int, typ types.Type) Value {
return f.emit(e) return f.emit(e)
} }
// emitTailCall emits to f a function call in tail position. // emitTailCall emits to f a function call in tail position,
// passing on all but the first formal parameter to f as actual
// values in the call. Intended for delegating bridge methods.
// Precondition: f does/will not use deferred procedure calls. // Precondition: f does/will not use deferred procedure calls.
// Postcondition: f.currentBlock is nil. // Postcondition: f.currentBlock is nil.
// //
func emitTailCall(f *Function, call *Call) { func emitTailCall(f *Function, call *Call) {
for _, arg := range f.Params[1:] {
call.Args = append(call.Args, arg)
}
call.Type_ = &types.Result{Values: f.Signature.Results}
tuple := f.emit(call) tuple := f.emit(call)
var ret Ret var ret Ret
switch { switch {
......
...@@ -272,13 +272,7 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function ...@@ -272,13 +272,7 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
} }
fn.start(nil) fn.start(nil)
fn.addSpilledParam(sig.Recv) fn.addSpilledParam(sig.Recv)
var last *Parameter createParams(fn)
for _, p := range fn.Signature.Params {
last = fn.addParam(p.Name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
// Each bridge method performs a sequence of selections, // Each bridge method performs a sequence of selections,
// then tailcalls the promoted method. // then tailcalls the promoted method.
...@@ -315,22 +309,30 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function ...@@ -315,22 +309,30 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function
fn.Pos = c.Func.(*Function).Pos // TODO(adonovan): fix: wrong. fn.Pos = c.Func.(*Function).Pos // TODO(adonovan): fix: wrong.
c.Pos = fn.Pos // TODO(adonovan): fix: wrong. c.Pos = fn.Pos // TODO(adonovan): fix: wrong.
c.Args = append(c.Args, v) c.Args = append(c.Args, v)
for _, arg := range fn.Params[1:] {
c.Args = append(c.Args, arg)
}
} else { } else {
c.Recv = v c.Recv = v
c.Method = 0 c.Method = 0
for _, arg := range fn.Params {
c.Args = append(c.Args, arg)
}
} }
c.Type_ = &types.Result{Values: sig.Results}
emitTailCall(fn, &c) emitTailCall(fn, &c)
fn.finish() fn.finish()
return fn return fn
} }
// createParams creates parameters for bridge method fn based on its Signature.
func createParams(fn *Function) {
var last *Parameter
for i, p := range fn.Signature.Params {
name := p.Name
if name == "" {
name = fmt.Sprintf("arg%d", i)
}
last = fn.addParam(name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
}
// Thunks for standalone interface methods ---------------------------------------- // Thunks for standalone interface methods ----------------------------------------
// makeImethodThunk returns a synthetic thunk function permitting an // makeImethodThunk returns a synthetic thunk function permitting an
...@@ -373,21 +375,10 @@ func makeImethodThunk(prog *Program, typ types.Type, id Id) *Function { ...@@ -373,21 +375,10 @@ func makeImethodThunk(prog *Program, typ types.Type, id Id) *Function {
// TODO(adonovan): set fn.Pos to location of interface method ast.Field. // TODO(adonovan): set fn.Pos to location of interface method ast.Field.
fn.start(nil) fn.start(nil)
fn.addParam("recv", typ) fn.addParam("recv", typ)
var last *Parameter createParams(fn)
for _, p := range fn.Signature.Params {
last = fn.addParam(p.Name, p.Type)
}
if fn.Signature.IsVariadic {
last.Type_ = &types.Slice{Elt: last.Type_}
}
var c Call var c Call
c.Method = index c.Method = index
c.Recv = fn.Params[0] c.Recv = fn.Params[0]
for _, arg := range fn.Params[1:] {
c.Args = append(c.Args, arg)
}
c.Type_ = &types.Result{Values: sig.Results}
emitTailCall(fn, &c) emitTailCall(fn, &c)
fn.finish() fn.finish()
return fn return fn
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment