RFR: 7176515: ExceptionInInitializerError for an enum with multiple switch statements [v9]

Archie L. Cobbs duke at openjdk.org
Thu Feb 16 14:54:00 UTC 2023


> 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 ten additional commits since the last revision:

 - Merge branch 'master' into JDK-7176515
 - Simplify code a bit by using Map.computeIfAbsent().
 - Update unit test after fixing 8299760.
 - Revert 2nd part of previous commit ("Put mapping tables for different...").
   
   This should go into a separate branch.
 - Further refinements to compiler-generated mappings tables for switched-on enums.
   
   - No mapping table needed for any Enum class within the same top level class.
   - Put mapping tables for different enum types into separate synthetic classes.
 - 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.

-------------

Changes:
  - all: https://git.openjdk.org/jdk/pull/10797/files
  - new: https://git.openjdk.org/jdk/pull/10797/files/53be679b..8987541c

Webrevs:
 - full: https://webrevs.openjdk.org/?repo=jdk&pr=10797&range=08
 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=10797&range=07-08

  Stats: 126177 lines in 4278 files changed: 55096 ins; 29168 del; 41913 mod
  Patch: https://git.openjdk.org/jdk/pull/10797.diff
  Fetch: git fetch https://git.openjdk.org/jdk pull/10797/head:pull/10797

PR: https://git.openjdk.org/jdk/pull/10797


More information about the compiler-dev mailing list