<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body dir="auto">
For what it’s worth, there was an earlier experiment that merged the bound and unbound representation classes, and you could see a measurable performance loss just because these classes have more fields and there were more branches to access them. 
<div><br id="lineBreakAtBeginningOfSignature">
<div dir="ltr">Sent from my iPad</div>
<div dir="ltr"><br>
<blockquote type="cite">On May 2, 2024, at 7:34 AM, Claes Redestad <claes.redestad@oracle.com> wrote:<br>
<br>
</blockquote>
</div>
<blockquote type="cite">
<div dir="ltr"> Hi,
<div><br>
</div>
<div>Looking at replacing ASM with the ClassFile API (CFA) in various places we have observed both startup and footprint regressions. Startup times increase 4-5 ms on Hello World, 40 ms on a small GUI app and 250ms on a larger app. So there’s both a one-off
 cost and a scaling factor here.</div>
<div><br>
</div>
<div>We’ve been doing some analysis and picked a lot of low-hanging fruit. Bytecode executed has been reduced to about the same level and we’ve found improvements in dependencies such as the java.lang.constant API. All good. And the number of classes loaded
 on a Hello World style application has dropped by about 50. Great! </div>
<div><br>
</div>
<div>Still the overall picture persists: a Hello World style application that initializes a lambda takes a wee bit longer and the footprint is decidedly. The main culprit now that some low-hanging fruit has been plucked seem to be that the trivial use of CFA
 to spin up lambda proxies is loading in about 160 classes: An ASM-based baseline loads 691 classes. The best recent CFA version (a merge of <a href="https://github.com/openjdk/jdk/pull/19006">https://github.com/openjdk/jdk/pull/19006</a> and <a href="https://github.com/openjdk/jdk/pull/17108">https://github.com/openjdk/jdk/pull/17108</a>)
 loads 834. A net 143 class difference.</div>
<div><br>
</div>
<div>Loading classes slows down startup, increases memory footprint, grows the default CDS archive. And involving more classes - and more code - is often costly even accompanied with some of the solutions being explored to ”fix” startup at large. </div>
<div><br>
</div>
<div>So why is this?</div>
<div><br>
</div>
<div>The CFA is mainly split up into two package stuctures, one public under java.lang.classfile and one internal under jdk.internal.classfile.impl. In the public side most of the types are sealed interfaces, which are then implemented by an assortment of abstract
 and concrete classes under jdk.internal.classfile.impl. Very neat. But I do fear this means we are at least doubling the number of loaded classes from this neat separation.</div>
<div><br>
</div>
<div>While it’s a bit late in the game I still feel I must propose striking up a conversation about what, if anything, we could consider that would reduce the number of loaded classes. Whether they are interfaces, abstract or concrete classes. I think any savings
 would be very welcome. </div>
<div><br>
</div>
<div>Here’s an idea:</div>
<div><br>
</div>
<div>
<div>There are a number of cases where the separation seem unnecessary:</div>
<div>
<pre style="background-color: rgb(43, 43, 43);"><pre><span style="color: rgb(204, 120, 50); font-family: "JetBrains Mono", monospace;">public sealed interface </span><font color="#a9b7c6" face="JetBrains Mono, monospace">ArrayLoadInstruction </font><span style="color: rgb(204, 120, 50); font-family: "JetBrains Mono", monospace;">extends </span><font color="#a9b7c6" face="JetBrains Mono, monospace">Instruction<br>        </font><span style="color: rgb(204, 120, 50); font-family: "JetBrains Mono", monospace;">permits </span><font color="#a9b7c6" face="JetBrains Mono, monospace">AbstractInstruction.UnboundArrayLoadInstruction {<br></font><font color="#629755" face="JetBrains Mono, monospace"><span style="caret-color: rgb(98, 151, 85);"><i>…</i></span></font></pre><pre style="color: rgb(169, 183, 198); font-family: "JetBrains Mono", monospace;"><pre style="font-family: "JetBrains Mono", monospace;"><span style="color: rgb(98, 151, 85); font-style: italic;">    </span><span style="color: rgb(204, 120, 50);">static </span>ArrayLoadInstruction <span style="color: rgb(255, 198, 109);">of</span>(Opcode op) {<br>        Util.<span style="font-style: italic;">checkKind</span>(op<span style="color: rgb(204, 120, 50);">, </span>Opcode.Kind.<span style="color: rgb(152, 118, 170); font-style: italic;">ARRAY_LOAD</span>)<span style="color: rgb(204, 120, 50);">;<br></span><span style="color: rgb(204, 120, 50);">        return new </span>AbstractInstruction.UnboundArrayLoadInstruction(op)<span style="color: rgb(204, 120, 50);">;<br></span><span style="color: rgb(204, 120, 50);">    </span>}<br>}</pre></pre></pre>
</div>
<div>An interface in java.lang.classfile.instruction which only permits a single implementation class - <span class="Apple-tab-span" style="white-space: pre;">
</span>and as it happens has a static factory method which is the only place where that concrete instruction is called.</div>
<div><br>
</div>
</div>
<div>Making single-use interfaces such as this one a final class is doable[1], but now we’d have some instructions modeled as an interface, others as classes. Cats and dogs, living together. And it gets messy quick for instructions that can be bound or unbound,
 since those inherit from abstract BoundInstruction or UnboundInstruction respectively. But perhaps internal implementation details like whether an instruction is bound or unbound ought to be modeled with composition rather than inheritance (and optional CodeImpl
 + pos tuple) in a shared base class? Then it might follow that each of the interfaces in java.lang.classfile.instruction can really be a single final class. If all concrete instructions were folded into their corresponding interface that could reduce the total
 number of implementation classes by 46 (though only 6 of those seem to be on a Hello World)</div>
<div><br>
</div>
<div>Yikes, that’s a deep cut for a small, incremental gain. From an API consumer point of view I can’t say there’s much difference, and the factories can still (be evolved to) produce different concrete types when necessary.</div>
<div><br>
</div>
<div>Maybe someone can think of other, simpler ways to reduce the number of types floating around in the ClassFile API?</div>
<div><br>
</div>
<div>Thank you for your consideration.</div>
<div><br>
</div>
<div>Claes</div>
<div><br>
</div>
<div>[1] https://github.com/openjdk/jdk/compare/master...cl4es:jdk:fold_instruction_example?expand=1</div>
</div>
</blockquote>
</div>
</body>
</html>