]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: avoid assignment conversion in append(a, b...)
authorKeith Randall <khr@golang.org>
Mon, 18 Jul 2022 18:47:19 +0000 (11:47 -0700)
committerKeith Randall <khr@google.com>
Mon, 8 Aug 2022 16:58:57 +0000 (16:58 +0000)
There's no need for a and b to match types. The typechecker already
ensured that a and b are both slices with the same base type, or
a and b are (possibly named) []byte and string.

The optimization to treat append(b, make([], ...)) as a zeroing
slice extension doesn't fire when there's a OCONVNOP wrapping the make.
Fixes #53888

Change-Id: Ied871ed0bbb8e4a4b35d280c71acbab8103691bc
Reviewed-on: https://go-review.googlesource.com/c/go/+/418475
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Keith Randall <khr@golang.org>

src/cmd/compile/internal/noder/transform.go
src/cmd/compile/internal/test/issue53888_test.go [new file with mode: 0644]
src/cmd/compile/internal/typecheck/func.go
src/runtime/slice.go
test/fixedbugs/issue29190.go

index ddbccf4ff48e80959ba90d997280a64e770ec163..50254e694a4e325227d41ced51c7c6455f42f464 100644 (file)
@@ -730,11 +730,11 @@ func transformAppend(n *ir.CallExpr) ir.Node {
        assert(t.IsSlice())
 
        if n.IsDDD {
-               if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
-                       return n
-               }
-
-               args[1] = assignconvfn(args[1], t.Underlying())
+               // assignconvfn is of args[1] not required here, as the
+               // types of args[0] and args[1] don't need to match
+               // (They will both have an underlying type which are
+               // slices of indentical base types, or be []byte and string.)
+               // See issue 53888.
                return n
        }
 
diff --git a/src/cmd/compile/internal/test/issue53888_test.go b/src/cmd/compile/internal/test/issue53888_test.go
new file mode 100644 (file)
index 0000000..9f50a82
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !race
+
+package test
+
+import (
+       "testing"
+)
+
+func TestAppendOfMake(t *testing.T) {
+       for n := 32; n < 33; n++ { // avoid stack allocation of make()
+               b := make([]byte, n)
+               f := func() {
+                       b = append(b[:0], make([]byte, n)...)
+               }
+               if n := testing.AllocsPerRun(10, f); n > 0 {
+                       t.Errorf("got %f allocs, want 0", n)
+               }
+               type S []byte
+
+               s := make(S, n)
+               g := func() {
+                       s = append(s[:0], make(S, n)...)
+               }
+               if n := testing.AllocsPerRun(10, g); n > 0 {
+                       t.Errorf("got %f allocs, want 0", n)
+               }
+               h := func() {
+                       s = append(s[:0], make([]byte, n)...)
+               }
+               if n := testing.AllocsPerRun(10, h); n > 0 {
+                       t.Errorf("got %f allocs, want 0", n)
+               }
+               i := func() {
+                       b = append(b[:0], make(S, n)...)
+               }
+               if n := testing.AllocsPerRun(10, i); n > 0 {
+                       t.Errorf("got %f allocs, want 0", n)
+               }
+       }
+}
index 0988ce8dc7f360f50ece87ff5fe3de64ece89a0a..7790e65ca22affd126452160a18df5c7fde3e05f 100644 (file)
@@ -465,7 +465,11 @@ func tcAppend(n *ir.CallExpr) ir.Node {
                        return n
                }
 
-               args[1] = AssignConv(args[1], t.Underlying(), "append")
+               // AssignConv is of args[1] not required here, as the
+               // types of args[0] and args[1] don't need to match
+               // (They will both have an underlying type which are
+               // slices of indentical base types, or be []byte and string.)
+               // See issue 53888.
                return n
        }
 
index 9ca0adefd8d621939da1d781bdd8d0aa332a6b7b..75f202fca00f0cb79c2d4d447c6213e3b2df13b0 100644 (file)
@@ -194,7 +194,7 @@ func growslice(et *_type, old slice, cap int) slice {
        }
 
        if cap < old.cap {
-               panic(errorString("growslice: cap out of range"))
+               panic(errorString("growslice: len out of range"))
        }
 
        if et.size == 0 {
@@ -284,7 +284,7 @@ func growslice(et *_type, old slice, cap int) slice {
        //   print(len(s), "\n")
        // }
        if overflow || capmem > maxAlloc {
-               panic(errorString("growslice: cap out of range"))
+               panic(errorString("growslice: len out of range"))
        }
 
        var p unsafe.Pointer
index c0c4bb12b4df03ba862c4884b33e664a593a616a..9f9b864eabaeb98e793d2f9f9b6cb85d29fbb0b7 100644 (file)
@@ -16,9 +16,9 @@ const maxInt = int(^uint(0) >> 1)
 
 func main() {
        s := make([]T, maxInt)
-       shouldPanic("cap out of range", func() { s = append(s, T{}) })
+       shouldPanic("len out of range", func() { s = append(s, T{}) })
        var oneElem = make([]T, 1)
-       shouldPanic("cap out of range", func() { s = append(s, oneElem...) })
+       shouldPanic("len out of range", func() { s = append(s, oneElem...) })
 }
 
 func shouldPanic(str string, f func()) {