Skip to content

8345826: [DO NOT MERGE] Do not automatically resolve jdk.internal.vm.ci when libgraal is used #23408

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

Closed
wants to merge 9 commits into from

Conversation

dougxc
Copy link
Member

@dougxc dougxc commented Feb 1, 2025

JVMCI is currently incompatible with -XX:+AOTClassLinking as the CDS optimizations under this flag require use of the CDS archived module graph. Since -XX:+EnableJVMCI extends the default root module set, the CDS archived module graph is disabled. This will result in slower start-up time when -XX:+UseGraalJIT is enabled (since -XX:+UseGraalJIT implies -XX:+EnableJVMCI).

A work-around suggested by @iklam is to run with "-Xshare:dump --add-modules=jdk.internal.vm.ci -XX:+AOTClassLinking", but then the resulting CDS archive cannot be used when UseGraalJIT is disabled.

The EnableJVMCI flag serves 2 purposes:

  • Guards VM code (example).
  • Adds jdk.internal.vm.ci to the root module set.

This PR changes nothing about the first point.

On the second point, to use the jdk.internal.vm.ci module, it must now be explicitly added with --add-modules=jdk.internal.vm.ci, which will also set EnableJVMCI as a side-effect.

Replaced by #25240
Replaces #23289.


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-8345826: Do not automatically resolve jdk.internal.vm.ci when libgraal is used (Enhancement - P3)

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 23408

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

Using diff file

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

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 1, 2025

👋 Welcome back dnsimon! 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 Feb 1, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Feb 1, 2025

@dougxc The following labels will be automatically applied to this pull request:

  • core-libs
  • graal
  • hotspot

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

@openjdk openjdk bot added graal graal-dev@openjdk.org hotspot hotspot-dev@openjdk.org core-libs core-libs-dev@openjdk.org labels Feb 1, 2025
@dougxc dougxc force-pushed the ds/remove-EnableJVMCI-flag branch from dbfac0f to d43bdd6 Compare February 1, 2025 12:43
@bridgekeeper
Copy link

bridgekeeper bot commented Mar 29, 2025

@dougxc This pull request has been inactive for more than 8 weeks and will be automatically closed if another 8 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@openjdk
Copy link

openjdk bot commented Apr 23, 2025

@dougxc this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout ds/remove-EnableJVMCI-flag
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added the merge-conflict Pull request has merge conflict with target branch label Apr 23, 2025
@dougxc dougxc changed the title remove EnableJVMCI flag 8345826: Do not automatically resolve jdk.internal.vm.ci when libgraal is used Apr 25, 2025
@dougxc dougxc force-pushed the ds/remove-EnableJVMCI-flag branch from d43bdd6 to c4f083c Compare April 28, 2025 17:00
@openjdk openjdk bot removed the merge-conflict Pull request has merge conflict with target branch label Apr 28, 2025
Copy link
Member

@iklam iklam left a comment

Choose a reason for hiding this comment

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

Have you done any benchmarking? Since the unconditionally enabled code are only in i2c adapters and deopt entries, the impact should be minimal?

@@ -1225,6 +1225,9 @@ nmethod* nmethod::new_nmethod(const methodHandle& method,
DEBUG_ONLY(nm->verify();)
nm->log_new_nmethod();
}
#if INCLUDE_JVMCI
JVMCI::installed_code();
Copy link
Member

Choose a reason for hiding this comment

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

JVMCI::set_has_installed_code() would be clearer.

