Inline classes and the memory model
Mateusz Romanowski
romanowski.mateusz at gmail.com
Thu Mar 5 17:29:24 UTC 2020
Hi Florian,
I believe you might need to use @NonTearable annotation to force inline
fields not to tear like long and double ones.
The situation is orthogonal to constructor's safe publication, I think.
https://mail.openjdk.java.net/pipermail/valhalla-dev/2020-February/006827.html
Cheers,
Mateusz
On Thursday, March 5, 2020, Florian Weimer <fw at deneb.enyo.de> wrote:
> Sorry if this has been brought up before. Consisder this example,
> which is intended to simmulate a buffer-like class that has a pointer
> to a backing array, a capacity, and a size (where the size must be no
> greater than the capacity etc.):
>
> import java.util.Random;
>
> public class Consistency {
> public static void main(String[] args) {
> Holder holder = new Holder();
>
> new Thread() {
> public void run() {
> while (true) {
> Slice slice = holder.slice;
> if (!slice.consistent())
> System.out.println(slice);
> ++holder.counter;
> }
> }
> }.start();
>
> while (true) {
> holder.update();
> }
> }
>
> static inline class Slice {
> final long ptr;
> final int capacity;
> final int size;
>
> Slice(Random random) {
> capacity = random.nextInt(1 << 20);
> size = random.nextInt(capacity + 1);
> // Use the pointer to encode both the capacity and size.
> ptr = capacity * ((1L << 20) + 1) + size;
> }
>
> boolean consistent() {
> return ptr == capacity * ((1L << 20) + 1) + size
> && size <= capacity;
> }
>
> public String toString() {
> return String.format("ptr=0x%x capacity=%d size=%d",
> ptr, capacity, size);
> }
> }
>
> static class Holder {
> final Random random = new Random(1);
> Slice slice = new Slice(random);
> volatile int counter;
>
> void update() {
> slice = new Slice(random);
> ++counter;
> }
> }
> }
>
> If Slice is not an inline class, the barrier at the end of such
> constructors together with the barrier implied in a pointer load
> ensures that all created objects are consistent and always observed as
> such. With the inline keyword added, this is no longer the case.
>
> This suggests to me that inline classes cannot protect their
> invariants. Will that limit their usefulness?
>
> If you wonder how Go solves this problem with its built-in slice
> types, the answer is that it does not. Go is simply not memory-safe
> if goroutines can execute concurrently on multiple processors.
>
More information about the valhalla-dev
mailing list