diff options
| author | Matthew Dempsky <mdempsky@google.com> | 2023-11-19 20:18:50 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2023-11-20 15:10:54 +0000 |
| commit | 0709f1bb00287371da61a1fc94f6e2a086aa0f29 (patch) | |
| tree | a5aae7e780581c81736664be47e36c0c421c6802 /src/cmd/compile/internal/devirtualize/devirtualize.go | |
| parent | 468bc941886ae83b8d16af5deaaf12ea5cabb05b (diff) | |
| download | go-0709f1bb00287371da61a1fc94f6e2a086aa0f29.tar.xz | |
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>
Diffstat (limited to 'src/cmd/compile/internal/devirtualize/devirtualize.go')
| -rw-r--r-- | src/cmd/compile/internal/devirtualize/devirtualize.go | 30 |
1 files changed, 15 insertions, 15 deletions
diff --git a/src/cmd/compile/internal/devirtualize/devirtualize.go b/src/cmd/compile/internal/devirtualize/devirtualize.go index 7b3a869d8e..b5e55c6d48 100644 --- a/src/cmd/compile/internal/devirtualize/devirtualize.go +++ b/src/cmd/compile/internal/devirtualize/devirtualize.go @@ -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 } |
