57
57
import java .util .Arrays ;
58
58
import java .util .Collection ;
59
59
import java .util .Collections ;
60
+ import java .util .EnumSet ;
61
+ import java .util .HashMap ;
60
62
import java .util .HashSet ;
61
63
import java .util .List ;
62
64
import java .util .Map ;
66
68
import java .util .concurrent .Callable ;
67
69
import java .util .concurrent .ConcurrentHashMap ;
68
70
import java .util .function .Consumer ;
71
+ import java .util .function .Function ;
69
72
import java .util .stream .Collectors ;
70
73
71
74
import org .graalvm .nativeimage .ImageSingletons ;
85
88
import com .oracle .svm .core .MissingRegistrationUtils ;
86
89
import com .oracle .svm .core .configure .ConditionalRuntimeValue ;
87
90
import com .oracle .svm .core .configure .RuntimeConditionSet ;
91
+ import com .oracle .svm .core .feature .AutomaticallyRegisteredImageSingleton ;
88
92
import com .oracle .svm .core .hub .ClassForNameSupport ;
89
93
import com .oracle .svm .core .hub .DynamicHub ;
94
+ import com .oracle .svm .core .imagelayer .BuildingImageLayerPredicate ;
95
+ import com .oracle .svm .core .imagelayer .ImageLayerBuildingSupport ;
96
+ import com .oracle .svm .core .layeredimagesingleton .ImageSingletonLoader ;
97
+ import com .oracle .svm .core .layeredimagesingleton .ImageSingletonWriter ;
98
+ import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingleton ;
99
+ import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonBuilderFlags ;
90
100
import com .oracle .svm .core .reflect .SubstrateAccessor ;
91
101
import com .oracle .svm .core .reflect .target .ReflectionSubstitutionSupport ;
92
102
import com .oracle .svm .core .util .VMError ;
@@ -112,6 +122,7 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
112
122
private final SubstrateAnnotationExtractor annotationExtractor ;
113
123
private BeforeAnalysisAccessImpl analysisAccess ;
114
124
private final ClassForNameSupport classForNameSupport ;
125
+ private LayeredReflectionDataBuilder layeredReflectionDataBuilder ;
115
126
116
127
private boolean sealed ;
117
128
@@ -174,6 +185,9 @@ public void duringSetup(AnalysisMetaAccess analysisMetaAccess, AnalysisUniverse
174
185
registerConditionalConfiguration (conditionalTask .condition , (cnd ) -> universe .getBigbang ().postTask (debug -> conditionalTask .task .accept (cnd )));
175
186
}
176
187
pendingConditionalTasks .clear ();
188
+ if (ImageLayerBuildingSupport .buildingImageLayer ()) {
189
+ layeredReflectionDataBuilder = LayeredReflectionDataBuilder .singleton ();
190
+ }
177
191
}
178
192
179
193
public void beforeAnalysis (BeforeAnalysisAccessImpl beforeAnalysisAccess ) {
@@ -444,6 +458,12 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe
444
458
445
459
AnalysisMethod analysisMethod = metaAccess .lookupJavaMethod (reflectExecutable );
446
460
AnalysisType declaringType = analysisMethod .getDeclaringClass ();
461
+
462
+ if (layeredReflectionDataBuilder != null && layeredReflectionDataBuilder .isMethodRegistered (analysisMethod )) {
463
+ /* GR-66387: The runtime condition should be combined across layers. */
464
+ return ;
465
+ }
466
+
447
467
var classMethods = registeredMethods .computeIfAbsent (declaringType , t -> new ConcurrentHashMap <>());
448
468
var shouldRegisterReachabilityHandler = classMethods .isEmpty ();
449
469
@@ -606,6 +626,11 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel
606
626
AnalysisField analysisField = metaAccess .lookupJavaField (reflectField );
607
627
AnalysisType declaringClass = analysisField .getDeclaringClass ();
608
628
629
+ if (layeredReflectionDataBuilder != null && layeredReflectionDataBuilder .isFieldRegistered (analysisField )) {
630
+ /* GR-66387: The runtime condition should be combined across layers. */
631
+ return ;
632
+ }
633
+
609
634
var classFields = registeredFields .computeIfAbsent (declaringClass , t -> new ConcurrentHashMap <>());
610
635
boolean exists = classFields .containsKey (analysisField );
611
636
boolean shouldRegisterReachabilityHandler = classFields .isEmpty ();
@@ -1391,4 +1416,98 @@ public static void registerField(ReflectionDataBuilder reflectionDataBuilder, bo
1391
1416
reflectionDataBuilder .runConditionalInAnalysisTask (ConfigurationCondition .alwaysTrue (), (cnd ) -> reflectionDataBuilder .registerField (cnd , queriedOnly , field ));
1392
1417
}
1393
1418
}
1419
+
1420
+ @ AutomaticallyRegisteredImageSingleton (onlyWith = BuildingImageLayerPredicate .class )
1421
+ public static class LayeredReflectionDataBuilder implements LayeredImageSingleton {
1422
+ public static final String METHODS = "methods" ;
1423
+ public static final String FIELDS = "fields" ;
1424
+ public static final String REFLECTION_DATA_BUILDER = "reflection data builder" ;
1425
+ public static final String REFLECTION_DATA_BUILDER_CLASSES = REFLECTION_DATA_BUILDER + " classes" ;
1426
+ /**
1427
+ * The methods registered for reflection in the previous layers. The key of the map is the
1428
+ * id of the declaring type and the set contains the method ids.
1429
+ */
1430
+ private final Map <Integer , Set <Integer >> previousLayerRegisteredMethods ;
1431
+ /**
1432
+ * The fields registered for reflection in the previous layers. The key of the map is the id
1433
+ * of the declaring type and the set contains the field ids.
1434
+ */
1435
+ private final Map <Integer , Set <Integer >> previousLayerRegisteredFields ;
1436
+
1437
+ public LayeredReflectionDataBuilder () {
1438
+ this (Map .of (), Map .of ());
1439
+ }
1440
+
1441
+ private LayeredReflectionDataBuilder (Map <Integer , Set <Integer >> previousLayerRegisteredMethods , Map <Integer , Set <Integer >> previousLayerRegisteredFields ) {
1442
+ this .previousLayerRegisteredMethods = previousLayerRegisteredMethods ;
1443
+ this .previousLayerRegisteredFields = previousLayerRegisteredFields ;
1444
+ }
1445
+
1446
+ public static LayeredReflectionDataBuilder singleton () {
1447
+ return ImageSingletons .lookup (LayeredReflectionDataBuilder .class );
1448
+ }
1449
+
1450
+ public boolean isMethodRegistered (AnalysisMethod analysisMethod ) {
1451
+ return isElementRegistered (previousLayerRegisteredMethods , analysisMethod .getDeclaringClass (), analysisMethod .getId ());
1452
+ }
1453
+
1454
+ public boolean isFieldRegistered (AnalysisField analysisField ) {
1455
+ return isElementRegistered (previousLayerRegisteredFields , analysisField .getDeclaringClass (), analysisField .getId ());
1456
+ }
1457
+
1458
+ private static boolean isElementRegistered (Map <Integer , Set <Integer >> previousLayerRegisteredElements , AnalysisType declaringClass , int elementId ) {
1459
+ Set <Integer > previousLayerRegisteredElementIds = previousLayerRegisteredElements .get (declaringClass .getId ());
1460
+ if (declaringClass .isInBaseLayer () && previousLayerRegisteredElementIds != null ) {
1461
+ return previousLayerRegisteredElementIds .contains (elementId );
1462
+ }
1463
+ return false ;
1464
+ }
1465
+
1466
+ @ Override
1467
+ public EnumSet <LayeredImageSingletonBuilderFlags > getImageBuilderFlags () {
1468
+ return LayeredImageSingletonBuilderFlags .BUILDTIME_ACCESS_ONLY ;
1469
+ }
1470
+
1471
+ @ Override
1472
+ public PersistFlags preparePersist (ImageSingletonWriter writer ) {
1473
+ ReflectionDataBuilder reflectionDataBuilder = (ReflectionDataBuilder ) ImageSingletons .lookup (RuntimeReflectionSupport .class );
1474
+ persistRegisteredElements (writer , reflectionDataBuilder .registeredMethods , AnalysisMethod ::getId , METHODS );
1475
+ persistRegisteredElements (writer , reflectionDataBuilder .registeredFields , AnalysisField ::getId , FIELDS );
1476
+ return PersistFlags .CREATE ;
1477
+ }
1478
+
1479
+ private static <T , U > void persistRegisteredElements (ImageSingletonWriter writer , Map <AnalysisType , Map <T , U >> registeredElements , Function <T , Integer > getId , String element ) {
1480
+ List <Integer > classes = new ArrayList <>();
1481
+ for (var entry : registeredElements .entrySet ()) {
1482
+ classes .add (entry .getKey ().getId ());
1483
+ writer .writeIntList (getElementKeyName (element , entry .getKey ().getId ()), entry .getValue ().keySet ().stream ().map (getId ).toList ());
1484
+ }
1485
+ writer .writeIntList (getClassesKeyName (element ), classes );
1486
+ }
1487
+
1488
+ @ SuppressWarnings ("unused" )
1489
+ public static Object createFromLoader (ImageSingletonLoader loader ) {
1490
+ var previousLayerRegisteredMethods = loadRegisteredElements (loader , METHODS );
1491
+ var previousLayerRegisteredFields = loadRegisteredElements (loader , FIELDS );
1492
+ return new LayeredReflectionDataBuilder (previousLayerRegisteredMethods , previousLayerRegisteredFields );
1493
+ }
1494
+
1495
+ private static Map <Integer , Set <Integer >> loadRegisteredElements (ImageSingletonLoader loader , String element ) {
1496
+ Map <Integer , Set <Integer >> previousLayerRegisteredElements = new HashMap <>();
1497
+ var classes = loader .readIntList (getClassesKeyName (element ));
1498
+ for (int key : classes ) {
1499
+ var elements = loader .readIntList (getElementKeyName (element , key )).stream ().collect (Collectors .toUnmodifiableSet ());
1500
+ previousLayerRegisteredElements .put (key , elements );
1501
+ }
1502
+ return Collections .unmodifiableMap (previousLayerRegisteredElements );
1503
+ }
1504
+
1505
+ private static String getClassesKeyName (String element ) {
1506
+ return REFLECTION_DATA_BUILDER_CLASSES + " " + element ;
1507
+ }
1508
+
1509
+ private static String getElementKeyName (String element , int typeId ) {
1510
+ return REFLECTION_DATA_BUILDER + " " + element + " " + typeId ;
1511
+ }
1512
+ }
1394
1513
}
0 commit comments