RFR: 8241356: Use a more reliable way to encode Symbol flags

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

RFR: 8241356: Use a more reliable way to encode Symbol flags

Jan Lahoda-3
[This is a GitHub copy of: https://mail.openjdk.java.net/pipermail/compiler-dev/2020-March/014389.html ]

Currently, (com.sun.tools.javac.code.)Symbol/s have a long field "flags_field", which holds various one-bit information ("Flags") about the given Symbol.

We currently have around 64 such Flags, which means we are out of bits in the long field, and adding new flags is not easy.

We could change the "flags_field" to be a Set over enums, but this would increase the memory footprint notably, and would also slow-down access to flags. Currently, flags operations in javac are very fast and very common, so this is probably too much burden. There are also flags to which we need to access as bit masks, e.g. due to writing to classfile.

My proposal here is to use an intermediate solution, until we find a better solution, or until a better solution is possible (like due to Valhalla). The idea is as follows:
-the current long-based Flags are split into 4 groups:
--"flat" Flags, long based, work exactly as before.
--enum-based TypeSymbolFlags, MethodSymbolFlags and VarSymbolFlags, which are only applicable to TypeSymbols, MethodSymbols and VarSymbols, respectively, and are checked using methods like Symbol.isFlagSet and set/clear using methods Symbol.setFlag and Symbol.clearFlag. So these flags are mostly encapsulated, even though physically they are currently stored in the flags_field as well.

There are ~~37~~ 40 "flat" flags and ~~16~~ 17 TypeSymbolFlags (methods and vars have less flags), 57 in total. This gives us at least 7 new flags before we run out of long bits in flags_field again - but even if we do, there are several easy mitigation strategies we could use, like:
-create a new int/long field on TypeSymbols for the TypeSymbolFlags (probably preferable)
-split TypeSymbolFlags into Class/Package/MethodSymbolFlags

The positives of this solution include:
-safe(r) access to the flags - the access to the extra/symbol-kind-specific flags is mostly encapsulated, and hence mostly safe
-improves the abstractions at least for some flags
-reasonably complex patch (attempts to encapsulate all the flags were troublesome in previous experiments)
-the performances appears to be acceptable.

The negative that I see is that the code includes several incompatible types of flags now. These cannot be easily confused by accident (as the type system will complain), but still we need to be aware of them when writing code.

Some more alternatives:
-add a new field to Symbol, like long extraFlags, and continue with bit masks as we did so far using this new field. The drawback is that it is more error prone (it would be difficult to ensure only the new/extra flags would be stored and read from extraFlags).
-have a new field, and "flat" and non-"flat" enum-based encapsulated Flags, but don't separate Type/Method/Var flags. Probably something to consider, even though I am a bit reluctant to add new fields without trying to avoid it .

Any feedback is welcome!

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

Commit messages:
 - Whitespaces.
 - Cleanup.
 - Merging master into JDK-8241356
 - 8241356: Use a more reliable way to encode Symbol flags

Changes: https://git.openjdk.java.net/jdk/pull/2316/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=2316&range=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8241356
  Stats: 765 lines in 30 files changed: 331 ins; 198 del; 236 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2316.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2316/head:pull/2316

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags

liach
On Fri, 29 Jan 2021 17:31:20 GMT, Jan Lahoda <[hidden email]> wrote:

> [This is a GitHub copy of: https://mail.openjdk.java.net/pipermail/compiler-dev/2020-March/014389.html ]
>
> Currently, (com.sun.tools.javac.code.)Symbol/s have a long field "flags_field", which holds various one-bit information ("Flags") about the given Symbol.
>
> We currently have around 64 such Flags, which means we are out of bits in the long field, and adding new flags is not easy.
>
> We could change the "flags_field" to be a Set over enums, but this would increase the memory footprint notably, and would also slow-down access to flags. Currently, flags operations in javac are very fast and very common, so this is probably too much burden. There are also flags to which we need to access as bit masks, e.g. due to writing to classfile.
>
> My proposal here is to use an intermediate solution, until we find a better solution, or until a better solution is possible (like due to Valhalla). The idea is as follows:
> -the current long-based Flags are split into 4 groups:
> --"flat" Flags, long based, work exactly as before.
> --enum-based TypeSymbolFlags, MethodSymbolFlags and VarSymbolFlags, which are only applicable to TypeSymbols, MethodSymbols and VarSymbols, respectively, and are checked using methods like Symbol.isFlagSet and set/clear using methods Symbol.setFlag and Symbol.clearFlag. So these flags are mostly encapsulated, even though physically they are currently stored in the flags_field as well.
>
> There are ~~37~~ 40 "flat" flags and ~~16~~ 17 TypeSymbolFlags (methods and vars have less flags), 57 in total. This gives us at least 7 new flags before we run out of long bits in flags_field again - but even if we do, there are several easy mitigation strategies we could use, like:
> -create a new int/long field on TypeSymbols for the TypeSymbolFlags (probably preferable)
> -split TypeSymbolFlags into Class/Package/MethodSymbolFlags
>
> The positives of this solution include:
> -safe(r) access to the flags - the access to the extra/symbol-kind-specific flags is mostly encapsulated, and hence mostly safe
> -improves the abstractions at least for some flags
> -reasonably complex patch (attempts to encapsulate all the flags were troublesome in previous experiments)
> -the performances appears to be acceptable.
>
> The negative that I see is that the code includes several incompatible types of flags now. These cannot be easily confused by accident (as the type system will complain), but still we need to be aware of them when writing code.
>
> Some more alternatives:
> -add a new field to Symbol, like long extraFlags, and continue with bit masks as we did so far using this new field. The drawback is that it is more error prone (it would be difficult to ensure only the new/extra flags would be stored and read from extraFlags).
> -have a new field, and "flat" and non-"flat" enum-based encapsulated Flags, but don't separate Type/Method/Var flags. Probably something to consider, even though I am a bit reluctant to add new fields without trying to avoid it .
>
> Any feedback is welcome!

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java line 544:

> 542: //        RECORD(Flags.RECORD),
> 543: //        RECOVERABLE(Flags.RECOVERABLE),
> 544: //>>>>>>> master

This commented out merge conflict stub should be removed.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Jan Lahoda-3
In reply to this post by Jan Lahoda-3
> [This is a GitHub copy of: https://mail.openjdk.java.net/pipermail/compiler-dev/2020-March/014389.html ]
>
> Currently, (com.sun.tools.javac.code.)Symbol/s have a long field "flags_field", which holds various one-bit information ("Flags") about the given Symbol.
>
> We currently have around 64 such Flags, which means we are out of bits in the long field, and adding new flags is not easy.
>
> We could change the "flags_field" to be a Set over enums, but this would increase the memory footprint notably, and would also slow-down access to flags. Currently, flags operations in javac are very fast and very common, so this is probably too much burden. There are also flags to which we need to access as bit masks, e.g. due to writing to classfile.
>
> My proposal here is to use an intermediate solution, until we find a better solution, or until a better solution is possible (like due to Valhalla). The idea is as follows:
> -the current long-based Flags are split into 4 groups:
> --"flat" Flags, long based, work exactly as before.
> --enum-based TypeSymbolFlags, MethodSymbolFlags and VarSymbolFlags, which are only applicable to TypeSymbols, MethodSymbols and VarSymbols, respectively, and are checked using methods like Symbol.isFlagSet and set/clear using methods Symbol.setFlag and Symbol.clearFlag. So these flags are mostly encapsulated, even though physically they are currently stored in the flags_field as well.
>
> There are ~~37~~ 40 "flat" flags and ~~16~~ 17 TypeSymbolFlags (methods and vars have less flags), 57 in total. This gives us at least 7 new flags before we run out of long bits in flags_field again - but even if we do, there are several easy mitigation strategies we could use, like:
> -create a new int/long field on TypeSymbols for the TypeSymbolFlags (probably preferable)
> -split TypeSymbolFlags into Class/Package/MethodSymbolFlags
>
> The positives of this solution include:
> -safe(r) access to the flags - the access to the extra/symbol-kind-specific flags is mostly encapsulated, and hence mostly safe
> -improves the abstractions at least for some flags
> -reasonably complex patch (attempts to encapsulate all the flags were troublesome in previous experiments)
> -the performances appears to be acceptable.
>
> The negative that I see is that the code includes several incompatible types of flags now. These cannot be easily confused by accident (as the type system will complain), but still we need to be aware of them when writing code.
>
> Some more alternatives:
> -add a new field to Symbol, like long extraFlags, and continue with bit masks as we did so far using this new field. The drawback is that it is more error prone (it would be difficult to ensure only the new/extra flags would be stored and read from extraFlags).
> -have a new field, and "flat" and non-"flat" enum-based encapsulated Flags, but don't separate Type/Method/Var flags. Probably something to consider, even though I am a bit reluctant to add new fields without trying to avoid it .
>
> Any feedback is welcome!

Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:

  Removing merge tags are noted on the review - thanks!

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

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2316/files
  - new: https://git.openjdk.java.net/jdk/pull/2316/files/a9c3ff6e..27e37860

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk&pr=2316&range=01
 - incr: https://webrevs.openjdk.java.net/?repo=jdk&pr=2316&range=00-01

  Stats: 7 lines in 1 file changed: 0 ins; 7 del; 0 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2316.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2316/head:pull/2316

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Maurizio Cimadamore-2
On Tue, 2 Feb 2021 16:28:01 GMT, Jan Lahoda <[hidden email]> wrote:

>> [This is a GitHub copy of: https://mail.openjdk.java.net/pipermail/compiler-dev/2020-March/014389.html ]
>>
>> Currently, (com.sun.tools.javac.code.)Symbol/s have a long field "flags_field", which holds various one-bit information ("Flags") about the given Symbol.
>>
>> We currently have around 64 such Flags, which means we are out of bits in the long field, and adding new flags is not easy.
>>
>> We could change the "flags_field" to be a Set over enums, but this would increase the memory footprint notably, and would also slow-down access to flags. Currently, flags operations in javac are very fast and very common, so this is probably too much burden. There are also flags to which we need to access as bit masks, e.g. due to writing to classfile.
>>
>> My proposal here is to use an intermediate solution, until we find a better solution, or until a better solution is possible (like due to Valhalla). The idea is as follows:
>> -the current long-based Flags are split into 4 groups:
>> --"flat" Flags, long based, work exactly as before.
>> --enum-based TypeSymbolFlags, MethodSymbolFlags and VarSymbolFlags, which are only applicable to TypeSymbols, MethodSymbols and VarSymbols, respectively, and are checked using methods like Symbol.isFlagSet and set/clear using methods Symbol.setFlag and Symbol.clearFlag. So these flags are mostly encapsulated, even though physically they are currently stored in the flags_field as well.
>>
>> There are ~~37~~ 40 "flat" flags and ~~16~~ 17 TypeSymbolFlags (methods and vars have less flags), 57 in total. This gives us at least 7 new flags before we run out of long bits in flags_field again - but even if we do, there are several easy mitigation strategies we could use, like:
>> -create a new int/long field on TypeSymbols for the TypeSymbolFlags (probably preferable)
>> -split TypeSymbolFlags into Class/Package/MethodSymbolFlags
>>
>> The positives of this solution include:
>> -safe(r) access to the flags - the access to the extra/symbol-kind-specific flags is mostly encapsulated, and hence mostly safe
>> -improves the abstractions at least for some flags
>> -reasonably complex patch (attempts to encapsulate all the flags were troublesome in previous experiments)
>> -the performances appears to be acceptable.
>>
>> The negative that I see is that the code includes several incompatible types of flags now. These cannot be easily confused by accident (as the type system will complain), but still we need to be aware of them when writing code.
>>
>> Some more alternatives:
>> -add a new field to Symbol, like long extraFlags, and continue with bit masks as we did so far using this new field. The drawback is that it is more error prone (it would be difficult to ensure only the new/extra flags would be stored and read from extraFlags).
>> -have a new field, and "flat" and non-"flat" enum-based encapsulated Flags, but don't separate Type/Method/Var flags. Probably something to consider, even though I am a bit reluctant to add new fields without trying to avoid it .
>>
>> Any feedback is welcome!
>
> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>
>   Removing merge tags are noted on the review - thanks!

Good experiment! I don't mind too much the fact that we have sets of incompatible flags - but while looking at the new Flags.java I noted several flags that looked *kind-specific* which seem to be defined in the *global* bucket. If (as I suspect) this is no accident, then I guess I'm a bit worried that the proposed patch would land us in a state where _some_ var flags are in the VarSymbolFlags enum, but not _all_ of them.

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java line 167:

> 165:     /** Flag for synthesized default constructors of anonymous classes.
> 166:      */
> 167:     public static final int ANONCONSTR   = 1<<27;

Question: why this, and other flags that are specific to only one symbol kind have not been translated into the enum? Other examples are `ANONCONSTR_BASED`, `GENERATEDCONSTR`, `COMPACT_RECORD_CONSTRUCTOR`, `THROWS` and probably more.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Maurizio Cimadamore-2
On Wed, 3 Feb 2021 10:51:28 GMT, Maurizio Cimadamore <[hidden email]> wrote:

>> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>>
>>   Removing merge tags are noted on the review - thanks!
>
> Good experiment! I don't mind too much the fact that we have sets of incompatible flags - but while looking at the new Flags.java I noted several flags that looked *kind-specific* which seem to be defined in the *global* bucket. If (as I suspect) this is no accident, then I guess I'm a bit worried that the proposed patch would land us in a state where _some_ var flags are in the VarSymbolFlags enum, but not _all_ of them.

I'm also worried about where does this leave symbol construction - for instance, in TypeEnter I now see these lines (unchanged in this patch):

params.add(new VarSymbol(
                        GENERATED_MEMBER | PARAMETER | RECORD | (field == lastField && lastIsVarargs ? Flags.VARARGS : 0),
                        field.name, field.sym.type, csym));
 ```

Here, it seems, we are forced to just use a flat flags mask in the constructor - in other words, the new API is only for testing, and there is an asymmetry between construction and testing.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Jan Lahoda-3
On Wed, 3 Feb 2021 10:59:31 GMT, Maurizio Cimadamore <[hidden email]> wrote:

> I'm also worried about where does this leave symbol construction - for instance, in TypeEnter I now see these lines (unchanged in this patch):
>
> ```
> params.add(new VarSymbol(
>                         GENERATED_MEMBER | PARAMETER | RECORD | (field == lastField && lastIsVarargs ? Flags.VARARGS : 0),
>                         field.name, field.sym.type, csym));
> ```
>
> Here, it seems, we are forced to just use a flat flags mask in the constructor - in other words, the new API is only for testing, and there is an asymmetry between construction and testing.

The flat flags work exactly as before (i.e. set as bits and checked as bit masks), and that are these bits set here. Only the symbol-kind specific flags are set and checked using methods, see e.g. the constructor for BindingSymbol.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Jan Lahoda-3
In reply to this post by Maurizio Cimadamore-2
On Wed, 3 Feb 2021 10:43:52 GMT, Maurizio Cimadamore <[hidden email]> wrote:

>> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>>
>>   Removing merge tags are noted on the review - thanks!
>
> src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java line 167:
>
>> 165:     /** Flag for synthesized default constructors of anonymous classes.
>> 166:      */
>> 167:     public static final int ANONCONSTR   = 1<<27;
>
> Question: why this, and other flags that are specific to only one symbol kind have not been translated into the enum? Other examples are `ANONCONSTR_BASED`, `GENERATEDCONSTR`, `COMPACT_RECORD_CONSTRUCTOR`, `THROWS` and probably more.

Some of these (IIRC e.g. GENERATEDCONSTR, ANNONCONSTR) are also set on trees, and read and written as bitmasks, so it is more difficult to separate them to e.g. methods only. A few others could possibly be move with a little more code shuffling.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Maurizio Cimadamore-2
On Wed, 3 Feb 2021 13:26:25 GMT, Jan Lahoda <[hidden email]> wrote:

>> src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java line 167:
>>
>>> 165:     /** Flag for synthesized default constructors of anonymous classes.
>>> 166:      */
>>> 167:     public static final int ANONCONSTR   = 1<<27;
>>
>> Question: why this, and other flags that are specific to only one symbol kind have not been translated into the enum? Other examples are `ANONCONSTR_BASED`, `GENERATEDCONSTR`, `COMPACT_RECORD_CONSTRUCTOR`, `THROWS` and probably more.
>
> Some of these (IIRC e.g. GENERATEDCONSTR, ANNONCONSTR) are also set on trees, and read and written as bitmasks, so it is more difficult to separate them to e.g. methods only. A few others could possibly be move with a little more code shuffling.

I see what you mean - as I said, my worry is that, while this patch addresses the paucity of flags in an effective fashion, the resulting code base end up being worse than it was to begin with, as now a client will have to hunt flags in different enums. If the organization was consistent, I'd have no problem with giving each kind of flag its own enum - but given that the organization is more ad-hoc (e.g. driven by which use cases could be morphed into using enums), I'm unsure.

I mean, what's the advantage of the proposed solution vs. organizing the set of long flags in Flags by categories - so that there's no enum, but so that e.g. a variable symbol flag can reuse the same value as some other method symbol flag?

I think it would deliver same saving, w/o the need to change the flag API. Granted, we also not get any protection for when somebody tries to "merge" flags that are not mergeable - but I'm equally not sure as to whether the proposed solution offers a much more principled alternative?

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Jonathan Gibbons-2
In reply to this post by Jan Lahoda-3
On Tue, 2 Feb 2021 16:28:01 GMT, Jan Lahoda <[hidden email]> wrote:

>> [This is a GitHub copy of: https://mail.openjdk.java.net/pipermail/compiler-dev/2020-March/014389.html ]
>>
>> Currently, (com.sun.tools.javac.code.)Symbol/s have a long field "flags_field", which holds various one-bit information ("Flags") about the given Symbol.
>>
>> We currently have around 64 such Flags, which means we are out of bits in the long field, and adding new flags is not easy.
>>
>> We could change the "flags_field" to be a Set over enums, but this would increase the memory footprint notably, and would also slow-down access to flags. Currently, flags operations in javac are very fast and very common, so this is probably too much burden. There are also flags to which we need to access as bit masks, e.g. due to writing to classfile.
>>
>> My proposal here is to use an intermediate solution, until we find a better solution, or until a better solution is possible (like due to Valhalla). The idea is as follows:
>> -the current long-based Flags are split into 4 groups:
>> --"flat" Flags, long based, work exactly as before.
>> --enum-based TypeSymbolFlags, MethodSymbolFlags and VarSymbolFlags, which are only applicable to TypeSymbols, MethodSymbols and VarSymbols, respectively, and are checked using methods like Symbol.isFlagSet and set/clear using methods Symbol.setFlag and Symbol.clearFlag. So these flags are mostly encapsulated, even though physically they are currently stored in the flags_field as well.
>>
>> There are ~~37~~ 40 "flat" flags and ~~16~~ 17 TypeSymbolFlags (methods and vars have less flags), 57 in total. This gives us at least 7 new flags before we run out of long bits in flags_field again - but even if we do, there are several easy mitigation strategies we could use, like:
>> -create a new int/long field on TypeSymbols for the TypeSymbolFlags (probably preferable)
>> -split TypeSymbolFlags into Class/Package/MethodSymbolFlags
>>
>> The positives of this solution include:
>> -safe(r) access to the flags - the access to the extra/symbol-kind-specific flags is mostly encapsulated, and hence mostly safe
>> -improves the abstractions at least for some flags
>> -reasonably complex patch (attempts to encapsulate all the flags were troublesome in previous experiments)
>> -the performances appears to be acceptable.
>>
>> The negative that I see is that the code includes several incompatible types of flags now. These cannot be easily confused by accident (as the type system will complain), but still we need to be aware of them when writing code.
>>
>> Some more alternatives:
>> -add a new field to Symbol, like long extraFlags, and continue with bit masks as we did so far using this new field. The drawback is that it is more error prone (it would be difficult to ensure only the new/extra flags would be stored and read from extraFlags).
>> -have a new field, and "flat" and non-"flat" enum-based encapsulated Flags, but don't separate Type/Method/Var flags. Probably something to consider, even though I am a bit reluctant to add new fields without trying to avoid it .
>>
>> Any feedback is welcome!
>
> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>
>   Removing merge tags are noted on the review - thanks!

I've reviewed the one javadoc change, and made a comment there. Although I approve the change to that one file, I will leave the review/approval of the javac changes to the javac experts.

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java line 594:

> 592:         } else {
> 593:             ModuleSymbol msym = (ModuleSymbol) me;
> 594:             return msym.isFlagSet(TypeSymbolFlags.AUTOMATIC_MODULE);

The change is OK, but the code being changed is not. There should not be references to any `javac.code.*` types outside of the `WorkArounds` class.  Ideally, this function (`isAutomaticModule`) should be on the `Elements` class.

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

PR: https://git.openjdk.java.net/jdk/pull/2316
Reply | Threaded
Open this post in threaded view
|

Re: RFR: 8241356: Use a more reliable way to encode Symbol flags [v2]

Jonathan Gibbons-2
On Fri, 12 Feb 2021 00:12:07 GMT, Jonathan Gibbons <[hidden email]> wrote:

>> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>>
>>   Removing merge tags are noted on the review - thanks!
>
> src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Extern.java line 594:
>
>> 592:         } else {
>> 593:             ModuleSymbol msym = (ModuleSymbol) me;
>> 594:             return msym.isFlagSet(TypeSymbolFlags.AUTOMATIC_MODULE);
>
> The change is OK, but the code being changed is not. There should not be references to any `javac.code.*` types outside of the `WorkArounds` class.  Ideally, this function (`isAutomaticModule`) should be on the `Elements` class.

FYI, PR 2537 will move this code to the `Workarounds` class.

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

PR: https://git.openjdk.java.net/jdk/pull/2316