mirror of
https://github.com/golang/go
synced 2024-11-23 00:30:07 -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:
parent
493e177639
commit
e59a19cceb
@ -7,7 +7,6 @@ package walk
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/typecheck"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
|
||||
var init ir.Nodes
|
||||
switch call := n.Call; call.Op() {
|
||||
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 !validGoDeferCall(n.Call) {
|
||||
base.FatalfAt(n.Pos(), "invalid %v call: %v", n.Op(), n.Call)
|
||||
}
|
||||
|
||||
var init ir.Nodes
|
||||
n.Call = walkExpr(n.Call, &init)
|
||||
|
||||
if len(init) > 0 {
|
||||
init.Append(n)
|
||||
return ir.NewBlockStmt(n.Pos(), init)
|
||||
@ -229,94 +221,6 @@ func walkIf(n *ir.IfStmt) ir.Node {
|
||||
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
|
||||
//
|
||||
// f(a, b, []T{c, d, e}...)
|
||||
|
Loading…
Reference in New Issue
Block a user