24
24
*/
25
25
package jdk .graal .compiler .libgraal ;
26
26
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
+
27
33
import com .oracle .svm .core .annotate .Alias ;
28
34
import com .oracle .svm .core .annotate .RecomputeFieldValue ;
35
+ import com .oracle .svm .core .annotate .Substitute ;
29
36
import com .oracle .svm .core .annotate .TargetClass ;
30
37
38
+ import jdk .graal .compiler .debug .GraalError ;
39
+ import jdk .graal .compiler .debug .PathUtilities ;
40
+
31
41
class LibGraalSubstitutions {
32
42
33
43
@ TargetClass (className = "jdk.vm.ci.services.Services" , onlyWith = LibGraalFeature .IsEnabled .class )
34
44
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.
39
49
*/
40
50
// Checkstyle: stop
41
51
@ Alias //
@@ -47,11 +57,190 @@ static final class Target_jdk_vm_ci_services_Services {
47
57
@ TargetClass (className = "jdk.vm.ci.hotspot.Cleaner" , onlyWith = LibGraalFeature .IsEnabled .class )
48
58
static final class Target_jdk_vm_ci_hotspot_Cleaner {
49
59
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()} .
53
63
*/
54
64
@ Alias
55
65
public static native void clean ();
56
66
}
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
+ }
57
246
}
0 commit comments