Open quasilyte opened 6 years ago
Change https://golang.org/cl/136496 mentions this issue: cmd/compile/internal/gc: generalize self-assignment
/cc @randall77 @dr2chase
I'm slightly worried about the case where x is a slice or its elements are slices in
base(x[i][j]) // => x[i]
I think slice dereference counts as an indirection, where array dereference does not.
Search for IsArray
in esc.go, I think you will see the distinction made.
Safest route forward might be to put on all cases of indexing, see what you get with just dots, then add array (not slice!) to the base test in a separate CL in case there are subtle bugs.
ODOT is different, because I think there we rewrite to ODOTPTR when there is an explicit dereference.
Change https://golang.org/cl/172421 mentions this issue: test: add regress test cases for self-assignment
Right now, there are at least 2 quite adhoc patterns that are recognized by escape analysis as safe. It skips detailed analysis when it sees self-assignment statement that does not introduce new pointers that need tracking.
Initially, only some simple self-slicing assignments like this were handled:
Later, some more patterns were added, so these are recognized, too:
The problem with them is that they are very fragile and can't match expressions that are different from the simplest cases, but still represents self-assignments:
It is possible to generalize all self-assignment patterns with a concept of "base object". What we see above is a matching of object field assignment to the object itself. The base object is that object, the one that contains referenced field.
For the simplest cases, base object is just 1 syntactical level "above":
For cases where expression effectively returns the same object, we can skip several levels:
Given
base
function, we can express self-assignment as (pseudo Go):This covers all patterns above, plus a few more. As a bonus, it also solves trivial
*p = *p
case (see https://github.com/golang/go/issues/5919):More interesting examples of self-assignments that were not recognized until generalization:
This solution (if it is correct or can be made correct):
Collect new escape analysis results info:
And now with unpatched
go tool compile
:Now it is possible to do some comparisons.
New non-escaping values/parameters:
Since
ring.Ring.Len
receiver no longer escapes, we can try to verify and measure it with benchmarks:Old is unpatched escape analysis with leaking
r
. New is non-leakingr
:Here is
ring.Ring.Len
method implementation, for the reference:https://golang.org/src/container/ring/ring.go?s=2869:2893#L111
For additional examples, see proposed test suite extension: