push_index_nested_slice.mx raw

   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