Skip to content

Commit d5a4177

Browse files
committed
[GR-69927] Remove obsolete workarounds for libgraal building.
PullRequest: graal/22207
2 parents 06c9f07 + d85eef4 commit d5a4177

File tree

9 files changed

+248
-72
lines changed

9 files changed

+248
-72
lines changed

compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/LibGraalSubstitutions.java

Lines changed: 196 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,28 @@
2424
*/
2525
package jdk.graal.compiler.libgraal;
2626

27+
import java.io.IOException;
28+
import java.text.DateFormatSymbols;
29+
import java.time.temporal.TemporalAccessor;
30+
import java.util.Formatter;
31+
import java.util.Locale;
32+
2733
import com.oracle.svm.core.annotate.Alias;
2834
import com.oracle.svm.core.annotate.RecomputeFieldValue;
35+
import com.oracle.svm.core.annotate.Substitute;
2936
import com.oracle.svm.core.annotate.TargetClass;
3037

38+
import jdk.graal.compiler.debug.GraalError;
39+
import jdk.graal.compiler.debug.PathUtilities;
40+
3141
class LibGraalSubstitutions {
3242

3343
@TargetClass(className = "jdk.vm.ci.services.Services", onlyWith = LibGraalFeature.IsEnabled.class)
3444
static final class Target_jdk_vm_ci_services_Services {
35-
/*
36-
* Static final boolean field Services.IS_IN_NATIVE_IMAGE is used in many places in the
37-
* JVMCI codebase to switch between the different implementations needed for regular use (a
38-
* built-in module jdk.graal.compiler in the JVM) or as part of libgraal.
45+
/**
46+
* Static final boolean field {@code Services.IS_IN_NATIVE_IMAGE} is used in many places in
47+
* the JVMCI codebase to switch between the different implementations needed for regular use
48+
* (a built-in module {@code jdk.graal.compiler} in the JVM) or as part of libgraal.
3949
*/
4050
// Checkstyle: stop
4151
@Alias //
@@ -47,11 +57,190 @@ static final class Target_jdk_vm_ci_services_Services {
4757
@TargetClass(className = "jdk.vm.ci.hotspot.Cleaner", onlyWith = LibGraalFeature.IsEnabled.class)
4858
static final class Target_jdk_vm_ci_hotspot_Cleaner {
4959

50-
/*
51-
* Make package-private clean() accessible so that it can be called from
52-
* LibGraalEntryPoints.doReferenceHandling().
60+
/**
61+
* Make package-private {@code clean()} accessible so that it can be called from
62+
* {@link LibGraalSupportImpl#doReferenceHandling()}.
5363
*/
5464
@Alias
5565
public static native void clean();
5666
}
67+
68+
/**
69+
* There are no String-based class-lookups happening at libgraal runtime. Thus, we can safely
70+
* prune all classloading-logic out of the image.
71+
*/
72+
@TargetClass(value = java.lang.Class.class, onlyWith = LibGraalFeature.IsEnabled.class)
73+
static final class Target_java_lang_Class {
74+
@Substitute
75+
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
76+
throws ClassNotFoundException {
77+
throw new ClassNotFoundException(name + " (class loading not supported in libgraal)");
78+
}
79+
80+
@Substitute
81+
private static Class<?> forName(String className, Class<?> caller)
82+
throws ClassNotFoundException {
83+
throw new ClassNotFoundException(className + " (class loading not supported in libgraal)");
84+
}
85+
86+
@Substitute
87+
public static Class<?> forName(Module module, String name) {
88+
return null;
89+
}
90+
}
91+
92+
@TargetClass(value = java.lang.ClassLoader.class, onlyWith = LibGraalFeature.IsEnabled.class)
93+
static final class Target_java_lang_ClassLoader {
94+
@Substitute
95+
public Class<?> loadClass(String name) throws ClassNotFoundException {
96+
throw new ClassNotFoundException(name + " (class loading not supported in libgraal)");
97+
}
98+
99+
@Substitute
100+
static Class<?> findBootstrapClassOrNull(String name) {
101+
return null;
102+
}
103+
}
104+
105+
@TargetClass(className = "java.util.Formatter$FormatSpecifier", onlyWith = LibGraalFeature.IsEnabled.class)
106+
static final class Target_java_util_Formatter_FormatSpecifier {
107+
108+
/**
109+
* Custom version of
110+
* {@code java.util.Formatter.FormatSpecifier#localizedMagnitude(java.util.Formatter, java.lang.StringBuilder, java.lang.CharSequence, int, int, int, java.util.Locale)}
111+
* where the given locale is unconditionally replaced with {@code null}). Since the original
112+
* method was already able to accept `null` as locale, the substitution is straightforward.
113+
* The substitution does not contain any code path that requires dynamic class or resource
114+
* lookup.
115+
*/
116+
@Substitute
117+
StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb,
118+
CharSequence value, final int offset, int f, int width,
119+
Locale unused) {
120+
if (sb == null) {
121+
sb = new StringBuilder();
122+
}
123+
int begin = sb.length();
124+
125+
char zero = '0'; // getZero(l);
126+
127+
// determine localized grouping separator and size
128+
char grpSep = '\0';
129+
int grpSize = -1;
130+
char decSep = '\0';
131+
132+
int len = value.length();
133+
int dot = len;
134+
for (int j = offset; j < len; j++) {
135+
if (value.charAt(j) == '.') {
136+
dot = j;
137+
break;
138+
}
139+
}
140+
141+
if (dot < len) {
142+
decSep = '.'; // getDecimalSeparator(l);
143+
}
144+
145+
if (Target_java_util_Formatter_Flags.contains(f, Target_java_util_Formatter_Flags.GROUP)) {
146+
grpSep = ','; // getGroupingSeparator(l);
147+
148+
Locale l = null;
149+
if (l == null || l.equals(Locale.US)) {
150+
grpSize = 3;
151+
} else {
152+
throw GraalError.shouldNotReachHere("localizedMagnitude with l != null");
153+
}
154+
}
155+
156+
// localize the digits inserting group separators as necessary
157+
for (int j = offset; j < len; j++) {
158+
if (j == dot) {
159+
sb.append(decSep);
160+
// no more group separators after the decimal separator
161+
grpSep = '\0';
162+
continue;
163+
}
164+
165+
char c = value.charAt(j);
166+
sb.append((char) ((c - '0') + zero));
167+
if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) {
168+
sb.append(grpSep);
169+
}
170+
}
171+
172+
// apply zero padding
173+
if (width > sb.length() && Target_java_util_Formatter_Flags.contains(f, Target_java_util_Formatter_Flags.ZERO_PAD)) {
174+
String zeros = String.valueOf(zero).repeat(width - sb.length());
175+
sb.insert(begin, zeros);
176+
}
177+
178+
return sb;
179+
}
180+
181+
/**
182+
* Custom version of
183+
* {@code java.util.Formatter.FormatSpecifier#print(java.util.Formatter, java.time.temporal.TemporalAccessor, char, java.util.Locale)}
184+
* where the given locale is unconditionally replaced with {@code null}). Since the original
185+
* method was already able to accept `null` as locale, the substitution is straightforward.
186+
* The substitution does not contain any code path that requires dynamic class or resource
187+
* lookup.
188+
*/
189+
@Substitute
190+
void print(Target_java_util_Formatter fmt, TemporalAccessor t, char c, Locale unused) throws IOException {
191+
StringBuilder sb = new StringBuilder();
192+
print(fmt, sb, t, c, null);
193+
// justify based on width
194+
if (Target_java_util_Formatter_Flags.contains(flags, Target_java_util_Formatter_Flags.UPPERCASE)) {
195+
appendJustified(fmt.a, sb.toString().toUpperCase(Locale.ROOT));
196+
} else {
197+
appendJustified(fmt.a, sb);
198+
}
199+
}
200+
201+
@Alias
202+
native Appendable print(Target_java_util_Formatter fmt, StringBuilder sb, TemporalAccessor t, char c,
203+
Locale l) throws IOException;
204+
205+
@Alias
206+
native void appendJustified(Appendable a, CharSequence cs) throws IOException;
207+
208+
@Alias //
209+
int flags;
210+
}
211+
212+
@TargetClass(className = "java.util.Formatter", onlyWith = LibGraalFeature.IsEnabled.class)
213+
static final class Target_java_util_Formatter {
214+
@Alias //
215+
Appendable a;
216+
}
217+
218+
@TargetClass(className = "java.util.Formatter$Flags", onlyWith = LibGraalFeature.IsEnabled.class)
219+
static final class Target_java_util_Formatter_Flags {
220+
// Checkstyle: stop
221+
@Alias //
222+
static int ZERO_PAD;
223+
@Alias //
224+
static int GROUP;
225+
@Alias //
226+
static int UPPERCASE;
227+
// Checkstyle: resume
228+
229+
@Alias
230+
static native boolean contains(int flags, int f);
231+
}
232+
233+
@TargetClass(value = java.text.DateFormatSymbols.class, onlyWith = LibGraalFeature.IsEnabled.class)
234+
static final class Target_java_text_DateFormatSymbols {
235+
/**
236+
* {@link DateFormatSymbols#getInstance(Locale)} relies on String-based class-lookup (to
237+
* find resource bundle {@code sun.text.resources.cldr.FormatData}) which we do not want to
238+
* rely on at libgraal runtime because it increases image size too much. Instead, we return
239+
* the DateFormatSymbols instance that we already have in the image heap.
240+
*/
241+
@Substitute
242+
public static DateFormatSymbols getInstance(Locale unused) {
243+
return PathUtilities.getSharedDateFormatSymbols();
244+
}
245+
}
57246
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
import static jdk.graal.compiler.debug.PathUtilities.createDirectories;
2828
import static jdk.graal.compiler.debug.PathUtilities.exists;
2929
import static jdk.graal.compiler.debug.PathUtilities.getAbsolutePath;
30+
import static jdk.graal.compiler.debug.PathUtilities.getDateString;
3031
import static jdk.graal.compiler.debug.PathUtilities.getPath;
3132

3233
import java.io.IOException;
33-
import java.text.SimpleDateFormat;
3434
import java.util.Date;
3535

3636
import jdk.graal.compiler.options.EnumMultiOptionKey;
@@ -333,8 +333,7 @@ public static String getDumpDirectoryName(OptionValues options) {
333333
dumpDir = getPath(DumpPath.getValue(options));
334334
} else {
335335
Date date = new Date(GraalServices.getGlobalTimeStamp());
336-
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.SSS");
337-
dumpDir = getPath(DumpPath.getValue(options), formatter.format(date));
336+
dumpDir = getPath(DumpPath.getValue(options), getDateString(date));
338337
}
339338
dumpDir = getAbsolutePath(dumpDir);
340339
return dumpDir;

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/PathUtilities.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@
3434
import java.nio.file.InvalidPathException;
3535
import java.nio.file.OpenOption;
3636
import java.nio.file.Path;
37+
import java.text.DateFormatSymbols;
38+
import java.text.SimpleDateFormat;
39+
import java.util.Date;
3740
import java.util.Iterator;
3841
import java.util.ServiceLoader;
42+
import java.util.TimeZone;
3943

4044
/**
4145
* Miscellaneous methods for modifying and generating file system paths.
@@ -85,6 +89,34 @@ public static String getPath(String first, String... more) {
8589
return PROVIDER.getPath(first, more);
8690
}
8791

92+
/**
93+
* This circumvents instantiating {@link SimpleDateFormat} at libgraal runtime. This is needed
94+
* to avoid String-based class-lookup (to find resource bundle
95+
* {@code sun.text.resources.cldr.FormatData} as part of {@link SimpleDateFormat} construction)
96+
* and allows us to avoid class-lookup support in the image.
97+
*/
98+
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = getSimpleDateFormat();
99+
100+
private static SimpleDateFormat getSimpleDateFormat() {
101+
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.SSS");
102+
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
103+
return simpleDateFormat;
104+
}
105+
106+
public static DateFormatSymbols getSharedDateFormatSymbols() {
107+
// SimpleDateFormat is not thread-safe
108+
synchronized (SIMPLE_DATE_FORMAT) {
109+
return SIMPLE_DATE_FORMAT.getDateFormatSymbols();
110+
}
111+
}
112+
113+
public static String getDateString(Date date) {
114+
// SimpleDateFormat is not thread-safe
115+
synchronized (SIMPLE_DATE_FORMAT) {
116+
return SIMPLE_DATE_FORMAT.format(date);
117+
}
118+
}
119+
88120
/**
89121
* Gets the absolute pathname of {@code path}.
90122
*/

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/printer/GraphPrinterDumpHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import static jdk.graal.compiler.debug.DebugConfig.asJavaMethod;
2828
import static jdk.graal.compiler.debug.DebugOptions.PrintUnmodifiedGraphs;
29+
import static jdk.graal.compiler.debug.PathUtilities.getDateString;
2930

3031
import java.io.IOException;
3132
import java.nio.channels.ClosedByInterruptException;
@@ -346,7 +347,8 @@ private void openScope(DebugContext debug, String name, int inlineDepth, Map<Obj
346347
if (sunJavaCommand != null) {
347348
props.put("sun.java.command", sunJavaCommand);
348349
}
349-
props.put("date", new Date().toString());
350+
Date date = new Date(GraalServices.getGlobalTimeStamp());
351+
props.put("date", getDateString(date));
350352
}
351353
printer.beginGroup(debug, name, name, debug.contextLookup(ResolvedJavaMethod.class), -1, props);
352354
} catch (IOException e) {

sdk/src/com.oracle.svm.core.annotate/src/com/oracle/svm/core/annotate/TargetClass.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -47,7 +47,6 @@
4747
import java.util.function.BooleanSupplier;
4848
import java.util.function.Function;
4949
import java.util.function.Predicate;
50-
import java.util.function.Supplier;
5150

5251
import org.graalvm.nativeimage.Platform;
5352
import org.graalvm.nativeimage.Platforms;
@@ -141,21 +140,6 @@
141140
*/
142141
String[] innerClass() default {};
143142

144-
/**
145-
* Specifies a custom classloader that will be used to look up the substitutee class name.
146-
*
147-
* @since 24.2
148-
*/
149-
Class<? extends Supplier<ClassLoader>> classLoader() default NoClassLoaderProvider.class;
150-
151-
/**
152-
* Marker value for {@link #classLoader} that no custom classloader should be used.
153-
*
154-
* @since 24.2
155-
*/
156-
interface NoClassLoaderProvider extends Supplier<ClassLoader> {
157-
}
158-
159143
/**
160144
* Substitute only if all provided predicates are true (default: unconditional substitution that
161145
* is always included).

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,17 @@ def prevent_build_path_in_libgraal():
16921692
'-H:+JNIEnhancedErrorCodes',
16931693
'-H:InitialCollectionPolicy=LibGraal',
16941694

1695+
# A libgraal image contains classes with the same FQN loaded by different classloaders.
1696+
# I.e. the SVM runtime depends on
1697+
# - jdk.vm.ci.* classes loaded by the bootstrap classloader
1698+
# - jdk.graal.compiler.options.* classes loaded by the platform classloader
1699+
# - org.graalvm.collections.* classes loaded by the app classloader
1700+
# But potentially different versions of those classes are also loaded by the
1701+
# LibGraalClassLoader as part of the classes that libgraal consist of.
1702+
# Thus, we cannot use the naive default ClassForName implementation that only
1703+
# works if there are no two different classes in the image with the same FQN.
1704+
'-H:+ClassForNameRespectsClassLoader',
1705+
16951706
# Needed for initializing jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE.
16961707
# Remove after JDK-8346781.
16971708
'-Djdk.vm.ci.services.aot=true',

0 commit comments

Comments
 (0)