From 1627836e0e822875ead864fff82bd5f5eeb2429e Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 1 Jul 2025 13:25:16 +0200 Subject: [PATCH 1/3] Polyglot version check in HotSpotTruffleRuntimeAccess still accepts JDK-21. --- .../src/com/oracle/svm/truffle/TruffleBaseFeature.java | 4 ++++ .../oracle/truffle/runtime/OptimizedTruffleRuntime.java | 7 +++++-- .../runtime/hotspot/HotSpotTruffleRuntimeAccess.java | 6 ------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 85cae200402c..44b0f0cf2b85 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -182,6 +182,10 @@ private static MethodHandle findVersionGetComponent() { } private static final String NATIVE_IMAGE_FILELIST_FILE_NAME = "native-image-resources.filelist"; + /** + * When modifying the version values defined below, ensure that the corresponding version fields + * in {@code OptimizedTruffleRuntime} are also updated accordingly to maintain consistency. + */ private static final Version NEXT_POLYGLOT_VERSION_UPDATE = Version.create(29, 1); private static final int MAX_JDK_VERSION = 29; diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java index 7573f0d39dc2..8071e1d84018 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java @@ -168,8 +168,11 @@ public abstract class OptimizedTruffleRuntime implements TruffleRuntime, TruffleCompilerRuntime { private static final int JAVA_SPECIFICATION_VERSION = Runtime.version().feature(); - public static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2); - public static final int MIN_JDK_VERSION = 21; + /** + * When modifying the version values defined below, ensure that the corresponding version fields + * in {@code TruffleBaseFeature} are also updated accordingly to maintain consistency. + */ + public static final int MIN_JDK_VERSION = 25; public static final int MAX_JDK_VERSION = 29; public static final Version NEXT_VERSION_UPDATE = Version.create(29, 1); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 2b829a301bf2..cb38d62e2aec 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -41,7 +41,6 @@ package com.oracle.truffle.runtime.hotspot; import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MAX_JDK_VERSION; -import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MIN_COMPILER_VERSION; import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MIN_JDK_VERSION; import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.NEXT_VERSION_UPDATE; @@ -169,11 +168,6 @@ protected static TruffleRuntime createRuntime() { Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. Update the org.graalvm.polyglot versions to at least '%s' to resolve this. """, Runtime.version(), compilerVersion, truffleVersion, compilerVersion)); - } else if (compilerVersion.compareTo(MIN_COMPILER_VERSION) < 0) { - return new DefaultTruffleRuntime(formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - Update the Java runtime to the latest update release of JDK '%d'. - """, Runtime.version(), compilerVersion, truffleVersion, jdkFeatureVersion)); } } } else { From e17d792d84ee1552b75dd990c45660df4c8539c0 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 7 Jul 2025 16:11:26 +0200 Subject: [PATCH 2/3] Added common Truffle version support. --- .../truffle-runtime/native-image.properties | 1 + .../runtime/OptimizedTruffleRuntime.java | 8 - .../oracle/truffle/runtime/VersionCheck.java | 279 ++++++++++++++++++ .../truffle/runtime/VersionCheckFeature.java | 70 +++++ .../hotspot/HotSpotTruffleRuntimeAccess.java | 137 +-------- 5 files changed, 357 insertions(+), 138 deletions(-) create mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java create mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java diff --git a/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties b/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties index 29978d3da4f3..84192775e4ca 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties +++ b/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties @@ -2,6 +2,7 @@ ForceOnModulePath = org.graalvm.truffle.runtime Args = --macro:truffle-svm \ --features=com.oracle.svm.truffle.TruffleFeature \ --features=com.oracle.svm.truffle.TruffleJFRFeature \ + --features=com.oracle.truffle.runtime.VersionCheckFeature \ -H:MaxRuntimeCompileMethods=2500 JavaArgs = -Dtruffle.TruffleRuntime=com.oracle.svm.truffle.api.SubstrateTruffleRuntime \ diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java index 8071e1d84018..81e557524b66 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java @@ -71,7 +71,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.home.Version; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.options.OptionCategory; import org.graalvm.options.OptionDescriptor; @@ -168,13 +167,6 @@ public abstract class OptimizedTruffleRuntime implements TruffleRuntime, TruffleCompilerRuntime { private static final int JAVA_SPECIFICATION_VERSION = Runtime.version().feature(); - /** - * When modifying the version values defined below, ensure that the corresponding version fields - * in {@code TruffleBaseFeature} are also updated accordingly to maintain consistency. - */ - public static final int MIN_JDK_VERSION = 25; - public static final int MAX_JDK_VERSION = 29; - public static final Version NEXT_VERSION_UPDATE = Version.create(29, 1); /** * Used only to reset state for native image compilation. diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java new file mode 100644 index 000000000000..9fbc7ad18f41 --- /dev/null +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.runtime; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.compiler.TruffleCompilationSupport; +import com.oracle.truffle.polyglot.PolyglotImpl; +import org.graalvm.home.Version; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; + +/** + * Provides support for verifying compatibility between the Truffle API, Truffle compiler, and + * Truffle SubstrateVM feature versions. + */ +public final class VersionCheck { + + private static final int MIN_JDK_VERSION = 21; + private static final int MAX_JDK_VERSION = 29; + private static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2); + private static final Version NEXT_VERSION_UPDATE = Version.create(29, 1); + + private VersionCheck() { + } + + /** + * Verifies that the Truffle feature is compatible with the current Truffle runtime version. + * + * @return a string describing the incompatibility, or {@code null} if the check passes. + */ + static String checkSVMVersion() { + if (isVersionCheck()) { + Version truffleAPIVersion = getTruffleVersion(); + Version truffleMajorMinorVersion = stripUpdateVersion(truffleAPIVersion); + Version truffleSVMVersion = getSVMFeatureVersion(); + Version truffleSVMMajorMinorVersion = stripUpdateVersion(truffleSVMVersion); + if (truffleSVMVersion.compareTo(NEXT_VERSION_UPDATE) >= 0) { + throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); + } else if (truffleSVMMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { + // no forward compatibility + return formatVersionWarningMessage(""" + Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. + Update the org.graalvm.polyglot versions to at least '%s' to resolve this. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, truffleSVMVersion); + } else if (Runtime.version().feature() < MIN_JDK_VERSION) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. + The Java runtime version must be greater or equal to JDK '%d'. + Update your Java runtime to resolve this. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, MIN_JDK_VERSION); + } else if (truffleSVMVersion.compareTo(MIN_COMPILER_VERSION) < 0) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the Java runtime to the latest update release of JDK '%d'. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, Runtime.version().feature()); + } + } + return null; + } + + /** + * Verifies that the LibGraal compiler is compatible with the current Truffle runtime version. + * + * @return a string describing the incompatibility, or {@code null} if the check passes. + */ + public static String checkLibGraalCompilerVersion(TruffleCompilationSupport compilationSupport) { + if (isVersionCheck()) { + Version truffleVersion = getTruffleVersion(); + if (truffleVersion.compareTo(NEXT_VERSION_UPDATE) >= 0) { + throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); + } + Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); + Version compilerVersion = getCompilerVersion(compilationSupport); + Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); + int jdkFeatureVersion = Runtime.version().feature(); + if (jdkFeatureVersion < MIN_JDK_VERSION || jdkFeatureVersion >= MAX_JDK_VERSION) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + The Java runtime version must be greater or equal to JDK '%d' and smaller than JDK '%d'. + Update your Java runtime to resolve this. + """, Runtime.version(), compilerVersion, truffleVersion, MIN_JDK_VERSION, MAX_JDK_VERSION); + } else if (compilerMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { + /* + * Forward compatibility is supported only for minor updates, not for major + * releases. + */ + return formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the org.graalvm.polyglot versions to at least '%s' to resolve this. + """, Runtime.version(), compilerVersion, truffleVersion, compilerVersion); + } else if (compilerVersion.compareTo(MIN_COMPILER_VERSION) < 0) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the Java runtime to the latest update release of JDK '%d'. + """, Runtime.version(), compilerVersion, truffleVersion, jdkFeatureVersion); + } + } + return null; + } + + /** + * Verifies that the JarGraal compiler is compatible with the current Truffle runtime version. + * + * @return a string describing the incompatibility, or {@code null} if the check passes. + */ + public static String checkJarGraalCompilerVersion(TruffleCompilationSupport compilationSupport) { + if (isVersionCheck()) { + String jvmciVersionCheckError = verifyJVMCIVersion(compilationSupport.getClass()); + if (jvmciVersionCheckError != null) { + return jvmciVersionCheckError; + } + Version truffleVersion = getTruffleVersion(); + Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); + Version compilerVersion = getCompilerVersion(compilationSupport); + Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); + if (!compilerMajorMinorVersion.equals(truffleMajorMinorVersion)) { + return formatVersionWarningMessage(""" + The Graal compiler version '%s' is incompatible with polyglot version '%s'. + Update the compiler version to '%s' to resolve this. + """, compilerVersion, truffleVersion, truffleVersion); + } + } + return null; + } + + /** + * Determines whether version checks are currently enabled. + */ + private static boolean isVersionCheck() { + return !Boolean.getBoolean("polyglotimpl.DisableVersionChecks"); + } + + /** + * Reads reflectively the org.graalvm.truffle module version. The method uses reflection to + * access the {@code PolyglotImpl#TRUFFLE_VERSION} field because the Truffle API may be of a + * version earlier than graalvm-23.1.2 where the field does not exist. + * + * @return the Truffle API version or 23.1.1 if the {@code PolyglotImpl#TRUFFLE_VERSION} field + * does not exist. + */ + private static Version getTruffleVersion() { + try { + Field versionField = PolyglotImpl.class.getDeclaredField("TRUFFLE_VERSION"); + versionField.setAccessible(true); + return Version.parse((String) versionField.get(null)); + } catch (NoSuchFieldException nf) { + return Version.create(23, 1, 1); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + + /** + * Retrieves the compiler version from the provided {@link TruffleCompilationSupport} instance + * using reflection. If the method is unavailable, a fallback version of 23.1.1 is returned. + */ + private static Version getCompilerVersion(TruffleCompilationSupport compilationSupport) { + /* + * The TruffleCompilationSupport is present in both the maven artifact + * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The + * JDK version of TruffleCompilationSupport may be outdated and lack the getCompilerVersion + * method. To address this, we use reflection. + */ + String compilerVersionString = null; + try { + Method getCompilerVersion = compilationSupport.getClass().getMethod("getCompilerVersion"); + compilerVersionString = (String) getCompilerVersion.invoke(compilationSupport); + } catch (NoSuchMethodException noMethod) { + // pass with compilerVersionString set to null + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + return compilerVersionString != null ? Version.parse(compilerVersionString) : Version.create(23, 1, 1); + } + + /** + * Triggers verification of JVMCI. + */ + private static String verifyJVMCIVersion(Class hotspotCompilationSupport) { + /* + * The TruffleCompilationSupport is present in both the maven artifact + * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The + * JDK version of TruffleCompilationSupport may be outdated and lack the verifyJVMCIVersion + * method. To address this, we use reflection. + */ + String errorMessage = null; + try { + Method verifyJVMCIVersion = hotspotCompilationSupport.getDeclaredMethod("verifyJVMCIVersion"); + errorMessage = (String) verifyJVMCIVersion.invoke(null); + } catch (NoSuchMethodException noMethod) { + // pass with result set to true + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + return errorMessage; + } + + /** + * Reads the version of the Truffle feature. + */ + private static Version getSVMFeatureVersion() { + InputStream in = VersionCheckFeature.class.getClassLoader().getResourceAsStream("META-INF/graalvm/org.graalvm.truffle.runtime.svm/version"); + if (in == null) { + throw CompilerDirectives.shouldNotReachHere("Truffle native image feature must have a version file."); + } + try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + return Version.parse(r.readLine()); + } catch (IOException ioe) { + throw CompilerDirectives.shouldNotReachHere(ioe); + } + } + + private static Version stripUpdateVersion(Version version) { + int major = version.getComponent(0); + int minor = version.getComponent(1); + if (major == 0 && minor == 0) { + /* + * Version represents a pure snapshot version without any numeric component. + */ + return version; + } else { + return Version.create(major, minor); + } + } + + private static String formatVersionWarningMessage(String errorFormat, Object... args) { + StringBuilder errorMessage = new StringBuilder("Version check failed.\n"); + errorMessage.append(String.format(errorFormat, args)); + errorMessage.append(""" + To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used. + It is not recommended to disable version checks. + """); + return errorMessage.toString(); + } +} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java new file mode 100644 index 000000000000..69c8299644aa --- /dev/null +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.runtime; + +import org.graalvm.nativeimage.hosted.Feature; + +import java.io.PrintStream; + +public final class VersionCheckFeature implements Feature { + + @Override + public String getURL() { + return "https://github.com/oracle/graal/tree/master/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java"; + } + + @Override + public String getDescription() { + return "Ensures compatibility between the Truffle optimized runtime and the native-image builder"; + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + String result = VersionCheck.checkSVMVersion(); + if (result != null) { + // GR-67329: Exceptions thrown by features do not include their error messages in the + // native-image output + PrintStream out = System.err; + out.printf("[%s] %s", getClass().getName(), result); + throw new IllegalStateException(result); + } + } +} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index cb38d62e2aec..97220c648f44 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -40,23 +40,15 @@ */ package com.oracle.truffle.runtime.hotspot; -import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MAX_JDK_VERSION; -import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MIN_JDK_VERSION; -import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.NEXT_VERSION_UPDATE; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Set; import java.util.function.Consumer; -import org.graalvm.home.Version; - import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.TruffleRuntimeAccess; import com.oracle.truffle.api.impl.DefaultTruffleRuntime; import com.oracle.truffle.compiler.TruffleCompilationSupport; -import com.oracle.truffle.polyglot.PolyglotImpl; import com.oracle.truffle.runtime.ModulesSupport; +import com.oracle.truffle.runtime.VersionCheck; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraal; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraalTruffleCompilationSupport; @@ -144,31 +136,9 @@ protected static TruffleRuntime createRuntime() { if (LibGraal.isAvailable()) { // try LibGraal compilationSupport = new LibGraalTruffleCompilationSupport(); - if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) { - Version truffleVersion = getTruffleVersion(); - if (truffleVersion.compareTo(NEXT_VERSION_UPDATE) >= 0) { - throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); - } - Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); - Version compilerVersion = getCompilerVersion(compilationSupport); - Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); - int jdkFeatureVersion = Runtime.version().feature(); - if (jdkFeatureVersion < MIN_JDK_VERSION || jdkFeatureVersion >= MAX_JDK_VERSION) { - return new DefaultTruffleRuntime(formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - The Java runtime version must be greater or equal to JDK '%d' and smaller than JDK '%d'. - Update your Java runtime to resolve this. - """, Runtime.version(), compilerVersion, truffleVersion, MIN_JDK_VERSION, MAX_JDK_VERSION)); - } else if (compilerMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { - /* - * Forward compatibility is supported only for minor updates, not for major - * releases. - */ - return new DefaultTruffleRuntime(formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - Update the org.graalvm.polyglot versions to at least '%s' to resolve this. - """, Runtime.version(), compilerVersion, truffleVersion, compilerVersion)); - } + String result = VersionCheck.checkLibGraalCompilerVersion(compilationSupport); + if (result != null) { + return new DefaultTruffleRuntime(result); } } else { // try jar graal @@ -182,21 +152,9 @@ protected static TruffleRuntime createRuntime() { ModulesSupport.addExports(compilerModule, pkg, runtimeModule); Class hotspotCompilationSupport = Class.forName(compilerModule, pkg + ".HotSpotTruffleCompilationSupport"); compilationSupport = (TruffleCompilationSupport) hotspotCompilationSupport.getConstructor().newInstance(); - if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) { - String jvmciVersionCheckError = verifyJVMCIVersion(hotspotCompilationSupport); - if (jvmciVersionCheckError != null) { - return new DefaultTruffleRuntime(jvmciVersionCheckError); - } - Version truffleVersion = getTruffleVersion(); - Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); - Version compilerVersion = getCompilerVersion(compilationSupport); - Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); - if (!compilerMajorMinorVersion.equals(truffleMajorMinorVersion)) { - return new DefaultTruffleRuntime(formatVersionWarningMessage(""" - The Graal compiler version '%s' is incompatible with polyglot version '%s'. - Update the compiler version to '%s' to resolve this. - """, compilerVersion, truffleVersion, truffleVersion)); - } + String result = VersionCheck.checkJarGraalCompilerVersion(compilationSupport); + if (result != null) { + return new DefaultTruffleRuntime(result); } } catch (ReflectiveOperationException e) { throw new InternalError(e); @@ -216,19 +174,6 @@ protected static TruffleRuntime createRuntime() { return rt; } - private static Version stripUpdateVersion(Version version) { - int major = version.getComponent(0); - int minor = version.getComponent(1); - if (major == 0 && minor == 0) { - /* - * Version represents a pure snapshot version without any numeric component. - */ - return version; - } else { - return Version.create(major, minor); - } - } - private static void registerVirtualThreadMountHooks() { Consumer onMount = (t) -> { HotSpotFastThreadLocal.mount(); @@ -238,74 +183,6 @@ private static void registerVirtualThreadMountHooks() { ModulesSupport.getJavaLangSupport().registerVirtualThreadMountHooks(onMount, onUmount); } - private static String formatVersionWarningMessage(String errorFormat, Object... args) { - StringBuilder errorMessage = new StringBuilder("Version check failed.\n"); - errorMessage.append(String.format(errorFormat, args)); - errorMessage.append(""" - To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used. - It is not recommended to disable version checks. - """); - return errorMessage.toString(); - } - - /** - * Reads reflectively the org.graalvm.truffle module version. The method uses reflection to - * access the {@code PolyglotImpl#TRUFFLE_VERSION} field because the Truffle API may be of a - * version earlier than graalvm-23.1.2 where the field does not exist. - * - * @return the Truffle API version or 23.1.1 if the {@code PolyglotImpl#TRUFFLE_VERSION} field - * does not exist. - */ - private static Version getTruffleVersion() { - try { - Field versionField = PolyglotImpl.class.getDeclaredField("TRUFFLE_VERSION"); - versionField.setAccessible(true); - return Version.parse((String) versionField.get(null)); - } catch (NoSuchFieldException nf) { - return Version.create(23, 1, 1); - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - } - - private static Version getCompilerVersion(TruffleCompilationSupport compilationSupport) { - /* - * The TruffleCompilationSupport is present in both the maven artifact - * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The - * JDK version of TruffleCompilationSupport may be outdated and lack the getCompilerVersion - * method. To address this, we use reflection. - */ - String compilerVersionString = null; - try { - Method getCompilerVersion = compilationSupport.getClass().getMethod("getCompilerVersion"); - compilerVersionString = (String) getCompilerVersion.invoke(compilationSupport); - } catch (NoSuchMethodException noMethod) { - // pass with compilerVersionString set to null - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - return compilerVersionString != null ? Version.parse(compilerVersionString) : Version.create(23, 1, 1); - } - - private static String verifyJVMCIVersion(Class hotspotCompilationSupport) { - /* - * The TruffleCompilationSupport is present in both the maven artifact - * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The - * JDK version of TruffleCompilationSupport may be outdated and lack the verifyJVMCIVersion - * method. To address this, we use reflection. - */ - String errorMessage = null; - try { - Method verifyJVMCIVersion = hotspotCompilationSupport.getDeclaredMethod("verifyJVMCIVersion"); - errorMessage = (String) verifyJVMCIVersion.invoke(null); - } catch (NoSuchMethodException noMethod) { - // pass with result set to true - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - return errorMessage; - } - /** * Handle history of renamings applied to Graal. */ From c155f09e4ed6929015d343043184ee6a3da17754 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Sat, 2 Aug 2025 12:11:46 +0200 Subject: [PATCH 3/3] Resolved review comments. --- .../svm/truffle/TruffleBaseFeature.java | 15 +- .../oracle/svm/truffle/TruffleFeature.java | 2 +- .../truffle-api/native-image.properties | 1 + .../truffle/api/impl/TruffleAPIFeature.java | 145 +++++++++ .../truffle/api/impl/TruffleVersions.java} | 57 ++-- .../oracle/truffle/polyglot/PolyglotImpl.java | 24 +- .../truffle-runtime/native-image.properties | 1 - .../oracle/truffle/runtime/VersionCheck.java | 279 ------------------ .../hotspot/HotSpotTruffleRuntimeAccess.java | 123 +++++++- 9 files changed, 317 insertions(+), 330 deletions(-) create mode 100644 truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java rename truffle/src/{com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java => com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java} (56%) delete mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 44b0f0cf2b85..3a7d03cecdec 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -184,7 +184,7 @@ private static MethodHandle findVersionGetComponent() { private static final String NATIVE_IMAGE_FILELIST_FILE_NAME = "native-image-resources.filelist"; /** * When modifying the version values defined below, ensure that the corresponding version fields - * in {@code OptimizedTruffleRuntime} are also updated accordingly to maintain consistency. + * in {@code TruffleVersions} are also updated accordingly to maintain consistency. */ private static final Version NEXT_POLYGLOT_VERSION_UPDATE = Version.create(29, 1); private static final int MAX_JDK_VERSION = 29; @@ -196,7 +196,7 @@ public String getURL() { @Override public String getDescription() { - return "Provides support for Truffle languages"; + return "Provides internal support for Truffle"; } public static Class lookupClass(String className) { @@ -331,7 +331,11 @@ private void processInlinedField(DuringAnalysisAccess access, InlinableField inl @Override public void afterRegistration(AfterRegistrationAccess a) { - if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) { + /* + * The actual check is now performed in the Truffle API (TruffleAPIFeature). This fallback + * branch can be removed once all supported Truffle versions include TruffleAPIFeature. + */ + if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks") && !hasTruffleAPIFeature(a)) { Version truffleVersion = getTruffleVersion(a); Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); Version featureVersion = getSVMFeatureVersion(); @@ -381,6 +385,11 @@ public void afterRegistration(AfterRegistrationAccess a) { profilingEnabled = false; } + private static boolean hasTruffleAPIFeature(AfterRegistrationAccess a) { + Class featureClass = a.findClassByName("com.oracle.truffle.api.impl.TruffleAPIFeature"); + return featureClass != null && ((FeatureImpl.AfterRegistrationAccessImpl) a).getFeatureHandler().containsFeature(featureClass); + } + /** * Reads reflectively the org.graalvm.truffle module version. The method uses reflection to * access the {@code PolyglotImpl#TRUFFLE_VERSION} field because the Truffle API may be of a diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index d3c5620c9fd7..5216dec5f585 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -193,7 +193,7 @@ public String getURL() { @Override public String getDescription() { - return "Provides support for Truffle runtime compilation"; + return "Provides internal support for Truffle runtime compilation"; } public static class Options { diff --git a/truffle/src/com.oracle.truffle.api/src/META-INF/native-image/org.graalvm.truffle/truffle-api/native-image.properties b/truffle/src/com.oracle.truffle.api/src/META-INF/native-image/org.graalvm.truffle/truffle-api/native-image.properties index 3394d21e49ad..77fb8a89a906 100644 --- a/truffle/src/com.oracle.truffle.api/src/META-INF/native-image/org.graalvm.truffle/truffle-api/native-image.properties +++ b/truffle/src/com.oracle.truffle.api/src/META-INF/native-image/org.graalvm.truffle/truffle-api/native-image.properties @@ -3,6 +3,7 @@ ForceOnModulePath = org.graalvm.truffle Args = --macro:truffle-svm \ --features=com.oracle.svm.truffle.TruffleBaseFeature \ --features=com.oracle.truffle.api.object.DynamicObjectFeature \ + --features=com.oracle.truffle.api.impl.TruffleAPIFeature \ --initialize-at-build-time=com.oracle.truffle \ --initialize-at-build-time=org.graalvm.jniutils \ --initialize-at-build-time=org.graalvm.nativebridge \ diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java new file mode 100644 index 000000000000..981aafb324ee --- /dev/null +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.api.impl; + +import com.oracle.truffle.api.CompilerDirectives; +import org.graalvm.home.Version; +import org.graalvm.nativeimage.hosted.Feature; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +public final class TruffleAPIFeature implements Feature { + + @Override + public String getURL() { + return "https://github.com/oracle/graal/tree/master/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java"; + } + + @Override + public String getDescription() { + return "Provides basic support for Truffle"; + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + String result = doVersionCheck(); + if (result != null) { + // GR-67329: Exceptions thrown by features do not include their error messages in the + // native-image output + PrintStream out = System.err; + out.printf("[%s] %s", getClass().getName(), result); + throw new IllegalStateException(result); + } + } + + private static String doVersionCheck() { + if (TruffleVersions.isVersionCheckEnabled()) { + Version truffleAPIVersion = TruffleVersions.TRUFFLE_API_VERSION; + Version truffleMajorMinorVersion = stripUpdateVersion(truffleAPIVersion); + Version truffleSVMVersion = getSVMFeatureVersion(); + Version truffleSVMMajorMinorVersion = stripUpdateVersion(truffleSVMVersion); + if (truffleSVMVersion.compareTo(TruffleVersions.NEXT_VERSION_UPDATE) >= 0) { + throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); + } else if (truffleSVMMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { + // no forward compatibility + return formatVersionWarningMessage(""" + Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. + Update the org.graalvm.polyglot versions to at least '%s' to resolve this. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, truffleSVMVersion); + } else if (Runtime.version().feature() < TruffleVersions.MIN_JDK_VERSION) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. + The Java runtime version must be greater or equal to JDK '%d'. + Update your Java runtime to resolve this. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, TruffleVersions.MIN_JDK_VERSION); + } else if (truffleSVMVersion.compareTo(TruffleVersions.MIN_COMPILER_VERSION) < 0) { + return formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the Java runtime to the latest update release of JDK '%d'. + """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, Runtime.version().feature()); + } + } + return null; + } + + /** + * Reads the version of the Truffle feature. + */ + private static Version getSVMFeatureVersion() { + InputStream in = TruffleAPIFeature.class.getClassLoader().getResourceAsStream("META-INF/graalvm/org.graalvm.truffle.runtime.svm/version"); + if (in == null) { + throw CompilerDirectives.shouldNotReachHere("Truffle native image feature must have a version file."); + } + try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + return Version.parse(r.readLine()); + } catch (IOException ioe) { + throw CompilerDirectives.shouldNotReachHere(ioe); + } + } + + private static Version stripUpdateVersion(Version version) { + int major = version.getComponent(0); + int minor = version.getComponent(1); + if (major == 0 && minor == 0) { + /* + * Version represents a pure snapshot version without any numeric component. + */ + return version; + } else { + return Version.create(major, minor); + } + } + + private static String formatVersionWarningMessage(String errorFormat, Object... args) { + StringBuilder errorMessage = new StringBuilder("Version check failed.\n"); + errorMessage.append(String.format(errorFormat, args)); + errorMessage.append(""" + To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used. + It is not recommended to disable version checks. + """); + return errorMessage.toString(); + } +} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java similarity index 56% rename from truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java rename to truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java index 69c8299644aa..149be2e9eb31 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java @@ -38,33 +38,50 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.oracle.truffle.runtime; +package com.oracle.truffle.api.impl; -import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.home.Version; -import java.io.PrintStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; -public final class VersionCheckFeature implements Feature { +/** + * Provides support for verifying compatibility between the Truffle API, Truffle compiler, and + * Truffle SubstrateVM feature versions. + */ +public final class TruffleVersions { - @Override - public String getURL() { - return "https://github.com/oracle/graal/tree/master/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheckFeature.java"; + public static final int MIN_JDK_VERSION = 21; + public static final int MAX_JDK_VERSION = 29; + public static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2); + public static final Version NEXT_VERSION_UPDATE = Version.create(29, 1); + public static final Version TRUFFLE_API_VERSION; + static { + if (isVersionCheckEnabled()) { + InputStream in = TruffleVersions.class.getResourceAsStream("/META-INF/graalvm/org.graalvm.truffle/version"); + if (in == null) { + throw new InternalError("Truffle API must have a version file."); + } + try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + TRUFFLE_API_VERSION = Version.parse(r.readLine()); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } else { + TRUFFLE_API_VERSION = null; + } } - @Override - public String getDescription() { - return "Ensures compatibility between the Truffle optimized runtime and the native-image builder"; + private TruffleVersions() { } - @Override - public void afterRegistration(AfterRegistrationAccess access) { - String result = VersionCheck.checkSVMVersion(); - if (result != null) { - // GR-67329: Exceptions thrown by features do not include their error messages in the - // native-image output - PrintStream out = System.err; - out.printf("[%s] %s", getClass().getName(), result); - throw new IllegalStateException(result); - } + /** + * Determines whether version checks are currently enabled. + */ + public static boolean isVersionCheckEnabled() { + return !Boolean.getBoolean("polyglotimpl.DisableVersionChecks"); } } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java index f69bd9f13760..acff7ef97de2 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java @@ -45,11 +45,9 @@ import static com.oracle.truffle.polyglot.EngineAccessor.INSTRUMENT; import static com.oracle.truffle.polyglot.EngineAccessor.LANGUAGE; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.lang.ref.Reference; @@ -58,7 +56,6 @@ import java.net.URI; import java.net.URL; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; @@ -74,6 +71,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; +import com.oracle.truffle.api.impl.TruffleVersions; import org.graalvm.options.OptionDescriptors; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.HostAccess.TargetMappingPrecedence; @@ -127,22 +125,10 @@ public final class PolyglotImpl extends AbstractPolyglotImpl { static final Object SECRET = new Object(); static final Object[] EMPTY_ARGS = new Object[0]; - static final String TRUFFLE_VERSION; - static { - if (Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) { - TRUFFLE_VERSION = null; - } else { - InputStream in = PolyglotImpl.class.getResourceAsStream("/META-INF/graalvm/org.graalvm.truffle/version"); - if (in == null) { - throw new InternalError("Truffle API must have a version file."); - } - try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { - TRUFFLE_VERSION = r.readLine(); - } catch (IOException ioe) { - throw new InternalError(ioe); - } - } - } + /* + * Accessed reflectively by TruffleBaseFeature. + */ + static final String TRUFFLE_VERSION = TruffleVersions.TRUFFLE_API_VERSION == null ? null : TruffleVersions.TRUFFLE_API_VERSION.toString(); private final PolyglotSourceDispatch sourceDispatch = new PolyglotSourceDispatch(this); private final PolyglotSourceSectionDispatch sourceSectionDispatch = new PolyglotSourceSectionDispatch(this); diff --git a/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties b/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties index 84192775e4ca..29978d3da4f3 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties +++ b/truffle/src/com.oracle.truffle.runtime/src/META-INF/native-image/org.graalvm.truffle/truffle-runtime/native-image.properties @@ -2,7 +2,6 @@ ForceOnModulePath = org.graalvm.truffle.runtime Args = --macro:truffle-svm \ --features=com.oracle.svm.truffle.TruffleFeature \ --features=com.oracle.svm.truffle.TruffleJFRFeature \ - --features=com.oracle.truffle.runtime.VersionCheckFeature \ -H:MaxRuntimeCompileMethods=2500 JavaArgs = -Dtruffle.TruffleRuntime=com.oracle.svm.truffle.api.SubstrateTruffleRuntime \ diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java deleted file mode 100644 index 9fbc7ad18f41..000000000000 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/VersionCheck.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.runtime; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.compiler.TruffleCompilationSupport; -import com.oracle.truffle.polyglot.PolyglotImpl; -import org.graalvm.home.Version; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; - -/** - * Provides support for verifying compatibility between the Truffle API, Truffle compiler, and - * Truffle SubstrateVM feature versions. - */ -public final class VersionCheck { - - private static final int MIN_JDK_VERSION = 21; - private static final int MAX_JDK_VERSION = 29; - private static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2); - private static final Version NEXT_VERSION_UPDATE = Version.create(29, 1); - - private VersionCheck() { - } - - /** - * Verifies that the Truffle feature is compatible with the current Truffle runtime version. - * - * @return a string describing the incompatibility, or {@code null} if the check passes. - */ - static String checkSVMVersion() { - if (isVersionCheck()) { - Version truffleAPIVersion = getTruffleVersion(); - Version truffleMajorMinorVersion = stripUpdateVersion(truffleAPIVersion); - Version truffleSVMVersion = getSVMFeatureVersion(); - Version truffleSVMMajorMinorVersion = stripUpdateVersion(truffleSVMVersion); - if (truffleSVMVersion.compareTo(NEXT_VERSION_UPDATE) >= 0) { - throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); - } else if (truffleSVMMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { - // no forward compatibility - return formatVersionWarningMessage(""" - Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. - Update the org.graalvm.polyglot versions to at least '%s' to resolve this. - """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, truffleSVMVersion); - } else if (Runtime.version().feature() < MIN_JDK_VERSION) { - return formatVersionWarningMessage(""" - Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'. - The Java runtime version must be greater or equal to JDK '%d'. - Update your Java runtime to resolve this. - """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, MIN_JDK_VERSION); - } else if (truffleSVMVersion.compareTo(MIN_COMPILER_VERSION) < 0) { - return formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - Update the Java runtime to the latest update release of JDK '%d'. - """, Runtime.version(), truffleSVMVersion, truffleAPIVersion, Runtime.version().feature()); - } - } - return null; - } - - /** - * Verifies that the LibGraal compiler is compatible with the current Truffle runtime version. - * - * @return a string describing the incompatibility, or {@code null} if the check passes. - */ - public static String checkLibGraalCompilerVersion(TruffleCompilationSupport compilationSupport) { - if (isVersionCheck()) { - Version truffleVersion = getTruffleVersion(); - if (truffleVersion.compareTo(NEXT_VERSION_UPDATE) >= 0) { - throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); - } - Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); - Version compilerVersion = getCompilerVersion(compilationSupport); - Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); - int jdkFeatureVersion = Runtime.version().feature(); - if (jdkFeatureVersion < MIN_JDK_VERSION || jdkFeatureVersion >= MAX_JDK_VERSION) { - return formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - The Java runtime version must be greater or equal to JDK '%d' and smaller than JDK '%d'. - Update your Java runtime to resolve this. - """, Runtime.version(), compilerVersion, truffleVersion, MIN_JDK_VERSION, MAX_JDK_VERSION); - } else if (compilerMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { - /* - * Forward compatibility is supported only for minor updates, not for major - * releases. - */ - return formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - Update the org.graalvm.polyglot versions to at least '%s' to resolve this. - """, Runtime.version(), compilerVersion, truffleVersion, compilerVersion); - } else if (compilerVersion.compareTo(MIN_COMPILER_VERSION) < 0) { - return formatVersionWarningMessage(""" - Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. - Update the Java runtime to the latest update release of JDK '%d'. - """, Runtime.version(), compilerVersion, truffleVersion, jdkFeatureVersion); - } - } - return null; - } - - /** - * Verifies that the JarGraal compiler is compatible with the current Truffle runtime version. - * - * @return a string describing the incompatibility, or {@code null} if the check passes. - */ - public static String checkJarGraalCompilerVersion(TruffleCompilationSupport compilationSupport) { - if (isVersionCheck()) { - String jvmciVersionCheckError = verifyJVMCIVersion(compilationSupport.getClass()); - if (jvmciVersionCheckError != null) { - return jvmciVersionCheckError; - } - Version truffleVersion = getTruffleVersion(); - Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); - Version compilerVersion = getCompilerVersion(compilationSupport); - Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); - if (!compilerMajorMinorVersion.equals(truffleMajorMinorVersion)) { - return formatVersionWarningMessage(""" - The Graal compiler version '%s' is incompatible with polyglot version '%s'. - Update the compiler version to '%s' to resolve this. - """, compilerVersion, truffleVersion, truffleVersion); - } - } - return null; - } - - /** - * Determines whether version checks are currently enabled. - */ - private static boolean isVersionCheck() { - return !Boolean.getBoolean("polyglotimpl.DisableVersionChecks"); - } - - /** - * Reads reflectively the org.graalvm.truffle module version. The method uses reflection to - * access the {@code PolyglotImpl#TRUFFLE_VERSION} field because the Truffle API may be of a - * version earlier than graalvm-23.1.2 where the field does not exist. - * - * @return the Truffle API version or 23.1.1 if the {@code PolyglotImpl#TRUFFLE_VERSION} field - * does not exist. - */ - private static Version getTruffleVersion() { - try { - Field versionField = PolyglotImpl.class.getDeclaredField("TRUFFLE_VERSION"); - versionField.setAccessible(true); - return Version.parse((String) versionField.get(null)); - } catch (NoSuchFieldException nf) { - return Version.create(23, 1, 1); - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - } - - /** - * Retrieves the compiler version from the provided {@link TruffleCompilationSupport} instance - * using reflection. If the method is unavailable, a fallback version of 23.1.1 is returned. - */ - private static Version getCompilerVersion(TruffleCompilationSupport compilationSupport) { - /* - * The TruffleCompilationSupport is present in both the maven artifact - * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The - * JDK version of TruffleCompilationSupport may be outdated and lack the getCompilerVersion - * method. To address this, we use reflection. - */ - String compilerVersionString = null; - try { - Method getCompilerVersion = compilationSupport.getClass().getMethod("getCompilerVersion"); - compilerVersionString = (String) getCompilerVersion.invoke(compilationSupport); - } catch (NoSuchMethodException noMethod) { - // pass with compilerVersionString set to null - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - return compilerVersionString != null ? Version.parse(compilerVersionString) : Version.create(23, 1, 1); - } - - /** - * Triggers verification of JVMCI. - */ - private static String verifyJVMCIVersion(Class hotspotCompilationSupport) { - /* - * The TruffleCompilationSupport is present in both the maven artifact - * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The - * JDK version of TruffleCompilationSupport may be outdated and lack the verifyJVMCIVersion - * method. To address this, we use reflection. - */ - String errorMessage = null; - try { - Method verifyJVMCIVersion = hotspotCompilationSupport.getDeclaredMethod("verifyJVMCIVersion"); - errorMessage = (String) verifyJVMCIVersion.invoke(null); - } catch (NoSuchMethodException noMethod) { - // pass with result set to true - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - return errorMessage; - } - - /** - * Reads the version of the Truffle feature. - */ - private static Version getSVMFeatureVersion() { - InputStream in = VersionCheckFeature.class.getClassLoader().getResourceAsStream("META-INF/graalvm/org.graalvm.truffle.runtime.svm/version"); - if (in == null) { - throw CompilerDirectives.shouldNotReachHere("Truffle native image feature must have a version file."); - } - try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { - return Version.parse(r.readLine()); - } catch (IOException ioe) { - throw CompilerDirectives.shouldNotReachHere(ioe); - } - } - - private static Version stripUpdateVersion(Version version) { - int major = version.getComponent(0); - int minor = version.getComponent(1); - if (major == 0 && minor == 0) { - /* - * Version represents a pure snapshot version without any numeric component. - */ - return version; - } else { - return Version.create(major, minor); - } - } - - private static String formatVersionWarningMessage(String errorFormat, Object... args) { - StringBuilder errorMessage = new StringBuilder("Version check failed.\n"); - errorMessage.append(String.format(errorFormat, args)); - errorMessage.append(""" - To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used. - It is not recommended to disable version checks. - """); - return errorMessage.toString(); - } -} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 97220c648f44..bee94bb24195 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -40,15 +40,16 @@ */ package com.oracle.truffle.runtime.hotspot; +import java.lang.reflect.Method; import java.util.Set; import java.util.function.Consumer; import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.TruffleRuntimeAccess; import com.oracle.truffle.api.impl.DefaultTruffleRuntime; +import com.oracle.truffle.api.impl.TruffleVersions; import com.oracle.truffle.compiler.TruffleCompilationSupport; import com.oracle.truffle.runtime.ModulesSupport; -import com.oracle.truffle.runtime.VersionCheck; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraal; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraalTruffleCompilationSupport; @@ -56,6 +57,7 @@ import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.runtime.JVMCI; import jdk.vm.ci.services.Services; +import org.graalvm.home.Version; public final class HotSpotTruffleRuntimeAccess implements TruffleRuntimeAccess { @@ -136,9 +138,36 @@ protected static TruffleRuntime createRuntime() { if (LibGraal.isAvailable()) { // try LibGraal compilationSupport = new LibGraalTruffleCompilationSupport(); - String result = VersionCheck.checkLibGraalCompilerVersion(compilationSupport); - if (result != null) { - return new DefaultTruffleRuntime(result); + if (TruffleVersions.isVersionCheckEnabled()) { + Version truffleVersion = TruffleVersions.TRUFFLE_API_VERSION; + if (truffleVersion.compareTo(TruffleVersions.NEXT_VERSION_UPDATE) >= 0) { + throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!"); + } + Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); + Version compilerVersion = getCompilerVersion(compilationSupport); + Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); + int jdkFeatureVersion = Runtime.version().feature(); + if (jdkFeatureVersion < TruffleVersions.MIN_JDK_VERSION || jdkFeatureVersion >= TruffleVersions.MAX_JDK_VERSION) { + return new DefaultTruffleRuntime(formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + The Java runtime version must be greater or equal to JDK '%d' and smaller than JDK '%d'. + Update your Java runtime to resolve this. + """, Runtime.version(), compilerVersion, truffleVersion, TruffleVersions.MIN_JDK_VERSION, TruffleVersions.MAX_JDK_VERSION)); + } else if (compilerMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) { + /* + * Forward compatibility is supported only for minor updates, not for major + * releases. + */ + return new DefaultTruffleRuntime(formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the org.graalvm.polyglot versions to at least '%s' to resolve this. + """, Runtime.version(), compilerVersion, truffleVersion, compilerVersion)); + } else if (compilerVersion.compareTo(TruffleVersions.MIN_COMPILER_VERSION) < 0) { + return new DefaultTruffleRuntime(formatVersionWarningMessage(""" + Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'. + Update the Java runtime to the latest update release of JDK '%d'. + """, Runtime.version(), compilerVersion, truffleVersion, jdkFeatureVersion)); + } } } else { // try jar graal @@ -152,9 +181,21 @@ protected static TruffleRuntime createRuntime() { ModulesSupport.addExports(compilerModule, pkg, runtimeModule); Class hotspotCompilationSupport = Class.forName(compilerModule, pkg + ".HotSpotTruffleCompilationSupport"); compilationSupport = (TruffleCompilationSupport) hotspotCompilationSupport.getConstructor().newInstance(); - String result = VersionCheck.checkJarGraalCompilerVersion(compilationSupport); - if (result != null) { - return new DefaultTruffleRuntime(result); + if (TruffleVersions.isVersionCheckEnabled()) { + String jvmciVersionCheckError = verifyJVMCIVersion(compilationSupport.getClass()); + if (jvmciVersionCheckError != null) { + return new DefaultTruffleRuntime(jvmciVersionCheckError); + } + Version truffleVersion = TruffleVersions.TRUFFLE_API_VERSION; + Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); + Version compilerVersion = getCompilerVersion(compilationSupport); + Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); + if (!compilerMajorMinorVersion.equals(truffleMajorMinorVersion)) { + return new DefaultTruffleRuntime(formatVersionWarningMessage(""" + The Graal compiler version '%s' is incompatible with polyglot version '%s'. + Update the compiler version to '%s' to resolve this. + """, compilerVersion, truffleVersion, truffleVersion)); + } } } catch (ReflectiveOperationException e) { throw new InternalError(e); @@ -174,6 +215,74 @@ protected static TruffleRuntime createRuntime() { return rt; } + /** + * Triggers verification of JVMCI. + */ + private static String verifyJVMCIVersion(Class hotspotCompilationSupport) { + /* + * The TruffleCompilationSupport is present in both the maven artifact + * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The + * JDK version of TruffleCompilationSupport may be outdated and lack the verifyJVMCIVersion + * method. To address this, we use reflection. + */ + String errorMessage = null; + try { + Method verifyJVMCIVersion = hotspotCompilationSupport.getDeclaredMethod("verifyJVMCIVersion"); + errorMessage = (String) verifyJVMCIVersion.invoke(null); + } catch (NoSuchMethodException noMethod) { + // pass with result set to true + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + return errorMessage; + } + + /** + * Retrieves the compiler version from the provided {@link TruffleCompilationSupport} instance + * using reflection. If the method is unavailable, a fallback version of 23.1.1 is returned. + */ + public static Version getCompilerVersion(TruffleCompilationSupport compilationSupport) { + /* + * The TruffleCompilationSupport is present in both the maven artifact + * org.graalvm.truffle/truffle-compiler and the JDK org.graalvm.truffle.compiler module. The + * JDK version of TruffleCompilationSupport may be outdated and lack the getCompilerVersion + * method. To address this, we use reflection. + */ + String compilerVersionString = null; + try { + Method getCompilerVersion = compilationSupport.getClass().getMethod("getCompilerVersion"); + compilerVersionString = (String) getCompilerVersion.invoke(compilationSupport); + } catch (NoSuchMethodException noMethod) { + // pass with compilerVersionString set to null + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + return compilerVersionString != null ? Version.parse(compilerVersionString) : Version.create(23, 1, 1); + } + + private static Version stripUpdateVersion(Version version) { + int major = version.getComponent(0); + int minor = version.getComponent(1); + if (major == 0 && minor == 0) { + /* + * Version represents a pure snapshot version without any numeric component. + */ + return version; + } else { + return Version.create(major, minor); + } + } + + private static String formatVersionWarningMessage(String errorFormat, Object... args) { + StringBuilder errorMessage = new StringBuilder("Version check failed.\n"); + errorMessage.append(String.format(errorFormat, args)); + errorMessage.append(""" + To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used. + It is not recommended to disable version checks. + """); + return errorMessage.toString(); + } + private static void registerVirtualThreadMountHooks() { Consumer onMount = (t) -> { HotSpotFastThreadLocal.mount();