1 // Regression: the store-back for an indexed push target addressed the slice
2 // variable instead of its element.
3 //
4 // push is an in-place mutation, so the SSA builder emits a store of the grown
5 // header back into the argument's storage - without it a statement-form
6 // push(x, v) silently drops the appended elements. For an INDEX target that
7 // store computed the address wrongly: it passed the address of the slice
8 // variable to IndexAddr, where the emitter expects the slice value (as
9 // buildOperandAddr does for an assignment lvalue), so the address came out as
10 // data + index*elemSize relative to the slice HEADER. `d[i] = push(d[i], v)`
11 // therefore wrote the element's header over the outer slice: the directory
12 // gained an entry and its element lengths scrambled on every call, and a
13 // slice-of-slices accumulator could not be built at all.
14 //
15 // The legacy compiler addressed the element correctly, so this was a stage4
16 // divergence. The fix passes the slice value, and this case pins the chunked
17 // accumulator shape that exposed it.
18 package main
19 20 import "fmt"
21 22 func main() {
23 // Grow a slice-of-slices one element at a time, in fixed-size chunks.
24 var d [][]byte
25 for i := 0; i < 6; i++ {
26 if len(d) == 0 || len(d[len(d)-1]) == 4 {
27 d = push(d, []byte{:0:4})
28 }
29 last := int32(len(d)) - 1
30 d[last] = push(d[last], byte('a'+i))
31 }
32 if len(d) != 2 {
33 panic("wrong chunk count: the push store-back clobbered the directory")
34 }
35 if len(d[0]) != 4 || len(d[1]) != 2 {
36 panic("wrong chunk lengths")
37 }
38 if string(d[0]) != "abcd" || string(d[1]) != "ef" {
39 panic("wrong chunk contents")
40 }
41 42 // The same shape one level deeper: a field holding a slice-of-slices,
43 // grown from a method on the outer type.
44 var h holder
45 h.add("aa")
46 h.add("bbb")
47 if len(h.rows) != 2 {
48 panic("wrong row count")
49 }
50 if string(h.rows[0]) != "aa" || string(h.rows[1]) != "bbb" {
51 panic("wrong row contents")
52 }
53 54 fmt.Println("ok")
55 }
56 57 type holder struct {
58 rows [][]byte
59 }
60 61 func (h *holder) add(s string) {
62 h.rows = push(h.rows, []byte{:0:4})
63 last := int32(len(h.rows)) - 1
64 h.rows[last] = push(h.rows[last], []byte(s)...)
65 }
66