24
24
*/
25
25
package com .oracle .svm .hosted .image ;
26
26
27
+ import static com .oracle .graal .pointsto .api .PointstoOptions .UseConservativeUnsafeAccess ;
28
+ import static com .oracle .svm .core .SubstrateOptions .Preserve ;
29
+
30
+ import java .lang .reflect .Constructor ;
31
+ import java .lang .reflect .Field ;
32
+ import java .lang .reflect .Method ;
33
+ import java .lang .reflect .Modifier ;
27
34
import java .util .Arrays ;
35
+ import java .util .Collections ;
36
+ import java .util .Comparator ;
37
+ import java .util .HashSet ;
28
38
import java .util .Set ;
29
39
import java .util .stream .Stream ;
30
40
31
41
import org .graalvm .collections .EconomicMap ;
42
+ import org .graalvm .nativeimage .ImageSingletons ;
43
+ import org .graalvm .nativeimage .impl .ConfigurationCondition ;
44
+ import org .graalvm .nativeimage .impl .RuntimeJNIAccessSupport ;
45
+ import org .graalvm .nativeimage .impl .RuntimeProxyCreationSupport ;
46
+ import org .graalvm .nativeimage .impl .RuntimeReflectionSupport ;
32
47
48
+ import com .oracle .graal .pointsto .ClassInclusionPolicy ;
33
49
import com .oracle .svm .core .SubstrateOptions ;
34
50
import com .oracle .svm .core .option .AccumulatingLocatableMultiOptionValue ;
35
51
import com .oracle .svm .core .option .LocatableMultiOptionValue ;
36
52
import com .oracle .svm .core .option .SubstrateOptionsParser ;
37
53
import com .oracle .svm .core .util .UserError ;
38
54
import com .oracle .svm .hosted .NativeImageClassLoaderSupport ;
39
55
import com .oracle .svm .hosted .driver .IncludeOptionsSupport ;
56
+ import com .oracle .svm .util .ReflectionUtil ;
40
57
41
58
import jdk .graal .compiler .options .OptionKey ;
42
59
import jdk .graal .compiler .options .OptionValues ;
@@ -93,7 +110,8 @@ private static String preservePossibleOptions() {
93
110
}
94
111
95
112
public static void parsePreserveOption (EconomicMap <OptionKey <?>, Object > hostedValues , NativeImageClassLoaderSupport classLoaderSupport ) {
96
- AccumulatingLocatableMultiOptionValue .Strings preserve = SubstrateOptions .Preserve .getValue (new OptionValues (hostedValues ));
113
+ OptionValues optionValues = new OptionValues (hostedValues );
114
+ AccumulatingLocatableMultiOptionValue .Strings preserve = SubstrateOptions .Preserve .getValue (optionValues );
97
115
Stream <LocatableMultiOptionValue .ValueWithOrigin <String >> valuesWithOrigins = preserve .getValuesWithOrigins ();
98
116
valuesWithOrigins .forEach (valueWithOrigin -> {
99
117
String optionArgument = SubstrateOptionsParser .commandArgument (SubstrateOptions .Preserve , valueWithOrigin .value (), true , false );
@@ -112,5 +130,95 @@ public static void parsePreserveOption(EconomicMap<OptionKey<?>, Object> hostedV
112
130
}
113
131
}
114
132
});
133
+ if (classLoaderSupport .isPreserveMode ()) {
134
+ if (UseConservativeUnsafeAccess .hasBeenSet (optionValues )) {
135
+ UserError .guarantee (UseConservativeUnsafeAccess .getValue (optionValues ), "%s can not be used together with %s. Please unset %s." ,
136
+ SubstrateOptionsParser .commandArgument (UseConservativeUnsafeAccess , "-" ),
137
+ SubstrateOptionsParser .commandArgument (Preserve , "<value>" ),
138
+ SubstrateOptionsParser .commandArgument (UseConservativeUnsafeAccess , "-" ));
139
+ }
140
+ UseConservativeUnsafeAccess .update (hostedValues , true );
141
+ }
142
+ }
143
+
144
+ public static void registerPreservedClasses (NativeImageClassLoaderSupport classLoaderSupport ) {
145
+ var classesOrPackagesToIgnore = ignoredClassesOrPackagesForPreserve ();
146
+ var classesToPreserve = classLoaderSupport .getClassesToPreserve ()
147
+ .filter (ClassInclusionPolicy ::isClassIncludedBase )
148
+ .filter (c -> !(classesOrPackagesToIgnore .contains (c .getPackageName ()) || classesOrPackagesToIgnore .contains (c .getName ())))
149
+ .sorted (Comparator .comparing (ReflectionUtil ::getClassHierarchyDepth ).reversed ())
150
+ .toList ();
151
+
152
+ final RuntimeReflectionSupport reflection = ImageSingletons .lookup (RuntimeReflectionSupport .class );
153
+ final RuntimeJNIAccessSupport jni = ImageSingletons .lookup (RuntimeJNIAccessSupport .class );
154
+ final RuntimeProxyCreationSupport proxy = ImageSingletons .lookup (RuntimeProxyCreationSupport .class );
155
+ final ConfigurationCondition always = ConfigurationCondition .alwaysTrue ();
156
+
157
+ /*
158
+ * Sort descending by class hierarchy depth to avoid complexity related to field
159
+ * registration.
160
+ */
161
+ classesToPreserve .forEach (c -> {
162
+ reflection .register (always , false , c );
163
+
164
+ reflection .registerAllDeclaredFields (always , c );
165
+ reflection .registerAllDeclaredMethodsQuery (always , false , c );
166
+ reflection .registerAllDeclaredConstructorsQuery (always , false , c );
167
+ reflection .registerAllConstructorsQuery (always , false , c );
168
+ reflection .registerAllClassesQuery (always , c );
169
+ reflection .registerAllDeclaredClassesQuery (always , c );
170
+ reflection .registerAllNestMembersQuery (always , c );
171
+ reflection .registerAllPermittedSubclassesQuery (always , c );
172
+ reflection .registerAllRecordComponentsQuery (always , c );
173
+ reflection .registerAllSignersQuery (always , c );
174
+
175
+ /* Register every single-interface proxy */
176
+ // GR-62293 can't register proxies from jdk modules.
177
+ if (c .getModule () == null && c .isInterface ()) {
178
+ proxy .addProxyClass (always , c );
179
+ }
180
+
181
+ jni .register (ConfigurationCondition .alwaysTrue (), c );
182
+ try {
183
+ for (Method declaredMethod : c .getDeclaredMethods ()) {
184
+ jni .register (always , false , declaredMethod );
185
+ }
186
+ for (Constructor <?> declaredConstructor : c .getDeclaredConstructors ()) {
187
+ jni .register (always , false , declaredConstructor );
188
+ }
189
+ for (Field declaredField : c .getDeclaredFields ()) {
190
+ jni .register (always , false , declaredField );
191
+ reflection .register (always , false , declaredField );
192
+ }
193
+ } catch (LinkageError e ) {
194
+ /* If we can't link we can not register for JNI and reflection */
195
+ }
196
+
197
+ // if we register as unsafe allocated earlier there are build-time
198
+ // initialization errors
199
+ reflection .register (always , !(c .isArray () || c .isInterface () || c .isPrimitive () || Modifier .isAbstract (c .getModifiers ())), c );
200
+ });
201
+
202
+ /*
203
+ * We now register super-type methods and fields in a separate pass--when all subtypes have
204
+ * been fully registered. We do it the opposite order to avoid crawling the hierarchy
205
+ * upwards multiple times when caching is implemented.
206
+ */
207
+ classesToPreserve .reversed ().forEach (c -> {
208
+ reflection .registerAllFields (always , c );
209
+ reflection .registerAllMethodsQuery (always , false , c );
210
+ // RuntimeSerialization.register(c);
211
+ });
212
+
213
+ for (String className : classLoaderSupport .getClassNamesToPreserve ()) {
214
+ reflection .registerClassLookup (always , className );
215
+ }
216
+ }
217
+
218
+ private static Set <String > ignoredClassesOrPackagesForPreserve () {
219
+ Set <String > ignoredClassesOrPackages = new HashSet <>(SubstrateOptions .IgnorePreserveForClasses .getValue ().valuesAsSet ());
220
+ // GR-63360: Parsing of constant_ lambda forms fails
221
+ ignoredClassesOrPackages .add ("java.lang.invoke.LambdaForm$Holder" );
222
+ return Collections .unmodifiableSet (ignoredClassesOrPackages );
115
223
}
116
224
}
0 commit comments