5757import java .util .Arrays ;
5858import java .util .Collection ;
5959import java .util .Collections ;
60+ import java .util .EnumSet ;
61+ import java .util .HashMap ;
6062import java .util .HashSet ;
6163import java .util .List ;
6264import java .util .Map ;
6668import java .util .concurrent .Callable ;
6769import java .util .concurrent .ConcurrentHashMap ;
6870import java .util .function .Consumer ;
71+ import java .util .function .Function ;
6972import java .util .stream .Collectors ;
7073
7174import org .graalvm .nativeimage .ImageSingletons ;
8588import com .oracle .svm .core .MissingRegistrationUtils ;
8689import com .oracle .svm .core .configure .ConditionalRuntimeValue ;
8790import com .oracle .svm .core .configure .RuntimeConditionSet ;
91+ import com .oracle .svm .core .feature .AutomaticallyRegisteredImageSingleton ;
8892import com .oracle .svm .core .hub .ClassForNameSupport ;
8993import 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 ;
90100import com .oracle .svm .core .reflect .SubstrateAccessor ;
91101import com .oracle .svm .core .reflect .target .ReflectionSubstitutionSupport ;
92102import com .oracle .svm .core .util .VMError ;
@@ -112,6 +122,7 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
112122 private final SubstrateAnnotationExtractor annotationExtractor ;
113123 private BeforeAnalysisAccessImpl analysisAccess ;
114124 private final ClassForNameSupport classForNameSupport ;
125+ private LayeredReflectionDataBuilder layeredReflectionDataBuilder ;
115126
116127 private boolean sealed ;
117128
@@ -174,6 +185,9 @@ public void duringSetup(AnalysisMetaAccess analysisMetaAccess, AnalysisUniverse
174185 registerConditionalConfiguration (conditionalTask .condition , (cnd ) -> universe .getBigbang ().postTask (debug -> conditionalTask .task .accept (cnd )));
175186 }
176187 pendingConditionalTasks .clear ();
188+ if (ImageLayerBuildingSupport .buildingImageLayer ()) {
189+ layeredReflectionDataBuilder = LayeredReflectionDataBuilder .singleton ();
190+ }
177191 }
178192
179193 public void beforeAnalysis (BeforeAnalysisAccessImpl beforeAnalysisAccess ) {
@@ -444,6 +458,12 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe
444458
445459 AnalysisMethod analysisMethod = metaAccess .lookupJavaMethod (reflectExecutable );
446460 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+
447467 var classMethods = registeredMethods .computeIfAbsent (declaringType , t -> new ConcurrentHashMap <>());
448468 var shouldRegisterReachabilityHandler = classMethods .isEmpty ();
449469
@@ -606,6 +626,11 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel
606626 AnalysisField analysisField = metaAccess .lookupJavaField (reflectField );
607627 AnalysisType declaringClass = analysisField .getDeclaringClass ();
608628
629+ if (layeredReflectionDataBuilder != null && layeredReflectionDataBuilder .isFieldRegistered (analysisField )) {
630+ /* GR-66387: The runtime condition should be combined across layers. */
631+ return ;
632+ }
633+
609634 var classFields = registeredFields .computeIfAbsent (declaringClass , t -> new ConcurrentHashMap <>());
610635 boolean exists = classFields .containsKey (analysisField );
611636 boolean shouldRegisterReachabilityHandler = classFields .isEmpty ();
@@ -1391,4 +1416,98 @@ public static void registerField(ReflectionDataBuilder reflectionDataBuilder, bo
13911416 reflectionDataBuilder .runConditionalInAnalysisTask (ConfigurationCondition .alwaysTrue (), (cnd ) -> reflectionDataBuilder .registerField (cnd , queriedOnly , field ));
13921417 }
13931418 }
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+ }
13941513}
0 commit comments