Soliciting opinions on JDK-8219412

Archie Cobbs archie.cobbs at gmail.com
Mon Jan 9 15:02:33 UTC 2023


I'm looking for advice/opinions on the best way to address JDK-8219412 -
Eager enum class initialization with enum switch
<https://bugs.openjdk.org/browse/JDK-8219412>.

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.

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.
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.

*Strategy #1 - Put each lookup table into a separate synthetic class.*

You can see *the reverse* of this fix in this diff
<https://github.com/openjdk/jdk/pull/10797/commits/f8b189ec75164873953e528b92ba06372b215c50>
.

The upside of this approach is that it fixes the bug without changing the
approach and therefore presumably minimally affecting performance.

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??

The total amount of code generated is basically the same, it's just spread
over multiple class files instead of one.


*Strategy #2 - Switch on String identifiers instead of ordinal values*

This approach is straightforward, however the performance suffers a good
bit in my tests. Probably not an option.


*Strategy #3 - Don't rely on a static initializer to build the mapping
tables*

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:

synthetic /* volatile ? */ int[] $EnumMap$E1;
synthetic /* volatile ? */ int[] $EnumMap$E2;
synthetic /* volatile ? */ int[] $EnumMap$E3;

static int[] getEnumMap$E1() {
    if ($EnumMap$E1 == null) {
        /* build map here */
    }
    return $EnumMap$E1;
}

static int[] getEnumMap$E2() {
    if ($EnumMap$E2 == null) {
        /* build map here */
    }
    return $EnumMap$E2;
}

static int[] getEnumMap$E3() {
    if ($EnumMap$E3 == null) {
        /* build map here */
    }
    return $EnumMap$E3;
}

*Strategy #4 - Other ideas?*

Thanks,
-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/compiler-dev/attachments/20230109/4b36aaca/attachment.htm>


More information about the compiler-dev mailing list