RFR: 7176515: ExceptionInInitializerError for an enum with multiple switch statements [v4]
Archie L. Cobbs
duke at openjdk.org
Mon Jan 9 04:23:21 UTC 2023
On Mon, 19 Dec 2022 15:44:30 GMT, Archie L. Cobbs <duke at openjdk.org> wrote:
>> This patch is both a minor optimization and a fix for JDK-7176515.
>>
>> JDK-7176515 relates to how javac handles `switch` statements on `Enum` values, which are effectively "syntactic sugar".
>>
>> The simple approach would be to just get the enum's `ordinal()` value and then revert to a normal integer value switch on that. However, this snapshots the ordinal values at compile-time, and thus can fail if the `Enum` class is recompiled later.
>>
>> Presumably to avoid that possibility (are there any other reasons?) the compiler instead uses a lookup table. This table is dynamically constructed at runtime by a static initializer in a synthetic class. This avoids the "stale ordinal" problem of the simple approach, but it also creates a potential class initialization loop if there happens to an `Enum` switch inside an `Enum` class constructor, as demonstrated by the bug.
>>
>> This patch makes the following change: If we are handling an `Enum` switch, and the `Enum` class we are switching on is also the class we are compiling, then just go with the simple approach, because the "stale ordinal" problem can't happen in this case so there's no need to build a runtime lookup table.
>>
>> This results in two improvements:
>> * It avoids building the lookup table for switches on self
>> * It fixes JDK-7176515 as stated
>>
>> Although the reproducing test case provided in JDK-7176515 gets fixed by this patch, the underlying issue is still there and can still be triggered with a slightly more complicated test case (included, but commented out).
>>
>> So JDK-7176515 could be left open (or a new bug created) and a separate discussion had about how to "really" fix it.
>>
>> Part of this discussion should be defining what that means, i.e., the boundaries of the bug. There are some scenarios that are basically impossible to fix, for example, two `Enum` classes whose constructors take as a parameter instances of the other `Enum` class and then switch on it. That cycle has nothing to do with how switches are handled.
>
> Archie L. Cobbs has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains four additional commits since the last revision:
>
> - Merge branch 'master' into JDK-7176515
> - Merge branch 'master' into JDK-7176515
> - Give test a better name and don't rely on assertions being enabled.
> - Skip enum switch lookup tables when compiling the enum switch class.
I've made a couple of improvements to this patch. As a result the follow-up bug [8299760](https://bugs.openjdk.org/browse/JDK-8299760), and also [8219412 - Eager enum class initialization with enum switch](https://bugs.openjdk.org/browse/JDK-8219412) are now fixed.
Improvement 1
The previous patch avoided generating a mapping table when the `enum` being switched on was the same class as the class currently being compiled. This is because there is no possibility of the ordinal values changing at runtime due to a recompilation. But this is too conservative - the same thing is true for any `enum` type defined in the same top-level class. So we generalize the test from "same class" as "in the same top-level class compilation". This change fixes the follow-up bug [8299760](https://bugs.openjdk.org/browse/JDK-8299760).
Improvement 2
All of the mapping tables for any `enum` type switched were being jammed into the same compiler-generated class. This meant that all of these `enum` types were initialized at the same time, regardless of which one actually experiences a 'first use'. This is what causes [8219412](https://bugs.openjdk.org/browse/JDK-8219412). The fix here is simple - put each mapping table into its own compiler-generated class.
-------------
PR: https://git.openjdk.org/jdk/pull/10797
More information about the compiler-dev
mailing list