Skip to content

Commit ad4502f

Browse files
Automatic merge of master into galahad
2 parents cd48c71 + 494fbe7 commit ad4502f

File tree

8 files changed

+313
-106
lines changed

8 files changed

+313
-106
lines changed

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ private static MethodHandle findVersionGetComponent() {
182182
}
183183

184184
private static final String NATIVE_IMAGE_FILELIST_FILE_NAME = "native-image-resources.filelist";
185+
/**
186+
* When modifying the version values defined below, ensure that the corresponding version fields
187+
* in {@code TruffleVersions} are also updated accordingly to maintain consistency.
188+
*/
185189
private static final Version NEXT_POLYGLOT_VERSION_UPDATE = Version.create(29, 1);
186190
private static final int MAX_JDK_VERSION = 29;
187191

@@ -192,7 +196,7 @@ public String getURL() {
192196

193197
@Override
194198
public String getDescription() {
195-
return "Provides support for Truffle languages";
199+
return "Provides internal support for Truffle";
196200
}
197201

198202
public static Class<?> lookupClass(String className) {
@@ -327,7 +331,11 @@ private void processInlinedField(DuringAnalysisAccess access, InlinableField inl
327331

328332
@Override
329333
public void afterRegistration(AfterRegistrationAccess a) {
330-
if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) {
334+
/*
335+
* The actual check is now performed in the Truffle API (TruffleAPIFeature). This fallback
336+
* branch can be removed once all supported Truffle versions include TruffleAPIFeature.
337+
*/
338+
if (!Boolean.getBoolean("polyglotimpl.DisableVersionChecks") && !hasTruffleAPIFeature(a)) {
331339
Version truffleVersion = getTruffleVersion(a);
332340
Version truffleMajorMinorVersion = stripUpdateVersion(truffleVersion);
333341
Version featureVersion = getSVMFeatureVersion();
@@ -377,6 +385,11 @@ public void afterRegistration(AfterRegistrationAccess a) {
377385
profilingEnabled = false;
378386
}
379387

388+
private static boolean hasTruffleAPIFeature(AfterRegistrationAccess a) {
389+
Class<?> featureClass = a.findClassByName("com.oracle.truffle.api.impl.TruffleAPIFeature");
390+
return featureClass != null && ((FeatureImpl.AfterRegistrationAccessImpl) a).getFeatureHandler().containsFeature(featureClass);
391+
}
392+
380393
/**
381394
* Reads reflectively the org.graalvm.truffle module version. The method uses reflection to
382395
* access the {@code PolyglotImpl#TRUFFLE_VERSION} field because the Truffle API may be of a

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public String getURL() {
194194

195195
@Override
196196
public String getDescription() {
197-
return "Provides support for Truffle runtime compilation";
197+
return "Provides internal support for Truffle runtime compilation";
198198
}
199199

200200
public static class Options {

truffle/src/com.oracle.truffle.api/src/META-INF/native-image/org.graalvm.truffle/truffle-api/native-image.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ ForceOnModulePath = org.graalvm.truffle
33
Args = --macro:truffle-svm \
44
--features=com.oracle.svm.truffle.TruffleBaseFeature \
55
--features=com.oracle.truffle.api.object.DynamicObjectFeature \
6+
--features=com.oracle.truffle.api.impl.TruffleAPIFeature \
67
--initialize-at-build-time=com.oracle.truffle \
78
--initialize-at-build-time=org.graalvm.jniutils \
89
--initialize-at-build-time=org.graalvm.nativebridge \
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.api.impl;
42+
43+
import com.oracle.truffle.api.CompilerDirectives;
44+
import org.graalvm.home.Version;
45+
import org.graalvm.nativeimage.hosted.Feature;
46+
47+
import java.io.BufferedReader;
48+
import java.io.IOException;
49+
import java.io.InputStream;
50+
import java.io.InputStreamReader;
51+
import java.io.PrintStream;
52+
import java.nio.charset.StandardCharsets;
53+
54+
public final class TruffleAPIFeature implements Feature {
55+
56+
@Override
57+
public String getURL() {
58+
return "https://github.com/oracle/graal/tree/master/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/TruffleAPIFeature.java";
59+
}
60+
61+
@Override
62+
public String getDescription() {
63+
return "Provides basic support for Truffle";
64+
}
65+
66+
@Override
67+
public void afterRegistration(AfterRegistrationAccess access) {
68+
String result = doVersionCheck();
69+
if (result != null) {
70+
// GR-67329: Exceptions thrown by features do not include their error messages in the
71+
// native-image output
72+
PrintStream out = System.err;
73+
out.printf("[%s] %s", getClass().getName(), result);
74+
throw new IllegalStateException(result);
75+
}
76+
}
77+
78+
private static String doVersionCheck() {
79+
if (TruffleVersions.isVersionCheckEnabled()) {
80+
Version truffleAPIVersion = TruffleVersions.TRUFFLE_API_VERSION;
81+
Version truffleMajorMinorVersion = stripUpdateVersion(truffleAPIVersion);
82+
Version truffleSVMVersion = getSVMFeatureVersion();
83+
Version truffleSVMMajorMinorVersion = stripUpdateVersion(truffleSVMVersion);
84+
if (truffleSVMVersion.compareTo(TruffleVersions.NEXT_VERSION_UPDATE) >= 0) {
85+
throw new AssertionError("MIN_COMPILER_VERSION, MIN_JDK_VERSION and MAX_JDK_VERSION must be updated!");
86+
} else if (truffleSVMMajorMinorVersion.compareTo(truffleMajorMinorVersion) > 0) {
87+
// no forward compatibility
88+
return formatVersionWarningMessage("""
89+
Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'.
90+
Update the org.graalvm.polyglot versions to at least '%s' to resolve this.
91+
""", Runtime.version(), truffleSVMVersion, truffleAPIVersion, truffleSVMVersion);
92+
} else if (Runtime.version().feature() < TruffleVersions.MIN_JDK_VERSION) {
93+
return formatVersionWarningMessage("""
94+
Your Java runtime '%s' with native-image feature version '%s' is incompatible with polyglot version '%s'.
95+
The Java runtime version must be greater or equal to JDK '%d'.
96+
Update your Java runtime to resolve this.
97+
""", Runtime.version(), truffleSVMVersion, truffleAPIVersion, TruffleVersions.MIN_JDK_VERSION);
98+
} else if (truffleSVMVersion.compareTo(TruffleVersions.MIN_COMPILER_VERSION) < 0) {
99+
return formatVersionWarningMessage("""
100+
Your Java runtime '%s' with compiler version '%s' is incompatible with polyglot version '%s'.
101+
Update the Java runtime to the latest update release of JDK '%d'.
102+
""", Runtime.version(), truffleSVMVersion, truffleAPIVersion, Runtime.version().feature());
103+
}
104+
}
105+
return null;
106+
}
107+
108+
/**
109+
* Reads the version of the Truffle feature.
110+
*/
111+
private static Version getSVMFeatureVersion() {
112+
InputStream in = TruffleAPIFeature.class.getClassLoader().getResourceAsStream("META-INF/graalvm/org.graalvm.truffle.runtime.svm/version");
113+
if (in == null) {
114+
throw CompilerDirectives.shouldNotReachHere("Truffle native image feature must have a version file.");
115+
}
116+
try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
117+
return Version.parse(r.readLine());
118+
} catch (IOException ioe) {
119+
throw CompilerDirectives.shouldNotReachHere(ioe);
120+
}
121+
}
122+
123+
private static Version stripUpdateVersion(Version version) {
124+
int major = version.getComponent(0);
125+
int minor = version.getComponent(1);
126+
if (major == 0 && minor == 0) {
127+
/*
128+
* Version represents a pure snapshot version without any numeric component.
129+
*/
130+
return version;
131+
} else {
132+
return Version.create(major, minor);
133+
}
134+
}
135+
136+
private static String formatVersionWarningMessage(String errorFormat, Object... args) {
137+
StringBuilder errorMessage = new StringBuilder("Version check failed.\n");
138+
errorMessage.append(String.format(errorFormat, args));
139+
errorMessage.append("""
140+
To disable this version check the '-Dpolyglotimpl.DisableVersionChecks=true' system property can be used.
141+
It is not recommended to disable version checks.
142+
""");
143+
return errorMessage.toString();
144+
}
145+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.api.impl;
42+
43+
import org.graalvm.home.Version;
44+
45+
import java.io.BufferedReader;
46+
import java.io.IOException;
47+
import java.io.InputStream;
48+
import java.io.InputStreamReader;
49+
import java.nio.charset.StandardCharsets;
50+
51+
/**
52+
* Provides support for verifying compatibility between the Truffle API, Truffle compiler, and
53+
* Truffle SubstrateVM feature versions.
54+
*/
55+
public final class TruffleVersions {
56+
57+
public static final int MIN_JDK_VERSION = 21;
58+
public static final int MAX_JDK_VERSION = 29;
59+
public static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2);
60+
public static final Version NEXT_VERSION_UPDATE = Version.create(29, 1);
61+
public static final Version TRUFFLE_API_VERSION;
62+
static {
63+
if (isVersionCheckEnabled()) {
64+
InputStream in = TruffleVersions.class.getResourceAsStream("/META-INF/graalvm/org.graalvm.truffle/version");
65+
if (in == null) {
66+
throw new InternalError("Truffle API must have a version file.");
67+
}
68+
try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
69+
TRUFFLE_API_VERSION = Version.parse(r.readLine());
70+
} catch (IOException ioe) {
71+
throw new InternalError(ioe);
72+
}
73+
} else {
74+
TRUFFLE_API_VERSION = null;
75+
}
76+
}
77+
78+
private TruffleVersions() {
79+
}
80+
81+
/**
82+
* Determines whether version checks are currently enabled.
83+
*/
84+
public static boolean isVersionCheckEnabled() {
85+
return !Boolean.getBoolean("polyglotimpl.DisableVersionChecks");
86+
}
87+
}

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,9 @@
4545
import static com.oracle.truffle.polyglot.EngineAccessor.INSTRUMENT;
4646
import static com.oracle.truffle.polyglot.EngineAccessor.LANGUAGE;
4747

48-
import java.io.BufferedReader;
4948
import java.io.File;
5049
import java.io.IOException;
5150
import java.io.InputStream;
52-
import java.io.InputStreamReader;
5351
import java.io.OutputStream;
5452
import java.io.Reader;
5553
import java.lang.ref.Reference;
@@ -58,7 +56,6 @@
5856
import java.net.URI;
5957
import java.net.URL;
6058
import java.nio.charset.Charset;
61-
import java.nio.charset.StandardCharsets;
6259
import java.nio.file.Path;
6360
import java.util.Collection;
6461
import java.util.HashMap;
@@ -74,6 +71,7 @@
7471
import java.util.logging.Level;
7572
import java.util.stream.Collectors;
7673

74+
import com.oracle.truffle.api.impl.TruffleVersions;
7775
import org.graalvm.options.OptionDescriptors;
7876
import org.graalvm.polyglot.Engine;
7977
import org.graalvm.polyglot.HostAccess.TargetMappingPrecedence;
@@ -127,22 +125,10 @@ public final class PolyglotImpl extends AbstractPolyglotImpl {
127125
static final Object SECRET = new Object();
128126
static final Object[] EMPTY_ARGS = new Object[0];
129127

130-
static final String TRUFFLE_VERSION;
131-
static {
132-
if (Boolean.getBoolean("polyglotimpl.DisableVersionChecks")) {
133-
TRUFFLE_VERSION = null;
134-
} else {
135-
InputStream in = PolyglotImpl.class.getResourceAsStream("/META-INF/graalvm/org.graalvm.truffle/version");
136-
if (in == null) {
137-
throw new InternalError("Truffle API must have a version file.");
138-
}
139-
try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
140-
TRUFFLE_VERSION = r.readLine();
141-
} catch (IOException ioe) {
142-
throw new InternalError(ioe);
143-
}
144-
}
145-
}
128+
/*
129+
* Accessed reflectively by TruffleBaseFeature.
130+
*/
131+
static final String TRUFFLE_VERSION = TruffleVersions.TRUFFLE_API_VERSION == null ? null : TruffleVersions.TRUFFLE_API_VERSION.toString();
146132

147133
private final PolyglotSourceDispatch sourceDispatch = new PolyglotSourceDispatch(this);
148134
private final PolyglotSourceSectionDispatch sourceSectionDispatch = new PolyglotSourceSectionDispatch(this);

truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@
7171

7272
import org.graalvm.collections.EconomicMap;
7373
import org.graalvm.collections.UnmodifiableEconomicMap;
74-
import org.graalvm.home.Version;
7574
import org.graalvm.nativeimage.ImageInfo;
7675
import org.graalvm.options.OptionCategory;
7776
import org.graalvm.options.OptionDescriptor;
@@ -168,10 +167,6 @@
168167
public abstract class OptimizedTruffleRuntime implements TruffleRuntime, TruffleCompilerRuntime {
169168

170169
private static final int JAVA_SPECIFICATION_VERSION = Runtime.version().feature();
171-
public static final Version MIN_COMPILER_VERSION = Version.create(23, 1, 2);
172-
public static final int MIN_JDK_VERSION = 21;
173-
public static final int MAX_JDK_VERSION = 29;
174-
public static final Version NEXT_VERSION_UPDATE = Version.create(29, 1);
175170

176171
/**
177172
* Used only to reset state for native image compilation.

0 commit comments

Comments
 (0)