mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/ir: add CallExpr.GoDefer
The devirtualizer and inliner both want to recognize call expressions that are part of a go or defer statement. This CL refactors them to use a single CallExpr.GoDefer flag, which gets set during normalization of go/defer statements during typecheck. While here, drop some OCALLMETH assertions. Typecheck has been responsible for desugaring them into OCALLFUNC for a while now, and ssagen will check this again for us later anyway. Change-Id: I3fc370f4417431aae97239313da6fe523f512a2e Reviewed-on: https://go-review.googlesource.com/c/go/+/543657 Reviewed-by: Than McIntosh <thanm@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
468bc94188
commit
0709f1bb00
4 changed files with 38 additions and 47 deletions
|
|
@ -23,24 +23,10 @@ import (
|
|||
func Static(fn *ir.Func) {
|
||||
ir.CurFunc = fn
|
||||
|
||||
// For promoted methods (including value-receiver methods promoted to pointer-receivers),
|
||||
// the interface method wrapper may contain expressions that can panic (e.g., ODEREF, ODOTPTR, ODOTINTER).
|
||||
// Devirtualization involves inlining these expressions (and possible panics) to the call site.
|
||||
// This normally isn't a problem, but for go/defer statements it can move the panic from when/where
|
||||
// the call executes to the go/defer statement itself, which is a visible change in semantics (e.g., #52072).
|
||||
// To prevent this, we skip devirtualizing calls within go/defer statements altogether.
|
||||
goDeferCall := make(map[*ir.CallExpr]bool)
|
||||
ir.VisitList(fn.Body, func(n ir.Node) {
|
||||
switch n := n.(type) {
|
||||
case *ir.GoDeferStmt:
|
||||
if call, ok := n.Call.(*ir.CallExpr); ok {
|
||||
goDeferCall[call] = true
|
||||
}
|
||||
return
|
||||
case *ir.CallExpr:
|
||||
if !goDeferCall[n] {
|
||||
staticCall(n)
|
||||
}
|
||||
staticCall(n)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -48,6 +34,20 @@ func Static(fn *ir.Func) {
|
|||
// staticCall devirtualizes the given call if possible when the concrete callee
|
||||
// is available statically.
|
||||
func staticCall(call *ir.CallExpr) {
|
||||
// For promoted methods (including value-receiver methods promoted
|
||||
// to pointer-receivers), the interface method wrapper may contain
|
||||
// expressions that can panic (e.g., ODEREF, ODOTPTR,
|
||||
// ODOTINTER). Devirtualization involves inlining these expressions
|
||||
// (and possible panics) to the call site. This normally isn't a
|
||||
// problem, but for go/defer statements it can move the panic from
|
||||
// when/where the call executes to the go/defer statement itself,
|
||||
// which is a visible change in semantics (e.g., #52072). To prevent
|
||||
// this, we skip devirtualizing calls within go/defer statements
|
||||
// altogether.
|
||||
if call.GoDefer {
|
||||
return
|
||||
}
|
||||
|
||||
if call.Op() != ir.OCALLINTER {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue