void writer(Tuple tuple) {
tuple.nonVolatileF = 5;
tuple.volatileF = 1;
}
void reader(Tuple tuple) {
int regNV = 0;
int cache = tuple.nonVolatileF;
int regV = tuple.volatileF;
if (regV == 1) { regNV = cache; }
// computation that uses both of the above
}
because `cache` might get assigned before `tuple.nonVolatileF` is set. (The same is true of regV, but I guess the untransformed program had that, so you don't bother). But you said that the JMM guarantees that all reads in C_i - C_(i-1) will see writes in C_(i-1); this means that C_3 which reads `tuple.nonVolatileF` will see the write to that variable in C_2, no? Since you're constructing an execution, why didn't you interleave the execution to make this trivially true? Also, can't you wrap the writer in an atomic block during transformation?
This is a wrong transformation:
because `cache` might get assigned before `tuple.nonVolatileF` is set. (The same is true of regV, but I guess the untransformed program had that, so you don't bother). But you said that the JMM guarantees that all reads in C_i - C_(i-1) will see writes in C_(i-1); this means that C_3 which reads `tuple.nonVolatileF` will see the write to that variable in C_2, no? Since you're constructing an execution, why didn't you interleave the execution to make this trivially true? Also, can't you wrap the writer in an atomic block during transformation?