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