Frozen objects?

Remi Forax forax at univ-mlv.fr
Sat Dec 16 19:24:19 UTC 2023


Hello, 
As part of Valhalla, the VM support for what you want to do already exists because we need something similar to be able to deserialize a value class. 
jdk.internal.misc.Unsafe provides several methods: makePrivateBuffer(), put*() and finishPrivateBuffer() [1]. 

Compared to your interface Freezable, the method equivalent of the method freeze(), finishPrivateBuffer() needs to returns a value so the VM/JIT can separate the reference to a piece of memory which is mutable from the reference to the same piece of memory which is frozen. 

regards, 
Rémi 

[1] [ https://github.com/openjdk/valhalla/blob/lworld/src/java.base/share/classes/jdk/internal/misc/Unsafe.java#L299 | https://github.com/openjdk/valhalla/blob/lworld/src/java.base/share/classes/jdk/internal/misc/Unsafe.java#L299 ] 

> From: "Archie Cobbs" <archie.cobbs at gmail.com>
> To: "amber-dev" <amber-dev at openjdk.org>
> Sent: Saturday, December 16, 2023 6:32:59 PM
> Subject: Frozen objects?

> Caveat: I'm just trying to educate myself on what's been discussed in the past,
> not actually suggest a new language feature. I'm sure this kind of idea has
> been discussed before so feel free to point me at some previous thread, etc.

> In C we have 'const' which essentially means "the memory allocated to this thing
> is immutable". The nice thing about 'const' is that it can apply to an
> individual variable or field in a structure, or it can apply to an entire C
> structure or C array. In effect it applies to any contiguous memory region that
> can be named/identified at the language level.

> On the other hand, it's just a language fiction, i.e., it can always be defeated
> at runtime by casting (except for static constants).

> In Java we have 'final' which (in part) is like 'const' for fields and
> variables, but unlike C 'final' can't be applied to larger memory regions like
> entire objects or entire arrays.

> In C, 'const' can be applied "dynamically" in the sense I can cast foo to const
> foo. Of course, this is only enforced at the language level.

> Summary of differences between C 'const' and Java 'final':

>     * Granularity:

>         * C: Any contiguous memory region that has a language name/identification
>         * Java: At most 64 bits at a time (*) and arrays are not included
>         * Advantage: C
>     *
> Enforcement:

>         * C: Enforced only by the compiler (mostly)
>         * Java: Enforced by the compiler and at runtime
>         * Advantage: Java
>     *
> Dynamic Application:

>         * C: Yes
>         * Java: No
>         * Advantage: C
> (*) With records and value objects we are gradually moving towards the ability
> for larger things than an individual field to be 'const'. More generally, Java
> has slowly been glomming on some of the goodness from functional programming,
> including making it easier to declare and work with immutable data.

> This all begs the question: why not take this idea to its logical conclusion?
> And while we're at it, make the capability fully dynamic, instead of limiting
> when you can 'freeze' something construction time?

> In other words, add the ability to "freeze" an object or array. If 'x' is
> frozen, whatever 'x' directly references becomes no longer mutable.

> A rough sketch...

> Add new Freezable interface:

> public interface Freezable {
> boolean isFrozen();
> static boolean freeze(Freezable obj); // returns false if already frozen
> }

> Arrays automatically implement Freezable (just like they do Cloneable )

> What about the memory model? Ideally it would work as if written like this:

> public class Foo implements Freezable {
> private volatile frozen; // set to true by Freezable.freeze()
> void mutateFooContent(Runnable mutation) {
> if (this.frozen)
> throw new FrozenObjectException();
> else
> mutation.run();
> }
> }

> But there could be a better trade-off of performance vs. semantics.

> Other trade-offs...

>    * (-) All mutations to a Freezable would require a new 'frozen' check (* see
>     below)
>     * (-) There would have to be a new bit allocated in the object header
>    * (+) Eliminate zillions of JDK defensive array copies (things like
>     String.toCharArray() )
>     * (+) JIT optimizations for constant-folding, etc.
>     * (+) GC optimizations

>        * (*) Put frozen objects into a read-only region of memory to eliminate mutation
>         checks
>         * Optimize scanning of frozen references (since they never change)
> I'm curious how other people think this idea would or wouldn't make sense for
> Java & what's been decided in the past.

> Thanks,
> -Archie

> --
> Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20231216/d6662a12/attachment.htm>


More information about the amber-dev mailing list