diff options
author | Dmitry Vyukov <dvyukov@google.com> | 2015-01-16 23:30:35 +0300 |
---|---|---|
committer | Dmitry Vyukov <dvyukov@google.com> | 2015-01-28 17:37:55 +0000 |
commit | 22c16b4b92f10baf42a3db5de439a70f49101a89 (patch) | |
tree | 9f9c12c64cf66b6fb5a9f6a74bed7da1508e1912 /test/escape2.go | |
parent | 1b87f01239de499654b390a41a7f8e2b453789dc (diff) | |
download | go-git-22c16b4b92f10baf42a3db5de439a70f49101a89.tar.gz |
cmd/gc: ignore re-slicing in escape analysis
Escape analysis treats everything assigned to OIND/ODOTPTR as escaping.
As the result b escapes in the following code:
func (b *Buffer) Foo() {
n, m := ...
b.buf = b.buf[n:m]
}
This change recognizes such assignments and ignores them.
Update issue #9043.
Update issue #7921.
There are two similar cases in std lib that benefit from this optimization.
First is in archive/zip:
type readBuf []byte
func (b *readBuf) uint32() uint32 {
v := binary.LittleEndian.Uint32(*b)
*b = (*b)[4:]
return v
}
Second is in time:
type data struct {
p []byte
error bool
}
func (d *data) read(n int) []byte {
if len(d.p) < n {
d.p = nil
d.error = true
return nil
}
p := d.p[0:n]
d.p = d.p[n:]
return p
}
benchmark old ns/op new ns/op delta
BenchmarkCompressedZipGarbage 32431724 32217851 -0.66%
benchmark old allocs new allocs delta
BenchmarkCompressedZipGarbage 153 143 -6.54%
Change-Id: Ia6cd32744e02e36d6d8c19f402f8451101711626
Reviewed-on: https://go-review.googlesource.com/3162
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'test/escape2.go')
-rw-r--r-- | test/escape2.go | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/test/escape2.go b/test/escape2.go index 357ce4a8a8..507a815044 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1519,3 +1519,40 @@ func ptrlitEscape() { x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap" sink = x } + +// self-assignments + +type Buffer struct { + arr [64]byte + buf1 []byte + buf2 []byte + str1 string + str2 string +} + +func (b *Buffer) foo() { // ERROR "b does not escape" + b.buf1 = b.buf1[1:2] // ERROR "ignoring self-assignment to b.buf1" + b.buf1 = b.buf1[1:2:3] // ERROR "ignoring self-assignment to b.buf1" + b.buf1 = b.buf2[1:2] // ERROR "ignoring self-assignment to b.buf1" + b.buf1 = b.buf2[1:2:3] // ERROR "ignoring self-assignment to b.buf1" +} + +func (b *Buffer) bar() { // ERROR "leaking param: b" + b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap" +} + +func (b *Buffer) baz() { // ERROR "b does not escape" + b.str1 = b.str1[1:2] // ERROR "ignoring self-assignment to b.str1" + b.str1 = b.str2[1:2] // ERROR "ignoring self-assignment to b.str1" +} + +func (b *Buffer) bat() { // ERROR "leaking param: b" + o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap" + o.buf1 = b.buf1[1:2] + sink = o +} + +func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape" + *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp" + *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp" +} |