2424 */
2525package 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+
2733import com .oracle .svm .core .annotate .Alias ;
2834import com .oracle .svm .core .annotate .RecomputeFieldValue ;
35+ import com .oracle .svm .core .annotate .Substitute ;
2936import com .oracle .svm .core .annotate .TargetClass ;
3037
38+ import jdk .graal .compiler .debug .GraalError ;
39+ import jdk .graal .compiler .debug .PathUtilities ;
40+
3141class 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}
0 commit comments