Fix panics on In-place update optimization#1149
Conversation
This checks ahead of time if the array we want to update in-place is uniquely referenced and correctly falls back to the previous, unoptimized path that makes a copy. Fixes #1146
Benchmark for b702a95Click to view benchmark
|
Benchmark for a286bb7Click to view benchmark
|
|
I notice we do an ad-hoc in-place check to see if the array is used elsewhere, and then decide whether or not to make a copy. Do we have a formal/documented notion of the pass-by-value or pass-by-reference semantics of data structures in Q#? If we were to define such a thing, and use something like linear typing, we could automatically perform this optimization on all data types. |
All values are read-only in Q#, even on mutable variables. The expectation for mutable variables is that they are allowed to be updated to "point" to a new value, rather than the actual value being mutated. This is why array index updates are only possible with "copy-update" expressions which are expected to copy. But when looking for ways to improve performance, we made it so aggregate data types, Arrays and Tuples, are actually let x = [1, 2, 3];
let y = x;would still only have one copy of mutable arr = [1, 2, 3];
set arr += [4, 5, 6];Such that the append (or index update) can happen without creating an entire copy of the source array. The bug was that we always did it, running into a panic if there was another reference: mutable arr = [1, 2, 3];
let copy = arr;
set arr += [4, 5, 6]; // in-place update fails because the source is not uniquely ownedWith this change, we've effectively made it so that uniquely owned arrays can be updated in-place, otherwise we fall back to the old behavior of copy-on-write. |
This checks ahead of time if the array we want to update in-place is uniquely referenced and correctly falls back to the previous, unoptimized path that makes a copy.
Fixes #1146