<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Toby Reyelts" <rreyelts@gmail.com><br><b>To: </b>"valhalla-dev" <valhalla-dev@openjdk.org><br><b>Sent: </b>Monday, May 5, 2025 9:41:12 PM<br><b>Subject: </b>Value objects and inheritance<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr">[Apologies if this is the wrong list. I was hoping to find something more user-focused (e.g. a valhalla-users@), but this seems to be the recommended place to ask questions. Please LMK if there's somewhere more appropriate].<div><br><div>I've been reading the JEPs and messing around with the early access build, trying to create a mental model for myself about how JVMs will typically be able to optimize value classes. It seems like a goal is effectively to be able to dump object headers:</div><div>- no identity (no boxing/unboxing visibility, no gc)</div><div>- no synchronization</div><div>- restrictions on inheritance</div><div>etc</div><br><div>but this seems like it relies on the ability of the JIT to know the concrete value of the type at runtime. E.G. if I have the method:<br><br>public void print(java.lang.Number! n) {<br>  System.out.println(n.toString());<br>}<br><br>It seems that the JVM must require some kind of object header to be able to determine the appropriate toString to dispatch to. </div></div></div></blockquote><div><br></div><div>Not necessarily, if you call with print(Integer.valueOf(3)), if the JIT is able to inlining the call,  the JIT will propagate the type (here Integer) so not boxing will occur.</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr"><div><div>Similarly, if I have:<br><br>class X {<br>   Number![] nums = someNums();<br>}<br><br>It seems like every Number in nums must still require an object header, because the JIT doesn't know the concrete type of said objects.</div></div></div></blockquote><div><br></div><div>Here you have a field which store an array.</div><div>An array is never a value type, so you will always have a header for the array.</div><div>But at runtime, you can have an array of Integer!, in that case, all the elements of the array have no header.</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr"><div><div> Reading JEP 401 more closely, I see now that scalarization can't be supported for supertypes:<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="color:rgb(0,0,0);font-family:"DejaVu Sans","Bitstream Vera Sans","Luxi Sans",Verdana,Arial,Helvetica;font-size:13.3333px">One limitation of scalarization is that it is not typically applied to a variable with a type that is a </span><em style="color:rgb(0,0,0);font-family:"DejaVu Sans","Bitstream Vera Sans","Luxi Sans",Verdana,Arial,Helvetica;font-size:13.3333px">supertype</em><span style="color:rgb(0,0,0);font-family:"DejaVu Sans","Bitstream Vera Sans","Luxi Sans",Verdana,Arial,Helvetica;font-size:13.3333px"> of a value class type. </span></blockquote><br></div><div>Is heap flattening in the same category? </div></div></div></blockquote><div><br></div><div>Heap flattening is usually harder to optimize than scalarization (see below).</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div dir="ltr"><div><div>Are there any optimizations that end up working with supertypes, or is the general premise that you'll mostly need to be working with the concrete classes for optimizations to kick in?</div></div></div></blockquote><div><br></div><div>Here is a simplified mental model :</div><div>The bytecode instructions are the same for an identity class or a value class. That allow us to retrofit Integer or Optional to be a value type without any recompilation (yai !).</div><div>Because of that, the value class optimizations have to be done at runtime, most of them are done by the JIT.</div><div><br data-mce-bogus="1"></div><div>For parameters/local variable (scalarization), if you use a concrete class, it's easy for a JIT.</div><div>If you use a supertype, it depends on inlining.</div><div><br data-mce-bogus="1"></div><div>For fields (flattening), if you use a concrete class, if sizeof(object) < 64 bits, it's easy for the JIT.</div><div>if you use a supertype, it depends on escape analysis.</div><div><br data-mce-bogus="1"></div><div>In the future,</div><div>  if sizeof(object) == 64 bits, the field has to be non-nullable.</div><div>  if sizeof(object) >= 64 bits, the field has to be non-nullable and the class has to allow tearing (several reads/writes).</div><div><br data-mce-bogus="1"></div><div>regards,</div><div>RĂ©mi</div><div><br data-mce-bogus="1"></div></div></div></body></html>