-
Couldn't load subscription status.
- Fork 6.1k
8355369: Remove setAccessible usage for setting final fields in java.util.concurrent #24821
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,7 +35,9 @@ | |
|
|
||
| package java.util.concurrent; | ||
|
|
||
| import java.lang.reflect.Field; | ||
| import jdk.internal.misc.Unsafe; | ||
|
|
||
| import java.lang.invoke.VarHandle; | ||
| import java.util.AbstractSet; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
|
|
@@ -176,6 +178,8 @@ public ConcurrentSkipListSet<E> clone() { | |
| ConcurrentSkipListSet<E> clone = | ||
| (ConcurrentSkipListSet<E>) super.clone(); | ||
| clone.setMap(new ConcurrentSkipListMap<E,Object>(m)); | ||
| // Needed to ensure safe publication of setMap() | ||
| VarHandle.releaseFence(); | ||
| return clone; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new InternalError(); | ||
|
|
@@ -527,12 +531,11 @@ public Spliterator<E> spliterator() { | |
|
|
||
| /** Initializes map field; for use in clone. */ | ||
| private void setMap(ConcurrentNavigableMap<E,Object> map) { | ||
| try { | ||
| Field mapField = ConcurrentSkipListSet.class.getDeclaredField("m"); | ||
| mapField.setAccessible(true); | ||
| mapField.set(this, map); | ||
| } catch (IllegalAccessException | NoSuchFieldException e) { | ||
| throw new Error(e); | ||
| } | ||
| final Unsafe U = Unsafe.getUnsafe(); | ||
| U.putReference( | ||
| this, | ||
| U.objectFieldOffset(ConcurrentSkipListSet.class, "m"), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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". There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| map | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
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. 👍
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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
headis not cleared upon clone, but seems immediately replaced later inbuildFromSorted). Both should still be fine with this new return values.There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.