<div dir="ltr"><div>I'm looking for advice/opinions on the best way to address <a href="https://bugs.openjdk.org/browse/JDK-8219412">JDK-8219412 - Eager enum class initialization with enum switch</a>.</div><div><br></div><div>The problem stems from how the compiler implements switches on enum. The obvious simple approach is to get the enum's <code class="gmail-notranslate">ordinal()</code>
value and then revert to a normal integer value switch.
However, this snapshots the ordinal values at compile-time, and thus can
fail if the <code class="gmail-notranslate">Enum</code> class is recompiled later.</div><div>
<p dir="auto">Instead the compiler uses a lookup table. This table is
dynamically constructed at runtime by a static initializer in a
synthetic class. When compiling <span style="font-family:monospace">Foo.java</span>, a separate lookup table is created for each enum type that is switched on anywhere in <span style="font-family:monospace">Foo.java</span>. These lookup tables are all put into a single synthetic class <span style="font-family:monospace">Foo$1</span> and are all initialized at the same time, in a single static initializer.<br></p></div><div>Now suppose Foo contains switches on enum types E1, E2, and E3 and a switch on E1 is encountered. This will cause classes E2 and E3 to be initialized, even though there is no 'first use' of either class. This is the bug.<br></div><div><br></div><div><b>Strategy #1 - Put each lookup table into a separate synthetic class.</b></div><div><br></div><div>You can see <i>the reverse</i> of this fix <a href="https://github.com/openjdk/jdk/pull/10797/commits/f8b189ec75164873953e528b92ba06372b215c50">in this diff</a>.</div><div><br></div><div>The upside of this approach is that it fixes the bug without changing the approach and therefore presumably minimally affecting performance.</div><div><br></div><div>The downside is an increase in the number of synthetic classes created: for every enum type switched on in Foo.java but declared in some other source file, there is a synthetic class created: <span style="font-family:monospace">Foo$1</span>, <span style="font-family:monospace">Foo$2</span>, etc. Is that a show-stopper??<br></div><div><br></div><div>The total amount of code generated is basically the same, it's just spread over multiple class files instead of one.<br></div><div><div><br></div><div><div><b>Strategy #2 - Switch on String identifiers instead of ordinal values<br></b></div></div><div><br></div><div>This approach is straightforward, however the performance suffers a good bit in my tests. Probably not an option.<br></div><div><br></div><div><b>Strategy #3 - Don't rely on a static initializer to build the mapping tables<br></b></div><div><br></div><div>This approach would mean not relying on class initialization to trigger building the mapping tables, so we could build each table separately on demand. The synthetic class would look something like this:</div><div style="margin-left:40px"><br></div><div style="margin-left:40px"><span style="font-family:monospace">synthetic /* <span style="font-family:monospace">volatile </span>? */ int[] $EnumMap$E1;<br>synthetic <span style="font-family:monospace">/*<span style="font-family:monospace"> volatile </span>? */</span> int[] $EnumMap$E2;<br>synthetic <span style="font-family:monospace">/*<span style="font-family:monospace"> volatile </span>? */</span> int[] $EnumMap$E3;<br><br>static int[] getEnumMap$E1() {<br> if ($EnumMap$E1 == null) {<br> /* build map here */<br> }<br> return $EnumMap$E1;<br>}<br><br>static int[] getEnumMap$E2() {<br> if ($EnumMap$E2 == null) {<br> /* build map here */<br> }<br> return $EnumMap$E2;<br>}<br><br>static int[] getEnumMap$E3() {<br> if ($EnumMap$E3 == null) {<br> /* build map here */<br> }<br> return $EnumMap$E3;<br>}</span><br></div><div><br></div><div><b>Strategy #4 - Other ideas?</b></div><div><br></div><div>Thanks,<br></div><div>-Archie</div><div><br></div><div>-- <br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Archie L. Cobbs<br></div></div></div></div>