<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>I agree with Brian. If we want to fix this and put our hands in
the enum switch classification, I think the best use of our time
would be to tweak enum switches to adopt the superior indy-based
classification approach, which should be immune to the issue you
present.</p>
<p>Thanks<br>
Maurizio<br>
</p>
<div class="moz-cite-prefix">On 09/01/2023 15:35, Brian Goetz wrote:<br>
</div>
<blockquote type="cite" cite="mid:F52C9975-09B4-423D-9007-ED5C0B3CADAA@oracle.com">
<font class="" 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 class="">
<br class="">
The idea is that we lower a switch<br class="">
<br class="">
switch (e) [ <br class="">
case A: …<br class="">
case B: …<br class="">
…<br class="">
}<br class="">
<br class="">
Into a compact switch on int, and use an indy to map the target
to a case number:<br class="">
<br class="">
switch (indy [BSM=EnumClassifier, type=(E)I, args = [
E.class, “A”, “B”, … ]) { <br class="">
case 1: …<br class="">
Case 2: …<br class="">
}<br class="">
<br class="">
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 class="">
<br class="">
<br class="">
<br class="">
<br class="">
<br class="">
</font>
<blockquote type="cite" class=""><font class="" face="Menlo">On
Jan 9, 2023, at 10:02 AM, Archie Cobbs <<a href="mailto:archie.cobbs@gmail.com" class="moz-txt-link-freetext" moz-do-not-send="true">archie.cobbs@gmail.com</a>>
wrote:<br class="">
<br class="">
I'm looking for advice/opinions on the best way to
address JDK-8219412 - Eager enum class initialization with
enum switch.<br class="">
<br class="">
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 class="">
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 class="">
<br class="">
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 class="">
<br class="">
Strategy #1 - Put each lookup table into a separate synthetic
class.<br class="">
<br class="">
You can see the reverse of this fix in this diff.<br class="">
<br class="">
The upside of this approach is that it fixes the bug without
changing the approach and therefore presumably minimally
affecting performance.<br class="">
<br class="">
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 class="">
<br class="">
The total amount of code generated is basically the same, it's
just spread over multiple class files instead of one.<br class="">
<br class="">
Strategy #2 - Switch on String identifiers instead of ordinal
values<br class="">
<br class="">
This approach is straightforward, however the performance
suffers a good bit in my tests. Probably not an option.<br class="">
<br class="">
Strategy #3 - Don't rely on a static initializer to build the
mapping tables<br class="">
<br class="">
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 class="">
<br class="">
synthetic /* volatile ? */ int[] $EnumMap$E1;<br class="">
synthetic /* volatile ? */ int[] $EnumMap$E2;<br class="">
synthetic /* volatile ? */ int[] $EnumMap$E3;<br class="">
<br class="">
static int[] getEnumMap$E1() {<br class="">
if ($EnumMap$E1 == null) {<br class="">
/* build map here */<br class="">
}<br class="">
return $EnumMap$E1;<br class="">
}<br class="">
<br class="">
static int[] getEnumMap$E2() {<br class="">
if ($EnumMap$E2 == null) {<br class="">
/* build map here */<br class="">
}<br class="">
return $EnumMap$E2;<br class="">
}<br class="">
<br class="">
static int[] getEnumMap$E3() {<br class="">
if ($EnumMap$E3 == null) {<br class="">
/* build map here */<br class="">
}<br class="">
return $EnumMap$E3;<br class="">
}<br class="">
<br class="">
Strategy #4 - Other ideas?<br class="">
<br class="">
Thanks,<br class="">
-Archie<br class="">
<br class="">
-- <br class="">
Archie L. Cobbs<br class="">
</font></blockquote>
<br class="">
</blockquote>
</body>
</html>