1
0
mirror of https://github.com/golang/go synced 2024-11-23 03:40:02 -07:00

[dev.typeparams] cmd/compile: simplify walkGoDefer

order already takes care of wrapping all go/defer function calls, so
there's no need for walk to duplicate that logic: it's never going to
be used.

Change-Id: I54e545404e52ab8f9d60151d1bd2aff4b9bd8b72
Reviewed-on: https://go-review.googlesource.com/c/go/+/330270
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2021-06-22 20:33:00 -07:00
parent 493e177639
commit e59a19cceb

View File

@ -7,7 +7,6 @@ package walk
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
) )
// The result of walkStmt MUST be assigned back to n, e.g. // The result of walkStmt MUST be assigned back to n, e.g.
@ -187,33 +186,26 @@ func walkFor(n *ir.ForStmt) ir.Node {
return n return n
} }
// validGoDeferCall reports whether call is a valid call to appear in
// a go or defer statement; that is, whether it's a regular function
// call without arguments or results.
func validGoDeferCall(call ir.Node) bool {
if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC && len(call.KeepAlive) == 0 {
sig := call.X.Type()
return sig.NumParams()+sig.NumResults() == 0
}
return false
}
// walkGoDefer walks an OGO or ODEFER node. // walkGoDefer walks an OGO or ODEFER node.
func walkGoDefer(n *ir.GoDeferStmt) ir.Node { func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
if !validGoDeferCall(n.Call) {
base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call)
}
var init ir.Nodes var init ir.Nodes
switch call := n.Call; call.Op() { n.Call = walkExpr(n.Call, &init)
case ir.OPRINT, ir.OPRINTN:
call := call.(*ir.CallExpr)
n.Call = wrapCall(call, &init)
case ir.ODELETE:
call := call.(*ir.CallExpr)
n.Call = wrapCall(call, &init)
case ir.OCOPY:
call := call.(*ir.BinaryExpr)
n.Call = walkCopy(call, &init, true)
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
call := call.(*ir.CallExpr)
if len(call.KeepAlive) > 0 {
n.Call = wrapCall(call, &init)
} else {
n.Call = walkExpr(call, &init)
}
default:
n.Call = walkExpr(call, &init)
}
if len(init) > 0 { if len(init) > 0 {
init.Append(n) init.Append(n)
return ir.NewBlockStmt(n.Pos(), init) return ir.NewBlockStmt(n.Pos(), init)
@ -229,94 +221,6 @@ func walkIf(n *ir.IfStmt) ir.Node {
return n return n
} }
// Rewrite
// go builtin(x, y, z)
// into
// go func(a1, a2, a3) {
// builtin(a1, a2, a3)
// }(x, y, z)
// for print, println, and delete.
//
// Rewrite
// go f(x, y, uintptr(unsafe.Pointer(z)))
// into
// go func(a1, a2, a3) {
// f(a1, a2, uintptr(a3))
// }(x, y, unsafe.Pointer(z))
// for function contains unsafe-uintptr arguments.
var wrapCall_prgen int
// The result of wrapCall MUST be assigned back to n, e.g.
// n.Left = wrapCall(n.Left, init)
func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
if len(n.Init()) != 0 {
walkStmtList(n.Init())
init.Append(ir.TakeInit(n)...)
}
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
if !isBuiltinCall && n.IsDDD {
undoVariadic(n)
}
wrapArgs := n.Args
// If there's a receiver argument, it needs to be passed through the wrapper too.
if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
recv := n.X.(*ir.SelectorExpr).X
wrapArgs = append([]ir.Node{recv}, wrapArgs...)
}
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
origArgs := make([]ir.Node, len(wrapArgs))
var funcArgs []*ir.Field
for i, arg := range wrapArgs {
s := typecheck.LookupNum("a", i)
if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
origArgs[i] = arg
arg = arg.(*ir.ConvExpr).X
wrapArgs[i] = arg
}
funcArgs = append(funcArgs, ir.NewField(base.Pos, s, nil, arg.Type()))
}
t := ir.NewFuncType(base.Pos, nil, funcArgs, nil)
wrapCall_prgen++
sym := typecheck.LookupNum("wrap·", wrapCall_prgen)
fn := typecheck.DeclFunc(sym, t)
args := ir.ParamNames(t.Type())
for i, origArg := range origArgs {
if origArg == nil {
continue
}
args[i] = ir.NewConvExpr(base.Pos, origArg.Op(), origArg.Type(), args[i])
}
if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
// Move wrapped receiver argument back to its appropriate place.
recv := typecheck.Expr(args[0])
n.X.(*ir.SelectorExpr).X = recv
args = args[1:]
}
call := ir.NewCallExpr(base.Pos, n.Op(), n.X, args)
if !isBuiltinCall {
call.SetOp(ir.OCALL)
call.IsDDD = n.IsDDD
}
fn.Body = []ir.Node{call}
typecheck.FinishFuncBody()
typecheck.Func(fn)
typecheck.Stmts(fn.Body)
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, wrapArgs)
return walkExpr(typecheck.Stmt(call), init)
}
// undoVariadic turns a call to a variadic function of the form // undoVariadic turns a call to a variadic function of the form
// //
// f(a, b, []T{c, d, e}...) // f(a, b, []T{c, d, e}...)