aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/devirtualize
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2023-06-05 22:28:48 -0400
committerCherry Mui <cherryyz@google.com>2023-06-06 14:45:44 +0000
commitfd03e6ebc91fb0b6f4dc721a323dc0b408e3b30b (patch)
tree30c30fab2375d53c0865f5474fe873ad451f7ad1 /src/cmd/compile/internal/devirtualize
parentdb3f952b1f3c996085cb9bfe846590084f8fae2e (diff)
downloadgo-fd03e6ebc91fb0b6f4dc721a323dc0b408e3b30b.tar.xz
cmd/compile: check method name in PGO devirtualization
Currently, we devirtualize an interface call if the profile indicates a concrete callee is hot on the same line, and the concrete receiver implements the interface. But it is possible that (likely due to another call on the same line, or possibly a stale profile) the concrete call is to a different method. With the current AST construction we generate correct code, as we extract the method name from the interface call and use that to create the concrete call. But the devirtualization decision is based on an unrelated call in the profile. Check the method name when finding the hottest callee, so we won't use unrelated calls to different methods. Change-Id: I75c026997926f21bd6cc5266d3ffe99649a9b2d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/500961 Run-TryBot: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/cmd/compile/internal/devirtualize')
-rw-r--r--src/cmd/compile/internal/devirtualize/pgo.go20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/cmd/compile/internal/devirtualize/pgo.go b/src/cmd/compile/internal/devirtualize/pgo.go
index a340248543..068e0ef8f2 100644
--- a/src/cmd/compile/internal/devirtualize/pgo.go
+++ b/src/cmd/compile/internal/devirtualize/pgo.go
@@ -15,6 +15,7 @@ import (
"encoding/json"
"fmt"
"os"
+ "strings"
)
// CallStat summarizes a single call site.
@@ -396,9 +397,9 @@ func methodRecvType(fn *ir.Func) *types.Type {
return recv.Type
}
-// interfaceCallRecvType returns the type of the interface used in an interface
-// call.
-func interfaceCallRecvType(call *ir.CallExpr) *types.Type {
+// interfaceCallRecvTypeAndMethod returns the type and the method of the interface
+// used in an interface call.
+func interfaceCallRecvTypeAndMethod(call *ir.CallExpr) (*types.Type, *types.Sym) {
if call.Op() != ir.OCALLINTER {
base.Fatalf("Call isn't OCALLINTER: %+v", call)
}
@@ -408,7 +409,7 @@ func interfaceCallRecvType(call *ir.CallExpr) *types.Type {
base.Fatalf("OCALLINTER doesn't contain SelectorExpr: %+v", call)
}
- return sel.X.Type()
+ return sel.X.Type(), sel.Sel
}
// findHotConcreteCallee returns the *ir.Func of the hottest callee of an
@@ -418,7 +419,7 @@ func findHotConcreteCallee(p *pgo.Profile, caller *ir.Func, call *ir.CallExpr) (
callerNode := p.WeightedCG.IRNodes[callerName]
callOffset := pgo.NodeLineOffset(call, caller)
- inter := interfaceCallRecvType(call)
+ inter, method := interfaceCallRecvTypeAndMethod(call)
var hottest *pgo.IREdge
@@ -512,6 +513,15 @@ func findHotConcreteCallee(p *pgo.Profile, caller *ir.Func, call *ir.CallExpr) (
continue
}
+ // If the method name is different it is most likely from a
+ // different call on the same line
+ if !strings.HasSuffix(e.Dst.Name(), "."+method.Name) {
+ if base.Debug.PGODebug >= 2 {
+ fmt.Printf("%v: edge %s:%d -> %s (weight %d): callee is a different method\n", ir.Line(call), callerName, callOffset, e.Dst.Name(), e.Weight)
+ }
+ continue
+ }
+
if base.Debug.PGODebug >= 2 {
fmt.Printf("%v: edge %s:%d -> %s (weight %d): hottest so far\n", ir.Line(call), callerName, callOffset, e.Dst.Name(), e.Weight)
}