42
42
import java .util .List ;
43
43
import java .util .Objects ;
44
44
import java .util .Set ;
45
+ import java .util .function .Predicate ;
45
46
import java .util .function .Supplier ;
46
47
import java .util .stream .Collectors ;
47
48
import java .util .stream .Stream ;
58
59
import org .graalvm .compiler .nodes .graphbuilderconf .InvocationPlugins .Registration ;
59
60
import org .graalvm .compiler .options .Option ;
60
61
import org .graalvm .nativeimage .ImageSingletons ;
62
+ import org .graalvm .nativeimage .hosted .RuntimeReflection ;
63
+ import org .graalvm .nativeimage .impl .RuntimeClassInitializationSupport ;
61
64
62
65
import com .oracle .graal .pointsto .infrastructure .OriginalClassProvider ;
63
66
import com .oracle .graal .pointsto .meta .AnalysisUniverse ;
72
75
import com .oracle .svm .core .util .VMError ;
73
76
import com .oracle .svm .hosted .ExceptionSynthesizer ;
74
77
import com .oracle .svm .hosted .ImageClassLoader ;
78
+ import com .oracle .svm .hosted .classinitialization .ClassInitializationSupport ;
75
79
import com .oracle .svm .hosted .substitute .AnnotationSubstitutionProcessor ;
76
80
import com .oracle .svm .hosted .substitute .DeletedElementException ;
77
81
import com .oracle .svm .util .ModuleSupport ;
@@ -165,6 +169,7 @@ public static void registerInvocationPlugins(ImageClassLoader imageClassLoader,
165
169
ByteOrder .class ));
166
170
167
171
private void registerMethodHandlesPlugins (InvocationPlugins plugins ) {
172
+
168
173
registerFoldInvocationPlugins (plugins , MethodHandles .class ,
169
174
"publicLookup" , "privateLookupIn" ,
170
175
"arrayConstructor" , "arrayLength" , "arrayElementGetter" , "arrayElementSetter" , "arrayElementVarHandle" ,
@@ -174,16 +179,18 @@ private void registerMethodHandlesPlugins(InvocationPlugins plugins) {
174
179
"in" ,
175
180
"findStatic" , "findVirtual" , "findConstructor" , "findClass" , "accessClass" , "findSpecial" ,
176
181
"findGetter" , "findSetter" , "findVarHandle" ,
177
- "findStaticGetter" , "findStaticSetter" , "findStaticVarHandle" ,
182
+ "findStaticGetter" , "findStaticSetter" ,
178
183
"unreflect" , "unreflectSpecial" , "unreflectConstructor" ,
179
- "unreflectGetter" , "unreflectSetter" , "unreflectVarHandle" );
184
+ "unreflectGetter" , "unreflectSetter" );
180
185
181
186
registerFoldInvocationPlugins (plugins , MethodType .class ,
182
187
"methodType" , "genericMethodType" ,
183
188
"changeParameterType" , "insertParameterTypes" , "appendParameterTypes" , "replaceParameterTypes" , "dropParameterTypes" ,
184
189
"changeReturnType" , "erase" , "generic" , "wrap" , "unwrap" ,
185
190
"parameterType" , "parameterCount" , "returnType" , "lastParameterType" );
186
191
192
+ registerConditionalFoldInvocationPlugins (plugins );
193
+
187
194
Registration r = new Registration (plugins , MethodHandles .class );
188
195
r .register (new RequiredInlineOnlyInvocationPlugin ("lookup" ) {
189
196
@ Override
@@ -193,6 +200,46 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
193
200
});
194
201
}
195
202
203
+ /**
204
+ * For some methods check if folding an invocation using reflection, i.e., by executing the
205
+ * target method and capturing the result, has undesired side effects, such as triggering
206
+ * initialization of classes that should be initialized at run time. This is based on knowledge
207
+ * about the reflection API methods implementation.
208
+ */
209
+ private void registerConditionalFoldInvocationPlugins (InvocationPlugins plugins ) {
210
+ Method methodHandlesLookupFindStaticVarHandle = ReflectionUtil .lookupMethod (MethodHandles .Lookup .class , "findStaticVarHandle" , Class .class , String .class , Class .class );
211
+ registerFoldInvocationPlugin (plugins , methodHandlesLookupFindStaticVarHandle , (args ) -> {
212
+ /* VarHandles.makeFieldHandle() triggers init of receiver class (JDK-8291065). */
213
+ Object classArg = args [0 ];
214
+ if (classArg instanceof Class <?>) {
215
+ if (shouldInitializeAtRuntime ((Class <?>) classArg )) {
216
+ /* Skip the folding and register the field for run time reflection. */
217
+ RuntimeReflection .register (ReflectionUtil .lookupField ((Class <?>) args [0 ], (String ) args [1 ]));
218
+ return false ;
219
+ }
220
+ }
221
+ return true ;
222
+ });
223
+
224
+ Method methodHandlesLookupUnreflectVarHandle = ReflectionUtil .lookupMethod (MethodHandles .Lookup .class , "unreflectVarHandle" , Field .class );
225
+ registerFoldInvocationPlugin (plugins , methodHandlesLookupUnreflectVarHandle , (args ) -> {
226
+ /*
227
+ * VarHandles.makeFieldHandle() triggers init of static field's declaring class
228
+ * (JDK-8291065).
229
+ */
230
+ Object fieldArg = args [0 ];
231
+ if (fieldArg instanceof Field ) {
232
+ Field field = (Field ) fieldArg ;
233
+ if (isStatic (field ) && shouldInitializeAtRuntime (field .getDeclaringClass ())) {
234
+ /* Skip the folding and register the field for run time reflection. */
235
+ RuntimeReflection .register (field );
236
+ return false ;
237
+ }
238
+ }
239
+ return true ;
240
+ });
241
+ }
242
+
196
243
private void registerClassPlugins (InvocationPlugins plugins ) {
197
244
registerFoldInvocationPlugins (plugins , Class .class ,
198
245
"getField" , "getMethod" , "getConstructor" ,
@@ -326,7 +373,13 @@ private void registerFoldInvocationPlugins(InvocationPlugins plugins, Class<?> d
326
373
}
327
374
}
328
375
376
+ private static final Predicate <Object []> alwaysAllowConstantFolding = args -> true ;
377
+
329
378
private void registerFoldInvocationPlugin (InvocationPlugins plugins , Method reflectionMethod ) {
379
+ registerFoldInvocationPlugin (plugins , reflectionMethod , alwaysAllowConstantFolding );
380
+ }
381
+
382
+ private void registerFoldInvocationPlugin (InvocationPlugins plugins , Method reflectionMethod , Predicate <Object []> allowConstantFolding ) {
330
383
if (!ALLOWED_CONSTANT_CLASSES .contains (reflectionMethod .getReturnType ()) && !reflectionMethod .getReturnType ().isPrimitive ()) {
331
384
throw VMError .shouldNotReachHere ("Return type of method " + reflectionMethod + " is not on the allow-list for types that are immutable" );
332
385
}
@@ -341,12 +394,13 @@ private void registerFoldInvocationPlugin(InvocationPlugins plugins, Method refl
341
394
plugins .register (reflectionMethod .getDeclaringClass (), new RequiredInvocationPlugin (reflectionMethod .getName (), parameterTypes .toArray (new Class <?>[0 ])) {
342
395
@ Override
343
396
public boolean defaultHandler (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Receiver receiver , ValueNode ... args ) {
344
- return foldInvocationUsingReflection (b , targetMethod , reflectionMethod , receiver , args );
397
+ return foldInvocationUsingReflection (b , targetMethod , reflectionMethod , receiver , args , allowConstantFolding );
345
398
}
346
399
});
347
400
}
348
401
349
- private boolean foldInvocationUsingReflection (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Method reflectionMethod , Receiver receiver , ValueNode [] args ) {
402
+ private boolean foldInvocationUsingReflection (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Method reflectionMethod , Receiver receiver , ValueNode [] args ,
403
+ Predicate <Object []> allowConstantFolding ) {
350
404
assert b .getMetaAccess ().lookupJavaMethod (reflectionMethod ).equals (targetMethod ) : "Fold method mismatch: " + reflectionMethod + " != " + targetMethod ;
351
405
352
406
Object receiverValue ;
@@ -376,6 +430,10 @@ private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJav
376
430
}
377
431
}
378
432
433
+ if (!allowConstantFolding .test (argValues )) {
434
+ return false ;
435
+ }
436
+
379
437
/* String representation of the parameters for debug printing. */
380
438
Supplier <String > targetParameters = () -> (receiverValue == null ? "" : receiverValue .toString () + "; " ) +
381
439
Stream .of (argValues ).map (arg -> arg instanceof Object [] ? Arrays .toString ((Object []) arg ) : Objects .toString (arg )).collect (Collectors .joining (", " ));
@@ -401,6 +459,15 @@ private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJav
401
459
return pushConstant (b , targetMethod , targetParameters , returnKind , returnValue , false ) != null ;
402
460
}
403
461
462
+ private static boolean shouldInitializeAtRuntime (Class <?> classArg ) {
463
+ ClassInitializationSupport classInitializationSupport = (ClassInitializationSupport ) ImageSingletons .lookup (RuntimeClassInitializationSupport .class );
464
+ return classInitializationSupport .shouldInitializeAtRuntime (classArg );
465
+ }
466
+
467
+ private static boolean isStatic (Field field ) {
468
+ return Modifier .isStatic (field .getModifiers ());
469
+ }
470
+
404
471
private Object unbox (GraphBuilderContext b , ValueNode arg , JavaKind argKind ) {
405
472
if (!arg .isJavaConstant ()) {
406
473
/*
0 commit comments