RFR: JDK-8219412: Eager enum class initialization with enum switch

forax at univ-mlv.fr forax at univ-mlv.fr
Fri Apr 5 17:14:34 UTC 2019


----- Mail original -----
> De: "jan lahoda" <jan.lahoda at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "compiler-dev" <compiler-dev at openjdk.java.net>, "Liam Miller-Cushon" <cushon at google.com>
> Envoyé: Vendredi 5 Avril 2019 13:56:58
> Objet: Re: RFR: JDK-8219412: Eager enum class initialization with enum switch

> On 4.4.2019 20:39, Remi Forax wrote:
>> Hi Jan,
>> it seems like a perfect case for a constant dynamic,
>> the array can be loaded using ldc and the bootstrap method takes the
>> enum names as constant arguments.
> 
> True, I didn't realize that. javac does not currently (AFAIK) have a way
> to generate condy, so we first need support for condy in javac. This
> patch strives to do that:
> http://cr.openjdk.java.net/~jlahoda/8219412/webrev.condy.01/
> based on Vicente's:
> http://hg.openjdk.java.net/amber/amber/rev/8e2f2d280e44
> 
> The usage to use that to generate the condy where available (and fall
> back on generating the holder classes where not available):
> http://cr.openjdk.java.net/~jlahoda/8219412/webrev.01/

The description of an enum (EnumMapping) can be encoded by the enum class and an array of String (in the order of the enum values at compile time).
So instead of generating one specific method per enum that initializes the mapping table and using it as a bootstrap method, i believe it's better to have one bootstrap method in the JDK (let say in java.lang.invoke.ConstantBootstraps) that takes the enum class and an array of Strings. This method will use ConstantBootstraps.enumConstant to get the corresponding enum value at runtime (which does the security checks) and a call ordinal() on each enum value in order to dynamically create the mapping table.
This will reduce the size of the generated bytecode by removing the need to have one bootstrap method per enum.

Also in Target.java, constant dynamic is available since 11 but if there is a need of a new BSM in ConstantBootstraps, it should be since 13 (apart if the patch is backported to 11).


> 
> (The downside of that is that when indy switch desugaring will be
> implemented, there will be three distinct desugarings for switches over
> enums.)

yes, as you said, we may able to share some code in the future, we will see when we get there.

> 
>>
>> You doesn't have to create one class per switch, it's lazy initialized
> 
> Please note that neither the original patch, nor the current javac
> state, creates a class per switch. It creates a field (and with the .00
> version of the patch a class) per enum used as switch selector per
> top-level class.


yes

> 
> Jan

Rémi

> 
>> like any constant pool item and each switch on the same enum type can
>> reuse the same,
>> compare to the solution implemented by Eclipse, it's not a field but a
>> constant pool constant you you can not mess with it using reflection and
>> you don't need to check if the array was loaded or not in the fastpath.
>>
>> regards,
>> Rémi
>>
>> ------------------------------------------------------------------------
>>
>>     *De: *"Liam Miller-Cushon" <cushon at google.com>
>>     *À: *"jan lahoda" <jan.lahoda at oracle.com>
>>     *Cc: *"compiler-dev" <compiler-dev at openjdk.java.net>
>>     *Envoyé: *Jeudi 4 Avril 2019 20:20:00
>>     *Objet: *Re: RFR: JDK-8219412: Eager enum class initialization with
>>     enum switch
>>
>>     Hi Jan,
>>     There are a couple of other bugs about enum switch / class
>>     initialization issues that I think are addressed by this approach:
>>     https://bugs.openjdk.java.net/browse/JDK-7176515
>>     https://bugs.openjdk.java.net/browse/JDK-8169526
>>
>>     Do you have a sense of how many additional auxiliary classes this
>>     will create for typical applications? I'm wondering if the number of
>>     additional classes might be large enough to effect performance (i.e.
>>     binary size, classloading).
>>
>>     Were other lazy initialization patterns considered? JDK-7176515
>>     mentions that ecj avoids this by caching the switch map in a field
>>     in the same class as the switch.
>>
>>     On Thu, Apr 4, 2019 at 11:04 AM Jan Lahoda <jan.lahoda at oracle.com
>>     <mailto:jan.lahoda at oracle.com>> wrote:
>>
>>         Hi,
>>
>>         When there is a switch over enum in the code, and is compiled
>>         into the
>>         bytecode, the meaning of the switch should not change even if
>>         the enum's
>>         constant are reordered. This is achieved by a map that maps the
>>         (current) enum constants to the appropriate case in the switch.
>>         This map
>>         is stored in a field in an auxiliary class, and filled when that
>>         auxiliary class is loaded in.
>>
>>         But, if there are multiple switches over distinct enums under a
>>         single
>>         top-level class, the mapping fields for all the enums are stored
>>         in a
>>         single class. So, when any of these is needed, the mapping is
>>         constructed for all the enums, which may cause enum class
>>         initialization
>>         even in cases where it shouldn't happen.
>>
>>         The proposed fix is to create a separate auxiliary classes for each
>>         enum/mapping.
>>
>>         Proposed patch:
>>         http://cr.openjdk.java.net/~jlahoda/8219412/webrev.00/
>>         JBS: https://bugs.openjdk.java.net/browse/JDK-8219412
>>
>>         How does this look?
>>
>>         Thanks,
>>               Jan
>>


More information about the compiler-dev mailing list