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
8301578: Perform output outside synchronization in Module.class #12193
Conversation
👋 Welcome back pminborg! A progress list of the required criteria for merging this PR into |
The potential performance improvement in determining if native access is enabled is a small part of the overall benchmarks in the
|
Webrevs
|
} | ||
} | ||
} | ||
} | ||
|
||
private static boolean casEnableNativeAccess(Module target) { |
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 change looks okay but the naming is a bit misleading, maybe trySetEnableNativeAccess would be better, as this isn't an Unsafe/VarHandler compareAndSet. Also would be possible to add a comment to the method so it's consistent with the existing methods.
BTW: Is this PR meant by openjdk/jdk20 or openjdk/jdk? Does it really address a startup issue or not? |
I can't quite see the effect of the change here. You went from a synchronized instance method, to a non-synchronized static method which then immediately synchronizes on the passed in instance. ?? That aside I'm not sure what the synchronization issues are here - isn't setting the native access bit an idempotent operation? |
@minborg Have you used the wrong JBS issue by any chance? There is no information in the JBS issue, or here, that the proposed change fixes the reported startup regression after the JEP 434 integration and maybe this is a drive-by cleanup while investigating the startup issue? |
} | ||
|
||
private static boolean isNativeAccessEnabled(Module target) { | ||
if (target.enableNativeAccess) |
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.
@minborg It'd seem a bit easier to implement using VarHandle and not having to use synchronized
? Is the reason that you don't want to init VarHandle in this class? 🤔
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.
It is a bootstrap problem. We cannot use AtomicBoolean, VarHandle or Unsafe here.
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.
Shouldn’t Unsafe
already be loaded at this point?
Let me take a step back here and explain the reason why I think this PR is worth looking at. Firstly, I think the argument that this might not solve https://bugs.openjdk.org/browse/JDK-8300917 is perfectly valid. Therefore, I have filed a separate issue and linked this PR to this. Thanks for pointing this out. This PR is more like a drive-by cleanup as mentioned. Back to the contents of the PR. My fear (which may or may not be substantiated) is that if we perform operations via the relatively slow
Again, this might not be the case in reality but I think removing the risk is worthwhile. |
} else { | ||
if (trySetEnableNativeAccess(target)) { | ||
// warn and set flag, so that only one warning is reported per module | ||
String cls = owner.getName(); | ||
String mtd = cls + "::" + methodName; | ||
String mod = isNamed() ? "module " + getName() : "the unnamed module"; | ||
String modflag = isNamed() ? getName() : "ALL-UNNAMED"; | ||
System.err.printf(""" | ||
WARNING: A restricted method in %s has been called | ||
WARNING: %s has been called by %s | ||
WARNING: Use --enable-native-access=%s to avoid a warning for this module | ||
%n""", cls, mtd, mod, modflag); | ||
|
||
// set the flag | ||
target.enableNativeAccess = true; | ||
WARNING: A restricted method in %s has been called | ||
WARNING: %s has been called by %s | ||
WARNING: Use --enable-native-access=%s to avoid a warning for this module | ||
%n""", cls, mtd, mod, modflag); | ||
} | ||
} |
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 else
and if
blocks can be merged:
} else { | |
if (trySetEnableNativeAccess(target)) { | |
// warn and set flag, so that only one warning is reported per module | |
String cls = owner.getName(); | |
String mtd = cls + "::" + methodName; | |
String mod = isNamed() ? "module " + getName() : "the unnamed module"; | |
String modflag = isNamed() ? getName() : "ALL-UNNAMED"; | |
System.err.printf(""" | |
WARNING: A restricted method in %s has been called | |
WARNING: %s has been called by %s | |
WARNING: Use --enable-native-access=%s to avoid a warning for this module | |
%n""", cls, mtd, mod, modflag); | |
// set the flag | |
target.enableNativeAccess = true; | |
WARNING: A restricted method in %s has been called | |
WARNING: %s has been called by %s | |
WARNING: Use --enable-native-access=%s to avoid a warning for this module | |
%n""", cls, mtd, mod, modflag); | |
} | |
} | |
} else if (trySetEnableNativeAccess(target)) { | |
// warn and set flag, so that only one warning is reported per module | |
String cls = owner.getName(); | |
String mtd = cls + "::" + methodName; | |
String mod = isNamed() ? "module " + getName() : "the unnamed module"; | |
String modflag = isNamed() ? getName() : "ALL-UNNAMED"; | |
System.err.printf(""" | |
WARNING: A restricted method in %s has been called | |
WARNING: %s has been called by %s | |
WARNING: Use --enable-native-access=%s to avoid a warning for this module | |
%n""", cls, mtd, mod, modflag); | |
} |
} | ||
|
||
private static boolean isNativeAccessEnabled(Module target) { | ||
if (target.enableNativeAccess) |
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.
Shouldn’t Unsafe
already be loaded at this point?
By putting |
// Accessing this variable is made through Unsafe in order to use the | ||
// memory semantics that preserves ordering and visibility across threads. | ||
// | ||
// Used reflectively via Unsafe |
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 assume L119-120 can be removed.
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 reson for the L119-120 comments is to make it easier to understand why we are declaring a variable that does not appear to be used. But maybe there is a better way to do that?
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 comment at L117-118 already explains that it's accessed with Unsafe so I don't think we need any more than that. The IDE may suggest the field is unused but if anyone removes it then it will break the JDK build/startup. Same thing many other areas where Unsafe or VarHandles are used. So I don't think we should be too concerned about and the comments at L116-118 are more than enough.
@@ -124,8 +129,7 @@ public final class Module implements AnnotatedElement { | |||
Module(ModuleLayer layer, | |||
ClassLoader loader, | |||
ModuleDescriptor descriptor, | |||
URI uri) | |||
{ | |||
URI uri) { |
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.
This seems a spurious edit, not sure if you meant to change it.
* | ||
* @throws SecurityException | ||
* If denied by the security manager | ||
* @throws SecurityException If denied by the security manager |
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 exception messages are aligned under the exceptions in this class so I assume you didn't mean to change this.
@@ -229,7 +230,7 @@ public ModuleDescriptor getDescriptor() { | |||
/** | |||
* Returns the module layer that contains this module or {@code null} if | |||
* this module is not in a module layer. | |||
* | |||
* <p> |
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.
This will break up the first paragraph, I don't think this PR should be changing that.
private AccessHolder() {} | ||
|
||
private static final Unsafe UNSAFE = Unsafe.getUnsafe(); | ||
private static final long FIELD_OFFSET = UNSAFE.objectFieldOffset(Module.class, "enableNativeAccess"); |
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.
Using Unsafe and CAS'ing the enableNativeAccess field looks okay. The name "AccessHolder" looks too general here as there is a lot of access going on in this class, maybe NativeAccessHolder will work.
It would be good if you could try to keep changes to this code consistent with the existing style if possible. In this case, the other inner class uses /** .. */ style comment for the class description. I think would I put the constants at the top of the this class.
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 think this is a good cleanup overall.
// Accessing this variable is made through Unsafe in order to use the | ||
// memory semantics that preserves ordering and visibility across threads. | ||
// | ||
// Used reflectively via Unsafe |
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 comment at L117-118 already explains that it's accessed with Unsafe so I don't think we need any more than that. The IDE may suggest the field is unused but if anyone removes it then it will break the JDK build/startup. Same thing many other areas where Unsafe or VarHandles are used. So I don't think we should be too concerned about and the comments at L116-118 are more than enough.
* This class is used to be able to bootstrap without using Unsafe | ||
* in the outer Module class as that would create a circular initializer dependency. | ||
*/ | ||
private static final class EnableNativeAccessHandler { |
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 see this has been renamed EnableNativeAccessHandler, maybe drop "Handler" as it just sets the enableNativeAccess bit, nothing more.
@minborg 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:
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 270 new commits pushed to the
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 |
/integrate |
Going to push as commit c25b4f4.
Your commit was automatically rebased without conflicts. |
This PR proposed to reduce contention in synchronized methods mainly by doing I/O operations outside synch blocks.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/12193/head:pull/12193
$ git checkout pull/12193
Update a local copy of the PR:
$ git checkout pull/12193
$ git pull https://git.openjdk.org/jdk pull/12193/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 12193
View PR using the GUI difftool:
$ git pr show -t 12193
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/12193.diff