summaryrefslogtreecommitdiff
path: root/test/escape2.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-01-16 23:30:35 +0300
committerDmitry Vyukov <dvyukov@google.com>2015-01-28 17:37:55 +0000
commit22c16b4b92f10baf42a3db5de439a70f49101a89 (patch)
tree9f9c12c64cf66b6fb5a9f6a74bed7da1508e1912 /test/escape2.go
parent1b87f01239de499654b390a41a7f8e2b453789dc (diff)
downloadgo-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.go37
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"
+}