if (status && UseJVMCICompiler && FLAG_IS_DEFAULT(UseJVMCINativeLibrary) && !UseJVMCINativeLibrary) {
if (!JVMCI::shared_library_exists() && ClassLoader::is_module_observable("jdk.internal.vm.ci")) {
// If no JVMCI native library is present,
// we enable the JVMCI module by default.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe the comment should explain who uses the JVMCI module? Is it used by jar graal?

Copy link
Member

Choose a reason for hiding this comment

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

Also, I see that you have modified the tests to say --add-modules=jdk.internal.vm.ci -XX:+UseJVMCICompiler. Shouldn't we leave the responsibility to the user for adding the module, and avoid hard-coding this into HotSpot?

Comment on lines 2757 to 2764
} else if (match_option(option, "-XX:+EnableJVMCI")) {
jio_fprintf(defaultStream::error_stream(),
"-XX:+EnableJVMCI was removed in JDK 25. Use --add-modules=jdk.internal.vm.ci to make use of the JVMCI module.\n");
return JNI_EINVAL;
} else if (match_option(option, "-XX:-EnableJVMCI")) {
jio_fprintf(defaultStream::error_stream(),
"-XX:-EnableJVMCI was removed in JDK 25.\n");
return JNI_EINVAL;
Copy link
Member

Choose a reason for hiding this comment

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

Since EnableJVMCI is an experimental flag, it should be removed by the "2 step" model. It should be entered in special_jvm_flags[] in arguments.cpp as obsoleted in JDK 25.

* To remove internal options (e.g. diagnostic, experimental, develop options), use
* a 2-step model adding major release numbers to the obsolete and expire columns.

@@ -30,7 +30,6 @@
* @test id=static
* @requires vm.cds.supports.aot.class.linking
* @comment work around JDK-8345635
Copy link
Member

Choose a reason for hiding this comment

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

The * @comment work around JDK-8345635 lines should also be removed from all the CDS tests.

@iklam
Copy link
Member

iklam commented Apr 29, 2025

Is it possible to limit the scope of the HotSpot changes by simply removing the addition of the jdk.internal.vm.ci module, but do not otherwise change EnableJVMCI?

@dougxc
Copy link
Member Author

dougxc commented May 2, 2025

Is it possible to limit the scope of the HotSpot changes by simply removing the addition of the jdk.internal.vm.ci module, but do not otherwise change EnableJVMCI?

This means Truffle users will need to add --add-modules=jdk.internal.vm.ci as the Truffle runtime requires jarjvmci to be able to communicate with libgraal. @chumer I think going this path makes some sense. Once JVMCI becomes non-experimental and enabled by default (i.e. when EnableJVMCI is removed altogether), this option will be required anyway as jdk.internal.vm.ci will never become part of the default root module set. What do you think?

@dougxc
Copy link
Member Author

dougxc commented May 3, 2025

@iklam based on your comment here, adding JVMCI to the AOT cache is visible from an application perspective. For example, ModuleLayer.boot().modules().stream().anyMatch(m -> m.getName().equals("jdk.internal.vm.ci")) will produce true. What would it take for the AOT cache to contain the pre-loaded resources in jdk.internal.vm.ci but not put it in the root set unless --add-modules=jdk.internal.vm.ci is explicitly added? I suspect "too much" state is cached for this to be easily done but wanted to double check.

@iklam
Copy link
Member

iklam commented May 5, 2025

@iklam based on your comment here, adding JVMCI to the AOT cache is visible from an application perspective. For example, ModuleLayer.boot().modules().stream().anyMatch(m -> m.getName().equals("jdk.internal.vm.ci")) will produce true. What would it take for the AOT cache to contain the pre-loaded resources in jdk.internal.vm.ci but not put it in the root set unless --add-modules=jdk.internal.vm.ci is explicitly added? I suspect "too much" state is cached for this to be easily done but wanted to double check.

AOT doesn't keep track of how a resource (e.g., a classfile) is loaded. It relies on the module system to only provide the classfiles that are visible when the AOT cache is being assembled. So it will take a lot of effort to implement what you are suggesting.

Anyway, I think the fundamental problem is libgraal doesn't need jdk.internal.vm.ci, but it makes it available anyway. As a result, real Java programs that need jdk.internal.vm.ci will be able to use it without asking properly (either by declaring in requires in their module-info class, or by the command-line option --add-modules=jdk.internal.vm.ci).

Therefore, I don't think it's a good idea for the AOT cache to try to support a behavior that's in itself not correct.

The right thing to do is to remove the unnecessary module addition in arguments.cpp, and change the Java apps so they ask for the modules that they depend on.

@chumer
Copy link
Member

chumer commented May 5, 2025

Is it possible to limit the scope of the HotSpot changes by simply removing the addition of the jdk.internal.vm.ci module, but do not otherwise change EnableJVMCI?

This means Truffle users will need to add --add-modules=jdk.internal.vm.ci as the Truffle runtime requires jarjvmci to be able to communicate with libgraal. @chumer I think going this path makes some sense. Once JVMCI becomes non-experimental and enabled by default (i.e. when EnableJVMCI is removed altogether), this option will be required anyway as jdk.internal.vm.ci will never become part of the default root module set. What do you think?

This will be breaking for Truffle users who currently rely on EnableJVMCI to enable both the jdk.internal.vm.ci module and the native JVMCI module. How about we add an option EnableJVMCINative that does only enable the native module. This would preserve behaviour for Truffle users (and others like TornadoVM). EnableJVMCI and UseGraalJIT can forward to EnableJVMCINative.

I think it would be alright if we also enable native JVMCI with --add-modules=jdk.internal.vm.ci but as far as I understand this is difficult to do. But maybe that assumption is wrong?

So options:
A) Introduce EnableJVMCINative
B) Make --add-modules=jdk.internal.vm.ci also enable native JVMCI.

