cmd/compile: avoid always escaping the receivers in interface method calls #62653
Labels
compiler/runtime
Issues related to the Go compiler and/or runtime.
NeedsFix
The path to resolution is known, but the work has not been done.
Milestone
Background
Currently, interface arguments to functions frequently escape due to subsequent use of the interface in an interface method call.
This affects many APIs, including things like marshalling/unmarshalling APIs, logging APIs, things like fmt.Sprintf, and many other flavors of APIs that take interfaces.
For example, in Go 1.21, the
val
here escapes and is heap allocated for this reason (and other for reasons as well):If we consider an extremely simplified implementation of Sprintf:
When
v.String
is called as an interface method in that example,v
might contain a type likeLeaking
:The current compiler knows this is possible, and as a result, the
input
interface argument to our simple Print function is conservatively marked as escaping. This is part of the reason the real fmt.Sprintf causesval
to be allocated above.Frequently, though,
v
contains a type likeNice
:Suggestion
The suggestion is for escape analysis to propagate what it knows about the use of interfaces in method calls to then prove (when it can) whether it is dealing with a type like Leaking or Nice to then avoid allocating the
n
inn := Nice{}; Print(n)
.In particular, escape analysis has had the concept of pseudo locations for things like the heap, and the escape analysis data-flow graph in the current compiler contains an edge leading to a heap pseudo location for each interface method call observed.
We could instead track the interface method use flows separately from other flows to the heap, including propagating across function call boundaries by tagging the associated function & method parameters. When a concrete value is later converted to an interface type (e.g.,
Print(n)
in our simple example above), we look at what we know about the type and its methods to see if we can prove that it is incapable of leaking if used as a method receiver in an interface method call.I sent CL 524945 with implementation of the idea, along with some related CLs like 524937 and 524944.
Those are a part of a larger stack targeting the fmt print functions. By the end of my stack (as of CL 528538), this no longer allocates the Point struct on the heap:
The primary CL 524945 is still WIP, but at least passes all.bash and the TryBots, including passing the more specific interface receiver tests I added. (It passes the older TryBots, but currently fails the new LUCI TryBots for LUCI-specific reasons). The first cut does not differentiate between a type that only has some methods with leaking receivers vs. the specific method in question, but CL 528539 is also a small refinement I had also been thinking about that attempts to address that. (That is not needed for many cases, and that CL is currently in much rougher shape & more exploratory).
In the initial discussion in Gerrit on CL 524945, Matthew Dempsky said he liked the idea. He also suggested opening an issue to help discussion, which is now this issue.
Matthew also later sent CL 526520 with an alternative implementation of the core idea.
CC @mdempsky, @ianlancetaylor
The text was updated successfully, but these errors were encountered: