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..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 @@ -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 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; @@ -192,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) { @@ -327,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(); @@ -377,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.api/src/com/oracle/truffle/api/impl/TruffleVersions.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java new file mode 100644 index 000000000000..149be2e9eb31 --- /dev/null +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleVersions.java @@ -0,0 +1,87 @@ +/* + * 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 org.graalvm.home.Version; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * Provides support for verifying compatibility between the Truffle API, Truffle compiler, and + * Truffle SubstrateVM feature versions. + */ +public final class TruffleVersions { + + 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; + } + } + + private TruffleVersions() { + } + + /** + * 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/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java index 7573f0d39dc2..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,10 +167,6 @@ 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; - 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/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 2b829a301bf2..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,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_COMPILER_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.api.impl.TruffleVersions; import com.oracle.truffle.compiler.TruffleCompilationSupport; -import com.oracle.truffle.polyglot.PolyglotImpl; import com.oracle.truffle.runtime.ModulesSupport; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraal; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraalTruffleCompilationSupport; @@ -65,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 { @@ -145,21 +138,21 @@ 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) { + 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 < MIN_JDK_VERSION || jdkFeatureVersion >= MAX_JDK_VERSION) { + 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, MIN_JDK_VERSION, MAX_JDK_VERSION)); + """, 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 @@ -169,7 +162,7 @@ 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) { + } 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'. @@ -188,12 +181,12 @@ 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 (TruffleVersions.isVersionCheckEnabled()) { + String jvmciVersionCheckError = verifyJVMCIVersion(compilationSupport.getClass()); if (jvmciVersionCheckError != null) { return new DefaultTruffleRuntime(jvmciVersionCheckError); } - Version truffleVersion = getTruffleVersion(); + Version truffleVersion = TruffleVersions.TRUFFLE_API_VERSION; Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion); Version compilerVersion = getCompilerVersion(compilationSupport); Version compilerMajorMinorVersion = stripUpdateVersion(compilerVersion); @@ -222,59 +215,33 @@ 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(); - HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); - }; - Consumer onUmount = (t) -> HotSpotFastThreadLocal.unmount(); - 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. + * Triggers verification of JVMCI. */ - private static Version getTruffleVersion() { + 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 { - 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); + 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; } - private static Version getCompilerVersion(TruffleCompilationSupport compilationSupport) { + /** + * 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 @@ -293,23 +260,36 @@ private static Version getCompilerVersion(TruffleCompilationSupport compilationS 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); + 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); } - return errorMessage; + } + + 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(); + HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); + }; + Consumer onUmount = (t) -> HotSpotFastThreadLocal.unmount(); + ModulesSupport.getJavaLangSupport().registerVirtualThreadMountHooks(onMount, onUmount); } /**