]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: initialize sparse slice literals dynamically
authorKeith Randall <khr@google.com>
Mon, 26 Nov 2018 22:33:32 +0000 (14:33 -0800)
committerKeith Randall <khr@golang.org>
Mon, 26 Nov 2018 22:50:48 +0000 (22:50 +0000)
When a slice composite literal is sparse, initialize it dynamically
instead of statically.

s := []int{5:5, 20:20}

To initialize the backing store for s, use 2 constant writes instead
of copying from a static array with 21 entries.

This CL also fixes pathologies in the compiler when the slice is
*very* sparse.

Fixes #23780

Change-Id: Iae95c6e6f6a0e2994675cbc750d7a4dd6436b13b
Reviewed-on: https://go-review.googlesource.com/c/151319
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/syntax.go
test/fixedbugs/issue23780.go [new file with mode: 0644]

index 28ea72b715a3c6bf2ace4c305ec6e15513a922d9..acd8550ee3608294f71a655e07c7bf79ed2f4f34 100644 (file)
@@ -612,6 +612,15 @@ func getdyn(n *Node, top bool) initGenType {
                if !top {
                        return initDynamic
                }
+               if n.Right.Int64()/4 > int64(n.List.Len()) {
+                       // <25% of entries have explicit values.
+                       // Very rough estimation, it takes 4 bytes of instructions
+                       // to initialize 1 byte of result. So don't use a static
+                       // initializer if the dynamic initialization code would be
+                       // smaller than the static value.
+                       // See issue 23780.
+                       return initDynamic
+               }
 
        case OARRAYLIT, OSTRUCTLIT:
        }
@@ -902,7 +911,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
                        continue
                }
 
-               if isLiteral(value) {
+               if vstat != nil && isLiteral(value) { // already set by copy from static value
                        continue
                }
 
index 0be52f12719e456f4580692e1e4193f2b089801b..c7becf53e56156204f3c9957b2f0bf993fb5861c 100644 (file)
@@ -622,7 +622,7 @@ const (
        OMAPLIT    // Type{List} (composite literal, Type is map)
        OSTRUCTLIT // Type{List} (composite literal, Type is struct)
        OARRAYLIT  // Type{List} (composite literal, Type is array)
-       OSLICELIT  // Type{List} (composite literal, Type is slice)
+       OSLICELIT  // Type{List} (composite literal, Type is slice) Right.Int64() = slice length.
        OPTRLIT    // &Left (left is composite literal)
        OCONV      // Type(Left) (type conversion)
        OCONVIFACE // Type(Left) (type conversion, to interface)
diff --git a/test/fixedbugs/issue23780.go b/test/fixedbugs/issue23780.go
new file mode 100644 (file)
index 0000000..71fc2d9
--- /dev/null
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2018 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.
+
+package p
+
+func f() {
+       _ = []byte{1 << 30: 1}
+}
+
+func g() {
+       sink = []byte{1 << 30: 1}
+}
+
+var sink []byte