Skip to content

Commit 8088e8e

Browse files
committed
RFC [GR-52835] Support OpenJDK versions in JVMCIVersionCheck
PullRequest: graal/17419
2 parents 101501c + 9d2481d commit 8088e8e

File tree

7 files changed

+290
-60
lines changed

7 files changed

+290
-60
lines changed

compiler/mx.compiler/mx_compiler.py

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
from __future__ import print_function
2727
import os
28+
from functools import total_ordering
2829
from os.path import join, exists, basename, dirname, isdir
2930
import argparse
3031
from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER
@@ -79,7 +80,7 @@ def get_vm_prefix(asList=True):
7980

8081

8182
class JavaLangRuntimeVersion(mx.Comparable):
82-
"""Wrapper for by java.lang.Runtime.Version"""
83+
"""Wrapper for java.lang.Runtime.Version"""
8384

8485
_cmp_cache = {}
8586
_feature_re = re.compile('[1-9][0-9]*')
@@ -124,10 +125,48 @@ def feature(self):
124125
self._feature = int(JavaLangRuntimeVersion._feature_re.match(self.version).group(0))
125126
return self._feature
126127

128+
@total_ordering
129+
class JVMCIVersionCheckVersion(object):
130+
def __init__(self, jdk_version, jvmci_major, jvmci_minor, jvmci_build):
131+
"""
132+
Python version of jdk.graal.compiler.hotspot.JVMCIVersionCheck.Version
133+
134+
jdk_version is a JavaLangRuntimeVersion
135+
jvmci_major and jvmci_minor might be 0 if not needed (JDK 22+)
136+
"""
137+
assert isinstance(jdk_version, JavaLangRuntimeVersion)
138+
assert isinstance(jvmci_major, int)
139+
assert isinstance(jvmci_minor, int)
140+
assert isinstance(jvmci_build, int)
141+
self.jdk_version = jdk_version
142+
self.jvmci_major = jvmci_major
143+
self.jvmci_minor = jvmci_minor
144+
self.jvmci_build = jvmci_build
145+
146+
def _as_tuple(self):
147+
return (self.jdk_version, self.jvmci_major, self.jvmci_minor, self.jvmci_build)
148+
149+
def __eq__(self, other):
150+
if not isinstance(other, JVMCIVersionCheckVersion):
151+
return False
152+
return self._as_tuple() == other._as_tuple()
153+
154+
def __lt__(self, other):
155+
if not isinstance(other, JVMCIVersionCheckVersion):
156+
return NotImplemented
157+
return self._as_tuple() < other._as_tuple()
158+
159+
def __str__(self):
160+
jdk_version, jvmci_major, jvmci_minor, jvmci_build = self._as_tuple()
161+
if jvmci_major == 0:
162+
if jvmci_build == 0:
163+
return f'(openjdk|oraclejdk)-{jdk_version}'
164+
else:
165+
return f'labsjdk-(ce|ee)-{jdk_version}-jvmci-b{jvmci_build:02d}'
166+
else:
167+
return f'labsjdk-(ce|ee)-{jdk_version}-jvmci-{jvmci_major}.{jvmci_minor}-b{jvmci_build:02d}'
168+
127169

128-
#: 4-tuple (jdk_version, jvmci_major, jvmci_minor, jvmci_build) of JVMCI version, if any, denoted by `jdk`
129-
# jdk_version is a JavaLangRuntimeVersion
130-
# jvmci_major and jvmci_minor might be 0 if not needed (JDK 22+)
131170
_jdk_jvmci_version = None
132171
_jdk_min_jvmci_version = None
133172

