<div dir="auto"><div>How do you freeze a memory region without talking about freezing objects?</div><div dir="auto"><br></div><div dir="auto">Unless your data is flat (so only value classes, primitives and arrays, 2 of which won't benefit from freezing) the only way to have freezing something that is enforced at compile time you must talk about objects.<br><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Tue, 19 Dec 2023, 10:04 Markus Karg, <<a href="mailto:markus@headcrashing.eu">markus@headcrashing.eu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div lang="DE" link="#0563C1" vlink="#954F72" style="word-wrap:break-word"><div class="m_-2682028665710061497WordSection1"><p class="MsoNormal"><span style="font-size:11.0pt;color:#1f497d">I wonder why we discuss about freezing *objects* (which needs time) but not simply freezing *references* (like `const` does in C++)?<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;color:#1f497d">-Markus<u></u><u></u></span></p><p class="MsoNormal"><span style="font-size:11.0pt;color:#1f497d"><u></u> <u></u></span></p><p class="MsoNormal"><a name="m_-2682028665710061497__MailEndCompose" rel="noreferrer"><span style="font-size:11.0pt;color:#1f497d"><u></u> <u></u></span></a></p><div><div style="border:none;border-top:solid #b5c4df 1.0pt;padding:3.0pt 0cm 0cm 0cm"><p class="MsoNormal"><b><span style="font-family:"Tahoma","sans-serif"">Von:</span></b><span style="font-family:"Tahoma","sans-serif""> amber-dev [mailto:<a href="mailto:amber-dev-retn@openjdk.org" target="_blank" rel="noreferrer">amber-dev-retn@openjdk.org</a>] <b>Im Auftrag von </b>Dan Heidinga<br><b>Gesendet:</b> Montag, 18. Dezember 2023 16:04<br><b>An:</b> Archie Cobbs; amber-dev<br><b>Betreff:</b> Re: Frozen objects?<u></u><u></u></span></p></div></div><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt">Let me throw out one other concern: races.  The invariant frozen objects want is that the application and runtime can trust they will never be mutated again.  Unfortunately, if the object is published across threads before it is frozen, then that invariant is very difficult and expensive to maintain.<u></u><u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt">If two threads, A & B, both have references to the object and thread A freezes it, B may still be publishing writes to it that A only observes later.  To ensure the right JMM happens-before relationship for fields of Freezable objects, both reads and writes would need to be more expensive (volatile semantics?) until a thread could validate the object it was operating on was frozen.<u></u><u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt">Freezing is not just a free set of unexplored optimizations.  There’re also new costs associated with it across the runtime (field read/write, profiling, etc). <u></u><u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt">--Dan<u></u><u></u></span></p><p class="MsoNormal"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p><div id="m_-2682028665710061497mail-editor-reference-message-container"><div><div style="border:none;border-top:solid #b5c4df 1.0pt;padding:3.0pt 0cm 0cm 0cm"><p class="MsoNormal" style="margin-right:0cm;margin-bottom:12.0pt;margin-left:36.0pt"><b><span lang="EN-CA" style="font-size:12.0pt;color:black">From: </span></b><span lang="EN-CA" style="font-size:12.0pt;color:black">amber-dev <<a href="mailto:amber-dev-retn@openjdk.org" target="_blank" rel="noreferrer">amber-dev-retn@openjdk.org</a>> on behalf of Archie Cobbs <<a href="mailto:archie.cobbs@gmail.com" target="_blank" rel="noreferrer">archie.cobbs@gmail.com</a>><br><b>Date: </b>Saturday, December 16, 2023 at 12:33 PM<br><b>To: </b>amber-dev <<a href="mailto:amber-dev@openjdk.org" target="_blank" rel="noreferrer">amber-dev@openjdk.org</a>><br><b>Subject: </b>Frozen objects?<u></u><u></u></span></p></div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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.<u></u><u></u></span></p></div><div><div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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).<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Summary of differences between C 'const' and Java 'final':<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">Granularity:<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">C: Any contiguous memory region that has a language name/identification<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Java: At most 64 bits at a time (*) and arrays are not included<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Advantage: C<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">Enforcement:<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">C: Enforced only by the compiler (mostly)<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Java: Enforced by the compiler and at runtime<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Advantage: Java<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">Dynamic Application:<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">C: Yes<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Java: No<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Advantage: C<u></u><u></u></span></p></div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">(*) 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.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">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?<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">In other words, add the ability to "freeze" an object or array. If 'x' is frozen, whatever 'x' directly references becomes no longer mutable.<u></u><u></u></span></p></div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">A rough sketch...<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Add new </span><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">Freezable</span><span lang="EN-CA" style="font-size:11.0pt"> interface:<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">    public interface Freezable {</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">        boolean isFrozen();</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">        static boolean freeze(Freezable obj);   // returns false if already frozen</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">    }</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Arrays automatically implement </span><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">Freezable</span><span lang="EN-CA" style="font-size:11.0pt"> (just like they do </span><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">Cloneable</span><span lang="EN-CA" style="font-size:11.0pt">)<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">What about the memory model? Ideally it would work as if written like this:<u></u><u></u></span></p></div></div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">    public class Foo implements Freezable {</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">        private volatile frozen;    // set to true by Freezable.freeze()</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">        void mutateFooContent(Runnable mutation) {</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">            if (this.frozen)</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">                throw new FrozenObjectException();</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">            else</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">                mutation.run();</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">        }</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">    }</span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">But there could be a better trade-off of performance vs. semantics.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Other trade-offs...<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">(-) All mutations to a </span><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">Freezable</span><span lang="EN-CA" style="font-size:11.0pt"> would require a new 'frozen' check (* see below)<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">(-) There would have to be a new bit allocated in the object header<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">(+) Eliminate zillions of JDK defensive array copies (things like </span><span lang="EN-CA" style="font-size:11.0pt;font-family:"Courier New"">String.toCharArray()</span><span lang="EN-CA" style="font-size:11.0pt">)<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">(+) JIT optimizations for constant-folding, etc.<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:72.0pt"><span lang="EN-CA" style="font-family:Symbol">·</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">         </span><span lang="EN-CA" style="font-size:11.0pt">(+) GC optimizations<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">(*) Put frozen objects into a read-only region of memory to eliminate mutation checks<u></u><u></u></span></p><p class="MsoNormal" style="margin-left:108.0pt"><span lang="EN-CA" style="font-family:"Courier New"">o</span><span lang="EN-CA" style="font-size:7.0pt;font-family:"Times New Roman","serif"">    </span><span lang="EN-CA" style="font-size:11.0pt">Optimize scanning of frozen references (since they never change)<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">I'm curious how other people think this idea would or wouldn't make sense for Java & what's been decided in the past.<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Thanks,<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">-Archie<u></u><u></u></span></p></div><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt"><u></u> <u></u></span></p></div><div><div><p class="MsoNormal" style="margin-left:36.0pt"><span class="m_-2682028665710061497gmailsignatureprefix"><span lang="EN-CA" style="font-size:11.0pt">-- </span></span><span lang="EN-CA" style="font-size:11.0pt"><u></u><u></u></span></p><div><p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-CA" style="font-size:11.0pt">Archie L. Cobbs<u></u><u></u></span></p></div></div></div></div></div></div></div></div></blockquote></div></div></div>