We currently implement read and write barriers in the opt compiler by inserting LIR code during expansion of runtime services. We insert different barriers for array read/writes, static read/writes and instance fields read/writes. The barrier is a call into MM_Interface that then calls a service provided by MMTk. We inline the code on frequently executed paths.
For certain situations having 2 barrier calls is unnecessary, and can be removed by compiler analysis. For example, consider the following two writes to a reference field:
o.x = xxx
...
o.x = yyy
if ... doesn't contain a yieldpoint and the write barrier is just remembering/marking that o.x was written to, then the second write barrier is unnecessary.
In general whether a barrier is necessary or not depends on the GC implementation. We could construct HIR for the example above like:
g1 = field_write_barrier(o.x, xxx);
o.x = xxx, g1
...
g2 = field_write_barrier(o.x, yyy);
o.x = yyy, g2
which we'd expand as we currently do, but alternatively we could analyze the IR and find the second operator can be changed to a write after write field write barrier:
g1 = field_write_barrier(o.x, xxx);
o.x = xxx, g1
...
g2 = field_write_after_write_barrier(o.x, yyy);
o.x = yyy, g2
that is the write_after_write_barrier is guaranteeing that o.x will already have been seen by a write barrier prior to the second write. For some write barrier implementations this could be implemented as no operation.
Another prospect for interesting barrier operators are for objects that are known not yet to have escaped as there reference is only held locally.
Obviously this is a significant change and requires a certain amount of discussion. The exact semantics of the HIR isn't yet clear, do we want an operator or an operand to current HIR operators? The number of different useful operators also isn't yet clear.