Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8306075: Micro-optimize Enum.hashCode #13491

Closed
wants to merge 4 commits into from

Conversation

olivergillespie
Copy link
Contributor

@olivergillespie olivergillespie commented Apr 17, 2023

Improve the speed of Enum.hashCode by caching the identity hashcode on first use. I've seen an application where Enum.hashCode is a hot path, and this is fairly simple speedup. The memory overhead is low; in enums with no extra fields there is already a 4-byte space due to alignment so this new field can slot in 'for free'. In other cases, the singleton nature of enum values means that the number of total instances is typically very low, so a small per-instance overhead is not a concern.

Please see more discussion/explanation in the original enhancement request. [Benchmark results and generated code analysis moved to comment]

Thanks @shipilev for help with the implementation and interpreting the generated code.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

Reviewers

Contributors

  • Aleksey Shipilev <shade@openjdk.org>

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/13491/head:pull/13491
$ git checkout pull/13491

Update a local copy of the PR:
$ git checkout pull/13491
$ git pull https://git.openjdk.org/jdk.git pull/13491/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 13491

View PR using the GUI difftool:
$ git pr show -t 13491

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/13491.diff

Webrev

Link to Webrev Comment

@olivergillespie
Copy link
Contributor Author

/contributor add @shipilev

@bridgekeeper
Copy link

bridgekeeper bot commented Apr 17, 2023

👋 Welcome back olivergillespie! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk openjdk bot added the rfr Pull request is ready for review label Apr 17, 2023
@openjdk
Copy link

openjdk bot commented Apr 17, 2023

@olivergillespie
Contributor Aleksey Shipilev <shade@openjdk.org> successfully added.

@openjdk
Copy link

openjdk bot commented Apr 17, 2023

@olivergillespie The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Apr 17, 2023
@mlbridge
Copy link

mlbridge bot commented Apr 17, 2023

Webrevs

* The hash code of this enumeration constant.
*
* @implNote Once initialized, the field value does not change.
* Hotspot's identity hash code generation also never returns zero
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hotspot's identity hash code generation also never returns zero

Isn't that behavior VM-specific? Also, where is it documented?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is implementation-specific, that is why it says "Hotspot's identity hash code". The relevant code blocks are

bool has_no_hash() const {
return hash() == no_hash;
}
(property) and
if (value == 0) value = 0xBAD;
assert(value != markWord::no_hash, "invariant");
(invariant).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would not break the code functionally if that invariant ever breaks: we would "just" call the (intrinsic) method on zero hash code. That implNote only shows that it would not happen with current implementation at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From that impl note it seemed like it was a big deal for hash code to never return 0 for an object. Could you maybe de-emphasize the importance of that HotSpot behavior in the note?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right, we can change "This allows to treat zero as the marker..." to "This makes zero a convenient marker...", I think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, the proposed implementation looks similar to that of String::hashCode before Compact Strings (JEP 254).

The interesting detail here is the fact that unlike String::hashCode, which can legitimately return 0, Object::hashCode cannot, at least in HotSpot. This is great news, because to be performant, java.lang.Enum does not need to be bloated with extra mechanics, such as that boolean hashIsZero introduced for java.lang.String in 8221836: Avoid recalculating String.hash when zero.

If the essence of that can be compressed to a few simple sentences and possibly moved to an inline comment in Enum::hashCode, that might be better.

