mirror of
https://github.com/golang/go
synced 2024-09-18 15:32:18 +00:00
[dev.typeparams] cmd/compile: add method value wrappers to unified IR
Method value wrappers will need dictionary support too, so bring them under the unified IR umbrella as well. Change-Id: Iec36bb04efdf59843d1b00f55d2c44bc841fa2ef Reviewed-on: https://go-review.googlesource.com/c/go/+/331190 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Trust: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
3ea0fcfe15
commit
d44ed5d144
|
@ -2065,6 +2065,8 @@ func (r *reader) wrapType(typ *types.Type, target *ir.Package) {
|
||||||
base.FatalfAt(meth.Pos, "invalid method: %v", meth)
|
base.FatalfAt(meth.Pos, "invalid method: %v", meth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.methodValueWrapper(typ, meth, target)
|
||||||
|
|
||||||
r.methodWrapper(0, typ, meth, target)
|
r.methodWrapper(0, typ, meth, target)
|
||||||
|
|
||||||
// For non-interface types, we also want *T wrappers.
|
// For non-interface types, we also want *T wrappers.
|
||||||
|
@ -2100,21 +2102,81 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
|
||||||
// TODO(mdempsky): Use method.Pos instead?
|
// TODO(mdempsky): Use method.Pos instead?
|
||||||
pos := base.AutogeneratedPos
|
pos := base.AutogeneratedPos
|
||||||
|
|
||||||
|
fn := r.newWrapperFunc(pos, sym, wrapper, method, target)
|
||||||
|
|
||||||
|
var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name)
|
||||||
|
|
||||||
|
// For simple *T wrappers around T methods, panicwrap produces a
|
||||||
|
// nicer panic message.
|
||||||
|
if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
|
||||||
|
cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
|
||||||
|
then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
|
||||||
|
fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// typecheck will add one implicit deref, if necessary,
|
||||||
|
// but not-in-heap types require more for their **T wrappers.
|
||||||
|
for i := 1; i < derefs; i++ {
|
||||||
|
recv = Implicit(ir.NewStarExpr(pos, recv))
|
||||||
|
}
|
||||||
|
|
||||||
|
addTailCall(pos, fn, recv, method)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) methodValueWrapper(tbase *types.Type, method *types.Field, target *ir.Package) {
|
||||||
|
recvType := tbase
|
||||||
|
if !tbase.IsInterface() {
|
||||||
|
recvType = method.Type.Recv().Type
|
||||||
|
if !types.Identical(tbase, types.ReceiverBaseType(recvType)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm")
|
||||||
|
assert(!sym.Uniq())
|
||||||
|
sym.SetUniq(true)
|
||||||
|
|
||||||
|
// TODO(mdempsky): Fix typecheck to not depend on creation of
|
||||||
|
// imported method value wrappers.
|
||||||
|
if false && !reflectdata.NeedEmit(tbase) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): Use method.Pos instead?
|
||||||
|
pos := base.AutogeneratedPos
|
||||||
|
|
||||||
|
fn := r.newWrapperFunc(pos, sym, nil, method, target)
|
||||||
|
fn.SetNeedctxt(true)
|
||||||
|
sym.Def = fn
|
||||||
|
|
||||||
|
// Declare and initialize variable holding receiver.
|
||||||
|
recv := ir.NewNameAt(pos, typecheck.Lookup(".this"))
|
||||||
|
recv.Class = ir.PAUTOHEAP
|
||||||
|
recv.SetType(recvType)
|
||||||
|
recv.Curfn = fn
|
||||||
|
recv.SetIsClosureVar(true)
|
||||||
|
recv.SetByval(true)
|
||||||
|
fn.ClosureVars = append(fn.ClosureVars, recv)
|
||||||
|
|
||||||
|
addTailCall(pos, fn, recv, method)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field, target *ir.Package) *ir.Func {
|
||||||
fn := ir.NewFunc(pos)
|
fn := ir.NewFunc(pos)
|
||||||
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
|
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
|
||||||
fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
|
|
||||||
|
|
||||||
fn.Nname = ir.NewNameAt(pos, sym)
|
name := ir.NewNameAt(pos, sym)
|
||||||
ir.MarkFunc(fn.Nname)
|
ir.MarkFunc(name)
|
||||||
fn.Nname.Func = fn
|
name.Func = fn
|
||||||
fn.Nname.Defn = fn
|
name.Defn = fn
|
||||||
|
fn.Nname = name
|
||||||
|
|
||||||
sig := newWrapperType(wrapper, method.Type)
|
sig := newWrapperType(wrapper, method)
|
||||||
r.setType(fn.Nname, sig)
|
r.setType(name, sig)
|
||||||
|
|
||||||
// TODO(mdempsky): De-duplicate with similar logic in funcargs.
|
// TODO(mdempsky): De-duplicate with similar logic in funcargs.
|
||||||
defParams := func(class ir.Class, params ...*types.Field) {
|
defParams := func(class ir.Class, params *types.Type) {
|
||||||
for _, param := range params {
|
for _, param := range params.FieldSlice() {
|
||||||
name := ir.NewNameAt(param.Pos, param.Sym)
|
name := ir.NewNameAt(param.Pos, param.Sym)
|
||||||
name.Class = class
|
name.Class = class
|
||||||
r.setType(name, param.Type)
|
r.setType(name, param.Type)
|
||||||
|
@ -2126,39 +2188,20 @@ func (r *reader) methodWrapper(derefs int, tbase *types.Type, method *types.Fiel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defParams(ir.PPARAM, sig.Recv())
|
defParams(ir.PPARAM, sig.Recvs())
|
||||||
defParams(ir.PPARAM, sig.Params().FieldSlice()...)
|
defParams(ir.PPARAM, sig.Params())
|
||||||
defParams(ir.PPARAMOUT, sig.Results().FieldSlice()...)
|
defParams(ir.PPARAMOUT, sig.Results())
|
||||||
|
|
||||||
var recv ir.Node = sig.Recv().Nname.(*ir.Name)
|
|
||||||
|
|
||||||
// For simple *T wrappers around T methods, panicwrap produces a
|
|
||||||
// nicer panic message.
|
|
||||||
if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
|
|
||||||
cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
|
|
||||||
then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
|
|
||||||
fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add implicit derefs, as necessary. typecheck will add one deref,
|
|
||||||
// but not-in-heap types will need another for their **T wrappers.
|
|
||||||
for i := 0; i < derefs; i++ {
|
|
||||||
recv = Implicit(ir.NewStarExpr(pos, recv))
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]ir.Node, sig.NumParams())
|
|
||||||
for i, param := range sig.Params().FieldSlice() {
|
|
||||||
args[i] = param.Nname.(*ir.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn.Body.Append(newTailCall(pos, method, recv, args))
|
|
||||||
|
|
||||||
target.Decls = append(target.Decls, fn)
|
target.Decls = append(target.Decls, fn)
|
||||||
|
|
||||||
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// newWrapperType returns a copy of the given signature type, but with
|
// newWrapperType returns a copy of the given signature type, but with
|
||||||
// the receiver parameter type substituted with wrapper.
|
// the receiver parameter type substituted with recvType.
|
||||||
func newWrapperType(wrapper, sig *types.Type) *types.Type {
|
// If recvType is nil, newWrapperType returns a signature
|
||||||
|
// without a receiver parameter.
|
||||||
|
func newWrapperType(recvType *types.Type, method *types.Field) *types.Type {
|
||||||
clone := func(params []*types.Field) []*types.Field {
|
clone := func(params []*types.Field) []*types.Field {
|
||||||
res := make([]*types.Field, len(params))
|
res := make([]*types.Field, len(params))
|
||||||
for i, param := range params {
|
for i, param := range params {
|
||||||
|
@ -2172,25 +2215,39 @@ func newWrapperType(wrapper, sig *types.Type) *types.Type {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
recv := types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), wrapper)
|
sig := method.Type
|
||||||
|
|
||||||
|
var recv *types.Field
|
||||||
|
if recvType != nil {
|
||||||
|
recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType)
|
||||||
|
}
|
||||||
params := clone(sig.Params().FieldSlice())
|
params := clone(sig.Params().FieldSlice())
|
||||||
results := clone(sig.Results().FieldSlice())
|
results := clone(sig.Results().FieldSlice())
|
||||||
|
|
||||||
return types.NewSignature(types.NoPkg, recv, nil, params, results)
|
return types.NewSignature(types.NoPkg, recv, nil, params, results)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTailCall(pos src.XPos, method *types.Field, recv ir.Node, args []ir.Node) ir.Node {
|
func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) {
|
||||||
|
sig := fn.Nname.Type()
|
||||||
|
args := make([]ir.Node, sig.NumParams())
|
||||||
|
for i, param := range sig.Params().FieldSlice() {
|
||||||
|
args[i] = param.Nname.(*ir.Name)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
|
// TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
|
||||||
// Not urgent though, because tail calls are currently incompatible with regabi anyway.
|
// Not urgent though, because tail calls are currently incompatible with regabi anyway.
|
||||||
|
|
||||||
|
fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
|
||||||
|
|
||||||
call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args)
|
call := ir.NewCallExpr(pos, ir.OCALL, ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym), args)
|
||||||
call.IsDDD = method.Type.IsVariadic()
|
call.IsDDD = method.Type.IsVariadic()
|
||||||
|
|
||||||
if method.Type.NumResults() == 0 {
|
if method.Type.NumResults() == 0 {
|
||||||
return call
|
fn.Body.Append(call)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := ir.NewReturnStmt(pos, nil)
|
ret := ir.NewReturnStmt(pos, nil)
|
||||||
ret.Results = []ir.Node{call}
|
ret.Results = []ir.Node{call}
|
||||||
return ret
|
fn.Body.Append(ret)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue