]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: reorder how slicelit initializes a slice
authorKeith Randall <khr@golang.org>
Sun, 24 Apr 2016 05:59:01 +0000 (22:59 -0700)
committerKeith Randall <khr@golang.org>
Sun, 24 Apr 2016 18:15:41 +0000 (18:15 +0000)
  func f(x, y, z *int) {
    a := []*int{x,y,z}
    ...
  }

We used to use:
  var tmp [3]*int
  a := tmp[:]
  a[0] = x
  a[1] = y
  a[2] = z

Now we do:
  var tmp [3]*int
  tmp[0] = x
  tmp[1] = y
  tmp[2] = z
  a := tmp[:]

Doesn't sound like a big deal, but the compiler has trouble
eliminating write barriers when using the former method because it
doesn't know that the slice points to the stack.  In the latter
method, the compiler knows the array is on the stack and as a result
doesn't emit any write barriers.

This turns out to be extremely common when building ... args, like
for calls fmt.Printf.

Makes go binaries ~1% smaller.

Doesn't have a measurable effect on the go1 fmt benchmarks,
unfortunately.

Fixes #14263
Update #6853

Change-Id: I9074a2788ec9e561a75f3b71c119b69f304d6ba2
Reviewed-on: https://go-review.googlesource.com/22395
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/walk.go
test/writebarrier.go

index 2c2ade06f5dcc547e34956688dc3d7beaee61f4a..cc1d1962d2143cb21328b36b1b871df471e7c81b 100644 (file)
@@ -745,15 +745,15 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
        //      var vauto *[...]t = new([...]t)
        // 4. copy the static array to the auto array
        //      *vauto = vstat
-       // 5. assign slice of allocated heap to var
-       //      var = [0:]*auto
-       // 6. for each dynamic part assign to the slice
-       //      var[i] = dynamic part
+       // 5. for each dynamic part assign to the array
+       //      vauto[i] = dynamic part
+       // 6. assign slice of allocated heap to var
+       //      var = vauto[:]
        //
        // an optimization is done if there is no constant part
        //      3. var vauto *[...]t = new([...]t)
-       //      5. var = [0:]*auto
-       //      6. var[i] = dynamic part
+       //      5. vauto[i] = dynamic part
+       //      6. var = vauto[:]
 
        // if the literal contains constants,
        // make static initialized array (1),(2)
@@ -811,21 +811,14 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
                init.Append(a)
        }
 
-       // make slice out of heap (5)
-       a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
-
-       a = typecheck(a, Etop)
-       a = orderstmtinplace(a)
-       a = walkstmt(a)
-       init.Append(a)
-       // put dynamics into slice (6)
+       // put dynamics into array (5)
        for _, r := range n.List.Slice() {
                if r.Op != OKEY {
                        Fatalf("slicelit: rhs not OKEY: %v", r)
                }
                index := r.Left
                value := r.Right
-               a := Nod(OINDEX, var_, index)
+               a := Nod(OINDEX, vauto, index)
                a.Bounded = true
 
                // TODO need to check bounds?
@@ -847,7 +840,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
                        continue
                }
 
-               // build list of var[c] = expr
+               // build list of vauto[c] = expr
                setlineno(value)
                a = Nod(OAS, a, value)
 
@@ -856,6 +849,14 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
                a = walkstmt(a)
                init.Append(a)
        }
+
+       // make slice out of heap (6)
+       a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
+
+       a = typecheck(a, Etop)
+       a = orderstmtinplace(a)
+       a = walkstmt(a)
+       init.Append(a)
 }
 
 func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
index 27ff045028a12a72560ec6ad01e166653d0e623c..7c4d74c8c3e42a3590747ecce83c4d6f4890dcb9 100644 (file)
@@ -2748,8 +2748,7 @@ func addstr(n *Node, init *Nodes) *Node {
                        prealloc[slice] = prealloc[n]
                }
                slice.List.Set(args[1:]) // skip buf arg
-               args = []*Node{buf}
-               args = append(args, slice)
+               args = []*Node{buf, slice}
                slice.Esc = EscNone
        }
 
index 44e42f0883d93d00e672a2f7a5778bd32dc20e88..2ff0ee95847f0902cea22a79460f2657e7b298a8 100644 (file)
@@ -182,3 +182,17 @@ func f18(p *T18, x *[]int) {
        p.s = p.s[8:9]   // ERROR "write barrier"
        *x = (*x)[3:5]   // ERROR "write barrier"
 }
+
+func f19(x, y *int, i int) int {
+       // Constructing a temporary slice on the stack should not
+       // require any write barriers. See issue 14263.
+       a := []*int{x, y} // no barrier
+       return *a[i]
+}
+
+func f20(x, y *int, i int) []*int {
+       // ... but if that temporary slice escapes, then the
+       // write barriers are necessary.
+       a := []*int{x, y} // ERROR "write barrier"
+       return a
+}