@@ -145,7 +184,7 @@ def _capture_jvmci_version(args=None):
145184
if out.data:
146185
try:
147186
(jdk_version, jvmci_major, jvmci_minor, jvmci_build) = out.data.split(',')
148-
return (JavaLangRuntimeVersion(jdk_version), int(jvmci_major), int(jvmci_minor), int(jvmci_build))
187+
return JVMCIVersionCheckVersion(JavaLangRuntimeVersion(jdk_version), int(jvmci_major), int(jvmci_minor), int(jvmci_build))
149188
except ValueError:
150189
mx.warn(f'Could not parse jvmci version from JVMCIVersionCheck output:\n{out.data}')
151190
return None
@@ -1165,7 +1204,7 @@ def _check_latest_jvmci_version():
11651204
``common.json`` file and issues a warning if not.
11661205
"""
11671206
jvmci_re = re.compile(r'(?:ce|ee)-(?P<jdk_version>.+)-jvmci(?:-(?P<jvmci_major>\d+)\.(?P<jvmci_minor>\d+))?-b(?P<jvmci_build>\d+)')
1168-
common_path = join(_suite.dir, '..', 'common.json')
1207+
common_path = os.path.normpath(join(_suite.dir, '..', 'common.json'))
11691208

11701209
if _jdk_jvmci_version is None:
11711210
# Not using a JVMCI JDK
@@ -1183,8 +1222,13 @@ def get_latest_jvmci_version():
11831222
if not match:
11841223
mx.abort(f'Cannot parse version {version}')
11851224
(jdk_version, jvmci_major, jvmci_minor, jvmci_build) = match.groups(default=0)
1186-
current = (JavaLangRuntimeVersion(jdk_version), int(jvmci_major), int(jvmci_minor), int(jvmci_build))
1187-
if current[0].feature() == _jdk_jvmci_version[0].feature():
1225+
if _jdk_jvmci_version.jvmci_build == 0:
1226+
# jvmci_build == 0 indicates an OpenJDK version has been specified in JVMCIVersionCheck.java.
1227+
# The JDK does not know the jvmci_build number that might have been specified in common.json,
1228+
# as it is only a repackaged JDK. Thus, we reset the jvmci_build because we cannot validate it.
1229+
jvmci_build = 0
1230+
current = JVMCIVersionCheckVersion(JavaLangRuntimeVersion(jdk_version), int(jvmci_major), int(jvmci_minor), int(jvmci_build))
1231+
if current.jdk_version.feature() == _jdk_jvmci_version.jdk_version.feature():
11881232
# only compare the same major versions
11891233
if latest == 'not found':
11901234
latest = current
@@ -1196,28 +1240,21 @@ def get_latest_jvmci_version():
11961240
return False, distribution
11971241
return not isinstance(latest, str), latest
11981242

1199-
def jvmci_version_str(version):
1200-
jdk_version, jvmci_major, jvmci_minor, jvmci_build = version
1201-
if jvmci_major == 0:
1202-
return f'labsjdk-(ce|ee)-{jdk_version}-jvmci-b{jvmci_build:02d}'
1203-
else:
1204-
return f'labsjdk-(ce|ee)-{jdk_version}-jvmci-{jvmci_major}.{jvmci_minor}-b{jvmci_build:02d}'
1205-
12061243
version_check_setting = os.environ.get('JVMCI_VERSION_CHECK', None)
12071244

12081245
success, latest = get_latest_jvmci_version()
12091246

12101247
if version_check_setting == 'strict' and _jdk_jvmci_version != _jdk_min_jvmci_version:
12111248
msg = f'JVMCI_MIN_VERSION specified in JVMCIVersionCheck.java is older than in {common_path}:'
1212-
msg += os.linesep + f'{jvmci_version_str(_jdk_min_jvmci_version)} < {jvmci_version_str(_jdk_jvmci_version)} '
1249+
msg += os.linesep + f'{_jdk_min_jvmci_version} < {_jdk_jvmci_version} '
12131250
msg += os.linesep + f'Did you forget to update JVMCI_MIN_VERSION after updating {common_path}?'
12141251
msg += os.linesep + 'Set the JVMCI_VERSION_CHECK environment variable to something else then "strict" to'
12151252
msg += ' suppress this error.'
12161253
mx.abort(msg)
12171254

12181255
if version_check_setting == 'strict' and not success:
12191256
if latest == 'not found':
1220-
msg = f'No JVMCI JDK found in {common_path} that matches {jvmci_version_str(_jdk_jvmci_version)}.'
1257+
msg = f'No JVMCI JDK found in {common_path} that matches {_jdk_jvmci_version}.'
12211258
msg += os.linesep + f'Check that {latest} matches the versions of the other JVMCI JDKs.'
12221259
else:
12231260
msg = f'Version mismatch in {common_path}:'
@@ -1227,10 +1264,9 @@ def jvmci_version_str(version):
12271264
mx.abort(msg)
12281265

12291266
if success and _jdk_jvmci_version < latest:
1230-
common_path = os.path.normpath(common_path)
1231-
msg = f'JVMCI version of JAVA_HOME is older than in {common_path}: {jvmci_version_str(_jdk_jvmci_version)} < {jvmci_version_str(latest)} '
1267+
msg = f'JVMCI version of JAVA_HOME is older than in {common_path}: {_jdk_jvmci_version} < {latest} '
12321268
msg += os.linesep + 'This poses the risk of hitting JVMCI bugs that have already been fixed.'
1233-
msg += os.linesep + f'Consider using {jvmci_version_str(latest)}, which you can get via:'
1269+
msg += os.linesep + f'Consider using {latest}, which you can get via:'
12341270
msg += os.linesep + f'mx fetch-jdk --configuration {common_path}'
12351271
mx.abort_or_warn(msg, version_check_setting == 'strict')
12361272

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/JVMCIVersionCheckMaxValueTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void testNewVersion() {
5454

5555
private static void testVersion(String javaVmVersion) {
5656
try {
57-
JVMCIVersionCheck.Version minVersion = new JVMCIVersionCheck.Version(20, 0, 1);
57+
JVMCIVersionCheck.Version minVersion = JVMCIVersionCheck.createLegacyVersion(20, 0, 1);
5858
// Use a javaSpecVersion that will likely not fail in the near future
5959
String javaSpecVersion = "99";
6060
var props = JVMCIVersionCheckTest.createTestProperties(javaSpecVersion, javaVmVersion, null);
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.graal.compiler.hotspot.test;
26+
27+
import org.junit.Assert;
28+
import org.junit.Test;
29+
30+
import jdk.graal.compiler.core.test.GraalCompilerTest;
31+
import jdk.graal.compiler.hotspot.JVMCIVersionCheck;
32+
import org.junit.runner.RunWith;
33+
import org.junit.runners.Parameterized;
34+
35+
import java.util.Collection;
36+
import java.util.List;
37+
import java.util.Map;
38+
39+
import static jdk.graal.compiler.hotspot.JVMCIVersionCheck.DEFAULT_VENDOR_ENTRY;
40+
41+
/**
42+
* Tests that {@link JVMCIVersionCheck} handles OpenJDK versions correctly.
43+
*/
44+
@RunWith(Parameterized.class)
45+
public class JVMCIVersionCheckOpenJDKTest extends GraalCompilerTest {
46+
47+
@Parameterized.Parameters(name = "{0} <= {1} = {2}")
48+
public static Collection<Object[]> data() {
49+
return List.of(
50+
/*
51+
* If comparing a LabsJDK version against an OpenJDK version, ignore the
52+
* JVMCI build number.
53+
*/
54+
expectFail("99+99-jvmci-b02", "99+98"),
55+
expectPass("99+99-jvmci-b02", "99+99"),
56+
expectPass("99+99-jvmci-b02", "99+100"),
57+
/*
58+
* If comparing a LabsJDK version against a LabsJDK version, respect the
59+
* JVMCI build.
60+
*/
61+
expectFail("99+99-jvmci-b02", "99+98-jvmci-b01"),
62+
expectFail("99+99-jvmci-b02", "99+98-jvmci-b02"),
63+
expectFail("99+99-jvmci-b02", "99+98-jvmci-b03"),
64+
65+
expectFail("99+99-jvmci-b02", "99+99-jvmci-b01"),
66+
expectPass("99+99-jvmci-b02", "99+99-jvmci-b02"),
67+
expectPass("99+99-jvmci-b02", "99+99-jvmci-b03"),
68+
69+
expectPass("99+99-jvmci-b02", "99+100-jvmci-b01"),
70+
expectPass("99+99-jvmci-b02", "99+100-jvmci-b02"),
71+
expectPass("99+99-jvmci-b02", "99+100-jvmci-b03"),
72+
73+
/* Comparing an OpenJDK version against an OpenJDK version. */
74+
expectFail("99+99", "99+98"),
75+
expectPass("99+99", "99+99"),
76+
expectPass("99+99", "99+100"),
77+
78+
/* Comparing an OpenJDK version against a LabsJDK version. */
79+
expectFail("99+99", "99+98-jvmci-b01"),
80+
expectPass("99+99", "99+99-jvmci-b01"),
81+
expectPass("99+99", "99+100-jvmci-b01"));
82+
}
83+
84+
private static Object[] expectPass(String minVersion, String javaVmVersion) {
85+
return new Object[]{minVersion, javaVmVersion, true};
86+
}
87+
88+
private static Object[] expectFail(String minVersion, String javaVmVersion) {
89+
return new Object[]{minVersion, javaVmVersion, false};
90+
}
91+
92+
@Parameterized.Parameter(0) public String minVersion;
93+
@Parameterized.Parameter(1) public String javaVmVersion;
94+
@Parameterized.Parameter(2) public boolean expectSuccess;
95+
96+
@Test
97+
public void compareToMinVersion() {
98+
if (checkVersionProperties(getMinVersionMap(minVersion), javaVmVersion)) {
99+
if (!expectSuccess) {
100+
Assert.fail(String.format("Expected %s to be older than %s", javaVmVersion, minVersion));
101+
}
102+
} else {
103+
if (expectSuccess) {
104+
Assert.fail(String.format("Expected %s not to be older than %s", javaVmVersion, minVersion));
105+
}
106+
107+
}
108+
}
109+
110+
private static Map<String, Map<String, JVMCIVersionCheck.Version>> getMinVersionMap(String minVersion) {
111+
Runtime.Version version = Runtime.Version.parse(minVersion);
112+
if (version.optional().isEmpty()) {
113+
// OpenJDK version
114+
return Map.of(Integer.toString(version.feature()), Map.of(
115+
DEFAULT_VENDOR_ENTRY, JVMCIVersionCheck.createOpenJDKVersion(minVersion)));
116+
} else {
117+
// LabsJDK version
118+
String optional = version.optional().get();
119+
// get the jvmci build number
120+
Assert.assertTrue("expected jvmci build number", optional.startsWith("jvmci-b"));
121+
int jvmciBuild = Integer.parseInt(optional.split("jvmci-b", 2)[1]);
122+
// get the version string without the option part
123+
String versionWithoutOptional = version.toString().split("-" + optional, 2)[0];
124+
return Map.of(Integer.toString(version.feature()), Map.of(
125+
DEFAULT_VENDOR_ENTRY, JVMCIVersionCheck.createLabsJDKVersion(versionWithoutOptional, jvmciBuild)));
126+
}
127+
}
128+
129+
private static boolean checkVersionProperties(Map<String, Map<String, JVMCIVersionCheck.Version>> minVersionMap, String javaVmVersion) {
130+
String javaSpecVersion = Integer.toString(Runtime.Version.parse(javaVmVersion).feature());
131+
var props = JVMCIVersionCheckTest.createTestProperties(javaSpecVersion, javaVmVersion, null);
132+
try {
133+
JVMCIVersionCheck.check(props, false, null, minVersionMap);
134+
return true;
135+
} catch (InternalError e) {
136+
return false;
137+
}
138+
}
139+
140+
}

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/JVMCIVersionCheckTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ public static Collection<Object[]> data() {
110110
private static Version getVersion(String jdkVersion, int major, int minor, int build) {
111111
if (jdkVersion != null) {
112112
// new version scheme
113-
return new Version(jdkVersion, build);
113+
return JVMCIVersionCheck.createLabsJDKVersion(jdkVersion, build);
114114
} else {
115115
// legacy version scheme
116-
return new Version(major, minor, build);
116+
return JVMCIVersionCheck.createLegacyVersion(major, minor, build);
117117
}
118118
}
119119

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/JVMCIVersionCheckVendorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
public class JVMCIVersionCheckVendorTest extends GraalCompilerTest {
4242

4343
private static final Map<String, Map<String, JVMCIVersionCheck.Version>> VERSION_MAP = Map.of("99", Map.of(
44-
DEFAULT_VENDOR_ENTRY, new JVMCIVersionCheck.Version("99+99", 1),
45-
"Vendor Specific", new JVMCIVersionCheck.Version("99.0.1", 1)));
44+
DEFAULT_VENDOR_ENTRY, JVMCIVersionCheck.createLabsJDKVersion("99+99", 1),
45+
"Vendor Specific", JVMCIVersionCheck.createLabsJDKVersion("99.0.1", 1)));
4646

4747
private static void expect(String javaVmVendor, String expected) {
4848
var props = JVMCIVersionCheckTest.createTestProperties("99", null, javaVmVendor);

0 commit comments

Comments
 (0)