<div dir="auto"><div>> <span style="font-family:menlo">The static argument list identifies the enum constants (by string) corresponding to the case numbers.</span></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">This will decrease theoretical maximum of switch blocks in enum switch statement due to constant pool size limitations. So it may affect some code with huge switches over enum.</div><div dir="auto"><br><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Mon, Jan 9, 2023, 18:35 Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">



<div style="word-wrap:break-word;line-break:after-white-space">
<font face="Menlo">Another strategy is to use an `invokedynamic` as a switch classifier.  (I believe there is even a bootstrap for this implemented somewhere.)<br>
<br>
The idea is that we lower a switch<br>
<br>
    switch (e) [ <br>
        case A: …<br>
        case B: …<br>
        …<br>
    }<br>
<br>
Into a compact switch on int, and use an indy to map the target to a case number:<br>
<br>
    switch (indy [BSM=EnumClassifier, type=(E)I, args = [ E.class, “A”, “B”, … ]) { <br>
        case 1: …<br>
        Case 2: …<br>
    }<br>
<br>
 The indy bootstrap takes as a dynamic argument the switch operand (enum value), and returns an int corresponding the case number.  The static argument list identifies the enum constants (by string) corresponding to the case numbers.  The bootstrap builds the
 array that we would have built at compile time, curries it onto a method handle, and wraps the method handle in a ConstantCallSite.  Then the array is only built the first time we invoke the switch.  Thereafter we get similar behavior to the current scheme,
 but without static initializers.  <br>
<br>
<br>
<br>
<br>
<br>
</font>
<blockquote type="cite"><font face="Menlo">On Jan 9, 2023, at 10:02 AM, Archie Cobbs <<a href="mailto:archie.cobbs@gmail.com" target="_blank" rel="noreferrer">archie.cobbs@gmail.com</a>> wrote:<br>
<br>
I'm looking for advice/opinions on the best way to address JDK-8219412 - Eager enum class initialization with enum switch.<br>
<br>
The problem stems from how the compiler implements switches on enum. The obvious simple approach is to get the enum's ordinal() 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 Enum class is recompiled later.<br>
Instead the compiler uses a lookup table. This table is dynamically constructed at runtime by a static initializer in a synthetic class. When compiling Foo.java, a separate lookup table is created for each enum type that is switched on anywhere in Foo.java.
 These lookup tables are all put into a single synthetic class Foo$1 and are all initialized at the same time, in a single static initializer.<br>
<br>
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>
<br>
Strategy #1 - Put each lookup table into a separate synthetic class.<br>
<br>
You can see the reverse of this fix in this diff.<br>
<br>
The upside of this approach is that it fixes the bug without changing the approach and therefore presumably minimally affecting performance.<br>
<br>
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: Foo$1, Foo$2, etc. Is that a show-stopper??<br>
<br>
The total amount of code generated is basically the same, it's just spread over multiple class files instead of one.<br>
<br>
Strategy #2 - Switch on String identifiers instead of ordinal values<br>
<br>
This approach is straightforward, however the performance suffers a good bit in my tests. Probably not an option.<br>
<br>
Strategy #3 - Don't rely on a static initializer to build the mapping tables<br>
<br>
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:<br>
<br>
synthetic /* volatile ? */ int[] $EnumMap$E1;<br>
synthetic /* volatile ? */ int[] $EnumMap$E2;<br>
synthetic /* volatile ? */ 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>
}<br>
<br>
Strategy #4 - Other ideas?<br>
<br>
Thanks,<br>
-Archie<br>
<br>
-- <br>
Archie L. Cobbs<br>
</font></blockquote>
<br>
</div>

</blockquote></div></div></div>