@dougxc
Copy link
Member Author

dougxc commented May 5, 2025

will be able to use it without asking properly

Depends on what you mean by properly. Since jdk.internal.vm.ci only has qualified exports, --add-exports is still required.

So options:
A) Introduce EnableJVMCINative
B) Make --add-modules=jdk.internal.vm.ci also enable native JVMCI.

Under both these options, running jargraal will now require --add-modules=jdk.internal.vm.ci (which sounds reasonable). Before considering them in depth, do you think B is even possible @iklam ?

@iklam
Copy link
Member

iklam commented May 5, 2025

will be able to use it without asking properly

Depends on what you mean by properly. Since jdk.internal.vm.ci only has qualified exports, --add-exports is still required.

So options:
A) Introduce EnableJVMCINative
B) Make --add-modules=jdk.internal.vm.ci also enable native JVMCI.

Under both these options, running jargraal will now require --add-modules=jdk.internal.vm.ci (which sounds reasonable). Before considering them in depth, do you think B is even possible @iklam ?

B seems doable (some parsing will be required in arguments.cpp: if jdk.internal.vm.ci is found to be added, we can ergonomically enable EnableJVMCI).

I've looked at the options inside jvmci_globals.hpp and it's hard to understand what each option is used for. As a result, I don't know what impact we have for all the options we discussed.

Before we decide on an action plan, can we first make a table that list all the uses cases, and the requirements for each case.

E.g.,

Use case    | How to use| requirements
------------+-----------+-----------------------------------
libgraal    | [A]       | native JVMCI only
jargraal    | [B]       | native JVMCI + jdk.internal.vm.ci
Truffle     | [C]       | ???


[A] = jdk24/bin/java -XX:+UnlockExperimentalVMOptions -XX:+UseGraalJIT
[B] = ??
[C] = ??

Also, how does one use jargraal or Truffle? Any example? Are these possible with the Oracle JDK, or do you need GraalVM for JDK?

@dougxc
Copy link
Member Author

dougxc commented May 5, 2025

Good idea.

Here's the current situation:

Use case Flags Requirements Comments
libgraal -XX:+UseGraalJIT native JVMCI Default if $JAVA_HOME/lib/libjvmcicompiler.so exists
jargraal -XX:+UseGraalJIT native JVMCI + jdk.internal.vm.ci Default if $JAVA_HOME/lib/libjvmcicompiler.so does not exist
Truffle -XX:+EnableJVMCI native JVMCI + jdk.internal.vm.ci Uses C2 as JIT, libgraal/jargraal only for Truffle compilations
Truffle -XX:+UseGraalJIT native JVMCI + jdk.internal.vm.ci Uses libgraal/jargraal as JIT and for Truffle compilations