return super.hashCode();
int hc = hash;
if (hc == 0) {
hc = hash = System.identityHashCode(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not hc = hash = super.hashCode()?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saves the virtual call, makes for a simpler intrinsic path (no need to handle NPE and fold away, for example), since we know the super-class is already java.lang.Object. Unless I miss something else here...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t invokespecial produce a non‑virtual call as well?

And this/super can never be null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super.hashCode() is a virtual call. System.identityHashCode is the static call. I don't understand where invokespecial enters the picture here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invokespecial is used to call instance methods in a non‑virtual manner.


Using super.hashCode() in java.lang.Enum produces the bytecode:

aload_0;
invokespecial java/lang/Object.hashCode:()I;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It does not matter here, because for performance, we largely only care about the distinction between virtual/static cases in C2 intrinsic for hashcode.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also fyi invokespecial now can be virtual calls (mainly calling private methods in the nest) since introduction of nestmates.

* initialization code.
*/
@Stable
private int hash;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that transient is not needed here, as per https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/serial-arch.html#serialization-of-enum-constants

The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form.

@cl4es
Copy link
Member

cl4es commented Apr 17, 2023

Why isn't Enum::hashCode simply doing return ordinal;?

@olivergillespie
Copy link
Contributor Author

Why isn't Enum::hashCode simply doing return ordinal;?

See https://bugs.openjdk.org/browse/JDK-8050217

@cl4es
Copy link
Member

cl4es commented Apr 17, 2023

Why isn't Enum::hashCode simply doing return ordinal;?

See https://bugs.openjdk.org/browse/JDK-8050217

Thanks! If there are apps where Enum::hashCode is performance sensitive then run-to-run stability may be a stronger argument than @stuart-marks et al argues it is here, though there might be some unspoken arguments about how it might affect iteration order et.c...

Adding a cached field to Enum seem innocuous though, whether it disappears into a padding gap or not.

@openjdk
Copy link

openjdk bot commented Apr 17, 2023

@olivergillespie Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information.

@openjdk
Copy link

openjdk bot commented Apr 17, 2023

@olivergillespie This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8306075: Micro-optimize Enum.hashCode

Co-authored-by: Aleksey Shipilev <shade@openjdk.org>
Reviewed-by: redestad, shade, rriggs, liach, apangin, jvernee

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 78 new commits pushed to the master branch:

  • fdaabd6: 8306581: JVMCI tests failed when run with -XX:TypeProfileLevel=222 after JDK-8303431
  • 36ec05d: 8306430: Open source some AWT tests related to TextComponent and Toolkit
  • 8346ae2: 8305942: Open source several AWT Focus related tests
  • 9a68d1d: 8306060: Open source few AWT Insets related tests
  • 2c70828: 8305236: Some LoadLoad barriers in the interpreter are unnecessary after JDK-8220051
  • ffb2494: 8305207: Calendar.aggregateStamp(int, int) return value can be simplified
  • 174c1a6: 4737887: (cal) API: Calendar methods taking field should document exceptions
  • f633623: 8306474: Move InstanceKlass read-only flags
  • afd2501: 8306482: Remove unused Method AccessFlags
  • d6cf4aa: 8305874: Open source AWT Key, Text Event related tests
  • ... and 68 more: https://git.openjdk.org/jdk/compare/2a062f165491d599eb0dcfb6050eb9186ae31b71...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

As you do not have Committer status in this project an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@cl4es, @shipilev, @RogerRiggs, @JornVernee) but any other Committer may sponsor as well.

➡️ To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Apr 17, 2023
* initialization code.
*/
@Stable
private int hash;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not we hide the field from reflection?

I understand this is an implementation detail, however, it makes a big difference that you add a private field to the public class that is meant to be inherited by user classes. Although I'm not aware of a particular example, this can be a breaking change for user code that does introspection on enums.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this a big difference? It's only discovered by getDeclaredFields. This can only be modified if users break jdk internal encapsulation in command line, which means they can change everything else.

* for the un-initialized value for both {#link @Stable} and the lazy
* HotSpot's identity hash code generation also never returns zero
* as the identity hash code. This makes zero a convenient marker
* for the un-initialized value for both {@link @Stable} and the lazy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, but @Stable won't work with @link. @Stable is not a class, interface, member name, etc. See https://docs.oracle.com/en/java/javase/20/docs/specs/javadoc/doc-comment-spec.html#references

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @implNote is more appropriate for an internal comment. It is not needed to be in the published javadoc; its only useful to someone viewing the source code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @implNote is more appropriate for an internal comment. It is not needed to be in the published javadoc; its only useful to someone viewing the source code.

Is it a comment to me or to the author? If it's the former, then I note, that if one bothers to mark up a comment, that markup should be valid.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this to be an non-javadoc comment. (Change /** to /*)
An there is no need for javadoc \implNote or @link javadoc markup.
There is very little value in being able to generate javadoc for --private.
(In part because most private implementations are not documented to javadoc standards).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is a bit strange to see @implNote here as this is a private field that isn't going to show up in the javadoc. The javadoc for non-transient fields in Serializable classes does show up in the Serialized Form page but this Enum which is special.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, so I'll switch to a /* comment with no markup?

Copy link
Member

@shipilev shipilev Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Existing private fields, name and ordinal use Javadoc-style /** comment. New field should use /** to match the style. The only thing that we might want is to move implementation discussion into the method body, like this:

    /**
     * The hash code of this enumeration constant.
     */
    @Stable
    private int hash;

    /**
     * Returns a hash code for this enum constant.
     *
     * @return a hash code for this enum constant.
     */
    public final int hashCode() {
        // Once initialized, the hash field value does not change.
        // HotSpot's identity hash code generation also never returns zero
        // as the identity hash code. This makes zero a convenient marker
        // for the un-initialized value for both @Stable and the lazy
        // initialization code below.

        int hc = hash;
        if (hc == 0) {
            hc = hash = System.identityHashCode(this);
        }
        return hc;
    }

@RogerRiggs
Copy link
Contributor

Can the detailed explanation be moved to a comment. The full description from the PR is included in every email and it makes it inconvenient to find the continuing comments.

@olivergillespie
Copy link
Contributor Author

(Moving benchmark results and generated code analysis here from PR description as requested.)

Benchmark

Before:

Benchmark              Mode  Cnt  Score   Error  Units
# Intel Cascade lake
EnumHashCode.constant  avgt   15  1.602 ± 0.011  ns/op
EnumHashCode.field     avgt   15  1.681 ± 0.014  ns/op
# Arm Neoverse N1
EnumHashCode.constant  avgt   15  1.642 ± 0.033  ns/op
EnumHashCode.field     avgt   15  1.717 ± 0.059  ns/op

After:

Benchmark              Mode  Cnt  Score   Error  Units
# Intel Cascade lake
EnumHashCode.constant  avgt   15  0.479 ± 0.001  ns/op
EnumHashCode.field     avgt   15  0.799 ± 0.002  ns/op
# Arm Neoverse N1
EnumHashCode.constant  avgt   15  0.802 ± 0.002  ns/op
EnumHashCode.field     avgt   15  1.059 ± 0.056  ns/op

Using -prof perfasm on the benchmark, we can compare the generated code for x86_64:

Before:

│ 0x00007fae4868dd17:   lea    (%r12,%r10,8),%rsi           ;*getfield e {reexecute=0 rethrow=0 return_oop=0}
│                                                           ; - org.sample.EnumHashCode::field@1 (line 24)
│                                                           ; - org.sample.jmh_generated.EnumHashCode_field_jmhTest::field_avgt_jmhStub@17 (line 186)
│ 0x00007fae4868dd1b:   mov    (%rsi),%r10
│ 0x00007fae4868dd1e:   mov    %r10,%r11
│ 0x00007fae4868dd21:   and    $0x3,%r11
│ 0x00007fae4868dd25:   cmp    $0x1,%r11
│ 0x00007fae4868dd29:   jne    0x00007fae4868dcc6
│ 0x00007fae4868dd2b:   shr    $0x8,%r10
│ 0x00007fae4868dd2f:   mov    %r10d,%eax
│ 0x00007fae4868dd32:   and    $0x7fffffff,%eax
│ 0x00007fae4868dd37:   test   %eax,%eax
│ 0x00007fae4868dd39:   je     0x00007fae4868dcc6           ;*invokespecial hashCode {reexecute=0 rethrow=0 return_oop=0}
│                                                           ; - java.lang.Enum::hashCode@1 (line 175)

This is the normal Object.hashCode intrinsic, which involves reading the object header, extracting the hash code and handling two slow-path cases (displaced object header, hash not initialized).

After:

  │  0x00007f550068e3b4:   mov    0x10(%r12,%r10,8),%r8d  <-- read the hash field
  │  0x00007f550068e3b9:   test   %r8d,%r8d               <-- if (hash == 0)
  │  0x00007f550068e3bc:   je     0x00007f550068e413      <-- slow init path, only taken on first use

@@ -166,13 +168,29 @@ public final boolean equals(Object other) {
return this==other;
}

/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be /** (Javadoc style), like other private fields.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the reviewers are fine with the essence of this PR. As for the comment, we could split it in two: the javadoc part, which stays with the field, and the inline part, which moves to the method. See String.hash and String::hashCode.

Copy link
Member

@shipilev shipilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay with this new version, thanks. (You need other commenters to approve as well.)

@pavelrappo
Copy link
Member

I am okay with this new version, thanks. (You need other commenters to approve as well.)

While there's already one more reviewer who approved this PR (@cl4es) and technically it can be already integrated, I'd leave it for a day or two so that other Reviewers could see it too.

Copy link
Contributor

@RogerRiggs RogerRiggs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for moving the explanation to the method. :)

@JornVernee
Copy link
Member

JornVernee commented Apr 17, 2023

Why isn't Enum::hashCode simply doing return ordinal;?

See https://bugs.openjdk.org/browse/JDK-8050217

Thanks! If there are apps where Enum::hashCode is performance sensitive then run-to-run stability may be a stronger argument than @stuart-marks et al argues it is here, though there might be some unspoken arguments about how it might affect iteration order et.c...

Identity hash code might theoretically be stable from run-to-run, but it's not like it's very stable in the first place. The hash code is generated using some thread-local state, so the value depends on how many times an identity hash code has been generated on the same thread before the hash code of the enum constant is generated (when hashCode is first called)

So, using ordinal as a hash code would, AFAICS, be no more unstable than the current implementation: if the code is altered (re-ordering the constants. Or calling hashCode for the first time at a different point in the application), the identity hash code can change. However, using the ordinal has the benefit of simplicity as well. (if anything, using the ordinal would be more stable, since it is only affected by the order of the constants, rather than by other code that runs before the identity hash code is generated).

@rose00
Copy link
Contributor

rose00 commented Apr 17, 2023

I don’t have a strong objection to this, but I would like to say for the record that it is likely we will want to reconsider enums in a larger sense after Valhalla starts to ship.

Specifically, if an enum is represented as a value object, it should be represented as a single ordinal value after flattening. This means both the old name and the new hash fields should not be present in a value-class version of an enum; they should be computed by using the ordinal as a key into some other table or algorithm.

In the long-running discussion about enum hash codes I added a comment here FTR:

https://bugs.openjdk.org/browse/JDK-8050217?focusedCommentId=14574367&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14574367

This sketches in more detail what I mean by deriving the hash from the ordinal and the class. These suggestions may be of interest to people looking at this RFE. But I am not suggesting a change to this RFE.

I do have one comment: Since identity hash codes are typically reasonably well-conditioned, it is perfectly reasonable to recondition an occasional 0 by replacing it with 1, in order to store it in a stable variable for later reuse. (Those hash codes are not so well-conditioned that that one tweak would cause quality tests to go from green to red; a test that could detect the tweak would already be red.) But it’s also harmless to leave it as zero; it just means you will occasionally see a failure of constant folding.

@shipilev
Copy link
Member

I do have one comment: Since identity hash codes are typically reasonably well-conditioned, it is perfectly reasonable to recondition an occasional 0 by replacing it with 1, in order to store it in a stable variable for later reuse.

As comment in the code change says, this is already handled on Hotspot side:

if (value == 0) value = 0xBAD;
assert(value != markWord::no_hash, "invariant");
-- if only to disambiguate the "unset" IHC in the object header. So the stars have already aligned well for us to use 0 as uninitialized marker!

@shipilev
Copy link
Member

(if anything, using the ordinal would be more stable, since it is only affected by the order of the constants, rather than by other code that runs before the identity hash code is generated).

Here lies the major original concern -- that I share -- about hooking up ordinal as hashCode, I think. It opens up enum for the similar sort of algorithmic collisions, perhaps even deliberate ones, like we had with String-s. Arguably, switching enum hashcode from IHC to ordinal is a step backwards.

Of course, as John says above, this might change when Valhalla arrives, but in that case we would give up the collision-resistant enum hashcodes for clear benefit of enums being flattened: it would be the "one step back, two steps forward" kind of deal. Today, however, there seem to be to reason to give up this resistance without getting anything in return. The "return" might have been better performance, but this PR eliminates that part as well.

@viktorklang-ora
Copy link
Contributor

@shipilev @rose00 Yes, ideally hashCode of enums should only depend on type + ordinal—as I presume that it is desirable that different enums of different types but bearing the same ordinal values shouldn't collide when mixed in a HashMap<Enum,Object>.

Given "on the wire" representation the information regarding type would either need to be out-of-bound or transmitted as a part of the value.

In such a case, would it not be "better" to base the HC on getClass().getName().hashCode() which is specced and stable mixed with the ordinal to improve distribution over the 32-bit space?

@shipilev
Copy link
Member

shipilev commented Apr 18, 2023

In such a case, would it not be "better" to base the HC on getClass().getName().hashCode() which is specced and stable mixed with the ordinal to improve distribution over the 32-bit space?

Maybe, even though it still raises lots of collision-resistance questions, given that both String (class) name and ordinal are constructable, and have hash codes that are easy to collide. Anyhow, I strongly believe this goes way beyond the scope of this PR.

@shipilev
Copy link
Member

@AlanBateman, @apangin, @ExE-Boss, @liach, @pavelrappo -- you had comments on this PR, could you please see if those are still relevant or not addressed? If you are good with the current version, can you please formally approve the PR? Thanks!

Copy link
Member

@liach liach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the poke Aleksey. I have been pleased with this patch; my comments were simply to dismiss the concerns about the behavior under reflection and to clarify that an invokespecial may be virtual since the introduction of private overrides with nest mates.

@pavelrappo
Copy link
Member

@AlanBateman, @apangin, @ExE-Boss, @liach, @pavelrappo -- you had comments on this PR, could you please see if those are still relevant or not addressed? If you are good with the current version, can you please formally approve the PR? Thanks!

Don't mind me: I had minor, mostly unrelated comments.

@olivergillespie
Copy link
Contributor Author

Thanks for all the comments so far. If there are no outstanding concerns, I'll integrate this tomorrow.

@JornVernee
Copy link
Member

I've also started a tier 1-4 run of this patch on our CI. Will report back with the results.

Copy link
Member

@JornVernee JornVernee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also started a tier 1-4 run of this patch on our CI. Will report back with the results.

All green

@olivergillespie
Copy link
Contributor Author

/integrate

@openjdk openjdk bot added the sponsor Pull request is ready to be sponsored label Apr 21, 2023
@openjdk
Copy link

openjdk bot commented Apr 21, 2023

@olivergillespie
Your change (at version 21882c1) is now ready to be sponsored by a Committer.

@shipilev
Copy link
Member

/sponsor

@openjdk
Copy link

openjdk bot commented Apr 21, 2023

Going to push as commit 3da987a.
Since your change was applied there have been 78 commits pushed to the master branch:

  • fdaabd6: 8306581: JVMCI tests failed when run with -XX:TypeProfileLevel=222 after JDK-8303431
  • 36ec05d: 8306430: Open source some AWT tests related to TextComponent and Toolkit
  • 8346ae2: 8305942: Open source several AWT Focus related tests
  • 9a68d1d: 8306060: Open source few AWT Insets related tests
  • 2c70828: 8305236: Some LoadLoad barriers in the interpreter are unnecessary after JDK-8220051
  • ffb2494: 8305207: Calendar.aggregateStamp(int, int) return value can be simplified
  • 174c1a6: 4737887: (cal) API: Calendar methods taking field should document exceptions
  • f633623: 8306474: Move InstanceKlass read-only flags
  • afd2501: 8306482: Remove unused Method AccessFlags
  • d6cf4aa: 8305874: Open source AWT Key, Text Event related tests
  • ... and 68 more: https://git.openjdk.org/jdk/compare/2a062f165491d599eb0dcfb6050eb9186ae31b71...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Apr 21, 2023
@openjdk openjdk bot closed this Apr 21, 2023
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review sponsor Pull request is ready to be sponsored labels Apr 21, 2023
@openjdk
Copy link

openjdk bot commented Apr 21, 2023

@shipilev @olivergillespie Pushed as commit 3da987a.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@olivergillespie olivergillespie deleted the 8306075 branch April 21, 2023 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org integrated Pull request has been integrated