aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/devirtualize
diff options
context:
space:
mode:
authorThan McIntosh <thanm@google.com>2024-06-06 12:51:57 +0000
committerThan McIntosh <thanm@google.com>2024-06-12 20:40:04 +0000
commitca5ba146da7a9d4e2a8cbe1715a78be42b45a745 (patch)
tree3281def467f6a365d2e8e2f1ee47ac46e883ad09 /src/cmd/compile/internal/devirtualize
parent97bc577812592c2bc40bd1f2bc0d78c5d8281ff6 (diff)
downloadgo-ca5ba146da7a9d4e2a8cbe1715a78be42b45a745.tar.xz
cmd/compile/internal: add a PGO devirt post-lookup cleanup hook
The PGO-based devirtualization helper pgoir.addIndirectEdges makes a series of calls into the unified IR reader to import functions that would not normally be imported but may be the target of a hot indirect call from the current package. This importing primarily targets at non-generic functions and methods, but as part of the process we can encounter types that have methods (including generic methods) whose bodies need to be read in. When the reader encounters an inlinable func of this sort, it may (depending on the context) decide not to read the body right away, but instead adds the func to a list ("todoBodies") to be read in later on in a more convenient context. In the bug in question, a hot method lookup takes place in pgoir.addIndirectEdges, and as part of the import process we wind up with a type T with method M that is in this partially created state, and in addition T gets added to the unified IR's list of types that may need method wrappers. During wrapper generation we create a new wrapper "(*T).M" whose body has a call to "T.M", then farther on down the pike during escape analysis we try to analyze the two functions; this causes a crash due to "T.M" being in partially constructed state. As a fix, add a new "PostLookupCleanup" hook (in the unified IR reader) that pgoir.addIndirectEdges can invoke that takes care of reading in the bodies of any functions that have been added to the "todoBodies" list. [Note: creating a test case for this problem is proving to be very tricky; a new test will be added in a subsequent patch]. Fixes #67746. Change-Id: Ibc47ee79e08a55421728d35341df80a865231cff Reviewed-on: https://go-review.googlesource.com/c/go/+/591075 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/cmd/compile/internal/devirtualize')
-rw-r--r--src/cmd/compile/internal/devirtualize/pgo.go10
1 files changed, 9 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/devirtualize/pgo.go b/src/cmd/compile/internal/devirtualize/pgo.go
index 0a43135420..783940cbc2 100644
--- a/src/cmd/compile/internal/devirtualize/pgo.go
+++ b/src/cmd/compile/internal/devirtualize/pgo.go
@@ -364,11 +364,15 @@ func constructCallStat(p *pgoir.Profile, fn *ir.Func, name string, call *ir.Call
return e.Dst.Name() < stat.Hottest
}
+ callerNode := p.WeightedCG.IRNodes[name]
+ if callerNode == nil {
+ return nil
+ }
+
// Sum of all edges from this callsite, regardless of callee.
// For direct calls, this should be the same as the single edge
// weight (except for multiple calls on one line, which we
// can't distinguish).
- callerNode := p.WeightedCG.IRNodes[name]
for _, edge := range callerNode.OutEdges {
if edge.CallSiteOffset != offset {
continue
@@ -656,6 +660,10 @@ func findHotConcreteCallee(p *pgoir.Profile, caller *ir.Func, call *ir.CallExpr,
callerNode := p.WeightedCG.IRNodes[callerName]
callOffset := pgoir.NodeLineOffset(call, caller)
+ if callerNode == nil {
+ return nil, 0
+ }
+
var hottest *pgoir.IREdge
// Returns true if e is hotter than hottest.