Under proposal A (i.e. introduce EnableJVMCINative):

Use case Flags Requirements Comments (augments above)
libgraal -XX:+UseGraalJIT native JVMCI UseGraalJIT sets EnableJVMCINative
jargraal -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle -XX:+EnableJVMCI native JVMCI + jdk.internal.vm.ci EnableJVMCI sets EnableJVMCINative
Truffle -XX:+UseGraalJIT -XX:+EnableJVMCI native JVMCI + jdk.internal.vm.ci UseGraalJIT sets EnableJVMCINative

Under proposal B (i.e. EnableJVMCI enables native JVMCI and --add-modules=jdk.internal.vm.ci sets EnableJVMCI):

Use case Flags Requirements Comments (augments above)
libgraal -XX:+UseGraalJIT native JVMCI VM aborts if $JAVA_HOME/lib/libjvmcicompiler.so does not exist
jargraal -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci

Note: -XX:+UnlockExperimentalVMOptions is required for all above cases so is omitted for brevity. Also, jargraal is only intended for development as it's easier to debug than libgraal. Ease of use is only important for libgraal.

@iklam
Copy link
Member

iklam commented May 5, 2025

Good idea.

Here's the current situation:

Use case Flags Requirements Comments
libgraal -XX:+UseGraalJIT native JVMCI Default if $JAVA_HOME/lib/libjvmcicompiler.so exists
jargraal -XX:+UseGraalJIT native JVMCI + jdk.internal.vm.ci Default if $JAVA_HOME/lib/libjvmcicompiler.so does not exist
Truffle -XX:+EnableJVMCI native JVMCI + jdk.internal.vm.ci Uses C2 as JIT, libgraal/jargraal only for Truffle compilations
Truffle -XX:+UseGraalJIT native JVMCI + jdk.internal.vm.ci Uses libgraal/jargraal as JIT and for Truffle compilations
Under proposal A (i.e. introduce EnableJVMCINative):

Use case Flags Requirements Comments (augments above)
libgraal -XX:+UseGraalJIT native JVMCI UseGraalJIT sets EnableJVMCINative
jargraal -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle -XX:+EnableJVMCI native JVMCI + jdk.internal.vm.ci EnableJVMCI sets EnableJVMCINative
Truffle -XX:+UseGraalJIT native JVMCI + jdk.internal.vm.ci UseGraalJIT sets EnableJVMCINative
Under proposal B (i.e. EnableJVMCI enables native JVMCI and --add-modules=jdk.internal.vm.ci sets EnableJVMCI):

Use case Flags Requirements Comments (augments above)
libgraal -XX:+UseGraalJIT native JVMCI VM aborts if $JAVA_HOME/lib/libjvmcicompiler.so does not exist
jargraal -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Truffle -XX:+UseGraalJIT --add-modules=jdk.internal.vm.ci native JVMCI + jdk.internal.vm.ci
Note: -XX:+UnlockExperimentalVMOptions is required for all above cases so is omitted for brevity. Also, jargraal is only intended for development as it's easier to debug than libgraal. Ease of use is only important for libgraal.

For Proposal A, I think we should have this for the 4th row:

Truffle "-XX:+EnableJVMCI -XX:+UseGraalJIT"

Since both proposal A and B would require changes for Truffle users (which is not unreasonable because EnableJVMCI is an experimental flag, subject to change), I think it's better to go with B, where each party declare its own dependencies:

  • Truffe says: I depend on jdk.internal.vm.ci
  • jdk.internal.vm.ci says: I need to turn on the EnableJVMCI variable inside HotSpot

However, B would require more changes in the test cases. Some of the -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI flags would need to be replaced with --add-modules=jdk.internal.vm.ci .

@dougxc
Copy link
Member Author

