Skip to content

Conversation

@viktorklang-ora
Copy link
Contributor

@viktorklang-ora viktorklang-ora commented Apr 23, 2025

This Pull Request replaces the uses of Field + setAccessible to modify final fields in java.util.concurrent with Unsafe.


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

  • JDK-8355369: Remove setAccessible usage for setting final fields in java.util.concurrent (Enhancement - P4)

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 24821

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

Using diff file

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

Using Webrev

Link to Webrev Comment

…ceArray to use Unsafe rather than Field.setAccessible
@bridgekeeper
Copy link

bridgekeeper bot commented Apr 23, 2025

👋 Welcome back vklang! 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
Copy link

openjdk bot commented Apr 23, 2025

@viktorklang-ora 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:

8355369: Remove setAccessible usage for setting final fields in java.util.concurrent

Reviewed-by: pminborg, dl, rgiulietti, alanb

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 40 new commits pushed to the master branch:

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.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk
Copy link

openjdk bot commented Apr 23, 2025

@viktorklang-ora 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 core-libs core-libs-dev@openjdk.org rfr Pull request is ready for review labels Apr 23, 2025
@mlbridge
Copy link

mlbridge bot commented Apr 23, 2025

Webrevs

final Unsafe U = Unsafe.getUnsafe();
U.putReference(
this,
U.objectFieldOffset(ConcurrentSkipListSet.class, "m"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to compute the offset once and for all and put it in a static final long field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I originally did that, but the following patch is the "smallest change".
Given that the "original code" obtained the Field instance each call, this is still likely a performance improvement.

Copy link
Contributor

Choose a reason for hiding this comment

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

This code has always used getDeclaredField each time so if anyone had run into a performance issue then we should have heard by now. So I think keeping the changes simple and just moving to Unsafe is okay for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fine. The main effect of this change is to nearly revert to the pre-VarHandle version of this code.

@liach
Copy link
Member

liach commented Apr 23, 2025

Seems these are used mainly for cloning: is it possible for us to just use readResolve to resolve an alternative object?

@viktorklang-ora
Copy link
Contributor Author

@liach Not sure I understand, could you elaborate a bit?

@rgiulietti
Copy link
Contributor

I guess the intent is just to have the minimal patch to come away from setAccessible().

@AlanBateman
Copy link
Contributor

I guess the intent is just to have the minimal patch to come away from setAccessible().

It's to move away from using Field.set to mutate non-static final fields. Viktor offered to get this done before the "prepare for final means final" changes.

@liach
Copy link
Member

liach commented Apr 23, 2025

@liach Not sure I understand, could you elaborate a bit?

I mean that we call the setters in readObject methods. If we can instead call readResolve to provide safely constructed objects from constructors, that may be better, but since we are looking at marshalling guess we will not touch serialization.

@rgiulietti
Copy link
Contributor

@viktorklang-ora Before approving, what is the status of the copyright notices? There seem to be no years to update...

(ConcurrentSkipListSet<E>) super.clone();
clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
// Needed to ensure safe publication of setMap()
VarHandle.releaseFence();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DougLea This might be interesting to you. 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we could just change it to return new ConcurrentSkipListSet<>(m). COWAL could be changed to return a new object too.

Copy link
Member

Choose a reason for hiding this comment

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

The set only has a map field, and AbstractSet does not define any additional field. The map should be fine too - two fields in AbstractMap are cleared when cloning happens, so recreating a map from a constructor should have the same effect. (Note a significant field head is not cleared upon clone, but seems immediately replaced later in buildFromSorted). Both should still be fine with this new return values.

Copy link
Contributor

Choose a reason for hiding this comment

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

As others have mentioned, clone() needs to be re-checked wrt issuing final field fences. But can be conservatively done so here anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DougLea Yeah. I'd be surprised if clone()-invocations were specially tracked to get a trailing release fence inserted before handing out the instance.

@viktorklang-ora
Copy link
Contributor Author

@rgiulietti These are the JSR166 files, so I didn't touch the copyright notices.

@AlanBateman
Copy link
Contributor

AlanBateman commented Apr 23, 2025

Seems these are used mainly for cloning: is it possible for us to just use readResolve to resolve an alternative object?

Potentially AtomicReferenceArray.readObject could be replaced, the others are clone methods.

@liach
Copy link
Member

liach commented Apr 23, 2025

Thanks. We can investigate how clone cleanups interact with truly final or strict finals in another issue.

@viktorklang-ora
Copy link
Contributor Author

@liach @AlanBateman My proposal here would be to move forward with the proposed changes for now, and then once 25 is branched off there's an opportunity to take a broader look at clone().

Copy link
Contributor

@minborg minborg left a comment

Choose a reason for hiding this comment

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

I think these changes look good. Before we integrate, could you please raise an issue with the future improvements of clone() and friends so that we do not forget that?

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Apr 24, 2025
(ConcurrentSkipListSet<E>) super.clone();
clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
// Needed to ensure safe publication of setMap()
VarHandle.releaseFence();
Copy link
Contributor

Choose a reason for hiding this comment

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

As others have mentioned, clone() needs to be re-checked wrt issuing final field fences. But can be conservatively done so here anyway.

Copy link
Contributor

@rgiulietti rgiulietti left a comment

Choose a reason for hiding this comment

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

LGTM

@AlanBateman
Copy link
Contributor

@liach @AlanBateman My proposal here would be to move forward with the proposed changes for now, and then once 25 is branched off there's an opportunity to take a broader look at clone().

Okay with me. We can also add a non-public constructor to some of these classes and use it from readResolve so that we don't need readObject methods that mutate finals.

@viktorklang-ora
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented Apr 24, 2025

Going to push as commit 356c4d9.
Since your change was applied there have been 43 commits pushed to the master branch:

Your commit was automatically rebased without conflicts.

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

openjdk bot commented Apr 24, 2025

@viktorklang-ora Pushed as commit 356c4d9.

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

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

Development

Successfully merging this pull request may close these issues.

6 participants