aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/devirtualize/devirtualize.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2023-11-19 20:18:50 -0800
committerGopher Robot <gobot@golang.org>2023-11-20 15:10:54 +0000
commit0709f1bb00287371da61a1fc94f6e2a086aa0f29 (patch)
treea5aae7e780581c81736664be47e36c0c421c6802 /src/cmd/compile/internal/devirtualize/devirtualize.go
parent468bc941886ae83b8d16af5deaaf12ea5cabb05b (diff)
downloadgo-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.go30
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
}