dougxc commented May 6, 2025

For Proposal A, I think we should have this for the 4th row:

You're right - I fixed it in situ.

Since both proposal A and B would require changes for Truffle users (which is not unreasonable because EnableJVMCI is an experimental flag, subject to change), I think it's better to go with B, where each party declare its own dependencies:

Sounds reasonable to me. Once @chumer signs off on B, I'll start to look at implementing it.

However, B would require more changes in the test cases. Some of the -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI flags would need to be replaced with --add-modules=jdk.internal.vm.ci.

I think we're always going to need -XX:+UnlockExperimentalVMOptions until JVMCI is no longer experimental.

@chumer
Copy link
Member

chumer commented May 6, 2025

Once @chumer signs off on B, I'll start to look at implementing it.

I think B is alright.

One issue is that users who switch between JDK versions need to use both old and new ways of configuring truffle, at least in the time between when we still support both JDK versions. But I think multi-JDK-version users should be fine if they set both -XX:+EnableJVMCI and --add-modules=jdk.internal.vm.ci right?

@dougxc
Copy link
Member Author

dougxc commented May 6, 2025

should be fine if they set both -XX:+EnableJVMCI and --add-modules=jdk.internal.vm.ci right?

yes

@dougxc
Copy link
Member Author

dougxc commented May 13, 2025

I've pushed a commit for Proposal B.

I still need to figure out how to deal with the fact that jtreg puts --add-modules=jdk.internal.vm.ci on the command line for a test that specifies @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot. The problem is how to reconcile this with the requirement for -XX:+UnlockExperimentalVMOptions to precede --add-modules=jdk.internal.vm.ci.

@dougxc
Copy link
Member Author

dougxc commented May 14, 2025

I've pushed a commit for Proposal B.

I still need to figure out how to deal with the fact that jtreg puts --add-modules=jdk.internal.vm.ci on the command line for a test that specifies @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot. The problem is how to reconcile this with the requirement for -XX:+UnlockExperimentalVMOptions to precede --add-modules=jdk.internal.vm.ci.

The options I see are:

  1. Make JVMCI non-experimental.
  2. Allow --add-modules=jdk.internal.vm.ci to unlock EnableJVMCI without needing -XX:+UnlockExperimentalVMOptions:
index 5d23b03996f..40a2c75ef9f 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -2255,7 +2255,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin
       char after  = *(jvmci_module + strlen("jdk.internal.vm.ci"));
       if ((before == '=' || before == ',') && (after == '\0' || after == ',')) {
         if (!_jvmci_module_added) {
+            bool unlock_state = UnlockExperimentalVMOptions;
+            UnlockExperimentalVMOptions = true;
           bool valid = process_argument("+EnableJVMCI", args->ignoreUnrecognized, origin);
+            UnlockExperimentalVMOptions = unlock_state;
           if (!valid) {
             jio_fprintf(defaultStream::error_stream(),
               "'EnableJVMCI' implied by jdk.internal.vm.ci module in '%s'\n", option->optionString);

Are there other options I'm missing @iklam ?

@dougxc dougxc force-pushed the ds/remove-EnableJVMCI-flag branch 4 times, most recently from 5cf594f to f088f6e Compare May 14, 2025 16:36
@dougxc dougxc force-pushed the ds/remove-EnableJVMCI-flag branch from f088f6e to 2bc72fb Compare May 14, 2025 19:14
@dougxc
Copy link
Member Author

dougxc commented May 14, 2025

Closing this PR in favor of #25240.

@dougxc dougxc closed this May 14, 2025
@dougxc dougxc changed the title 8345826: Do not automatically resolve jdk.internal.vm.ci when libgraal is used 8345826: [DO NOT MERGE] Do not automatically resolve jdk.internal.vm.ci when libgraal is used May 14, 2025
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 graal graal-dev@openjdk.org hotspot hotspot-dev@openjdk.org
Development

Successfully merging this pull request may close these issues.

3 participants