24
24
*/
25
25
package com .oracle .svm .core .hub ;
26
26
27
+ import java .util .ArrayList ;
28
+ import java .util .Collections ;
27
29
import java .util .EnumSet ;
30
+ import java .util .HashMap ;
31
+ import java .util .List ;
32
+ import java .util .Map ;
28
33
29
34
import org .graalvm .collections .EconomicMap ;
30
35
import org .graalvm .nativeimage .Platform ;
31
36
import org .graalvm .nativeimage .Platforms ;
32
37
33
38
import com .oracle .svm .core .feature .AutomaticallyRegisteredImageSingleton ;
34
39
import com .oracle .svm .core .hub .DynamicHub .ReflectionMetadata ;
35
- import com .oracle .svm .core .imagelayer .BuildingImageLayerPredicate ;
40
+ import com .oracle .svm .core .imagelayer .BuildingInitialLayerPredicate ;
41
+ import com .oracle .svm .core .layeredimagesingleton .ImageSingletonLoader ;
42
+ import com .oracle .svm .core .layeredimagesingleton .ImageSingletonWriter ;
36
43
import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonBuilderFlags ;
37
44
import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonSupport ;
38
45
import com .oracle .svm .core .layeredimagesingleton .MultiLayeredImageSingleton ;
39
- import com .oracle .svm .core .layeredimagesingleton .UnsavedSingleton ;
40
46
41
47
/**
42
48
* This singleton stores the {@link ReflectionMetadata} of each {@link DynamicHub} across layers to
43
49
* allow registering elements for reflection in extension layers too.
44
50
*/
45
- @ AutomaticallyRegisteredImageSingleton (onlyWith = BuildingImageLayerPredicate .class )
46
- public class LayeredReflectionMetadataSingleton implements MultiLayeredImageSingleton , UnsavedSingleton {
51
+ @ AutomaticallyRegisteredImageSingleton (onlyWith = BuildingInitialLayerPredicate .class )
52
+ public class LayeredReflectionMetadataSingleton implements MultiLayeredImageSingleton {
53
+ private static final String LAYERED_REFLECTION_METADATA_HUBS = "layered reflection metadata hubs" ;
54
+ private static final String LAYERED_REFLECTION_METADATA_CLASS_FLAGS = "layered reflection metadata classFlags" ;
55
+
47
56
private final EconomicMap <Integer , ReflectionMetadata > reflectionMetadataMap = EconomicMap .create ();
48
57
58
+ /**
59
+ * The class flags registered in previous layers. This map is used to check if the class flags
60
+ * in the current layer are the same as the previous layer. If they are the same and the rest of
61
+ * the reflection metadata is empty, the class can be skipped. If the class flags of the current
62
+ * layer are not a subset of the previous layer class flags, the new class flags become the
63
+ * combination of both class flags through an or statement.
64
+ */
65
+ @ Platforms (Platform .HOSTED_ONLY .class ) //
66
+ private final Map <Integer , Integer > previousLayerClassFlags ;
67
+
68
+ LayeredReflectionMetadataSingleton () {
69
+ this (Map .of ());
70
+ }
71
+
72
+ LayeredReflectionMetadataSingleton (Map <Integer , Integer > previousLayerClassFlags ) {
73
+ this .previousLayerClassFlags = previousLayerClassFlags ;
74
+ }
75
+
49
76
@ Platforms (Platform .HOSTED_ONLY .class )
50
77
public static LayeredReflectionMetadataSingleton currentLayer () {
51
78
return LayeredImageSingletonSupport .singleton ().lookup (LayeredReflectionMetadataSingleton .class , false , true );
@@ -59,9 +86,26 @@ public static LayeredReflectionMetadataSingleton[] singletons() {
59
86
public void setReflectionMetadata (DynamicHub hub , ReflectionMetadata reflectionMetadata ) {
60
87
/* GR-63472: Two different classes could have the same name in different class loaders */
61
88
assert !reflectionMetadataMap .containsKey (hub .getTypeID ()) : "The hub %s was added twice in the same layered reflection metadata" .formatted (hub );
89
+ if (isClassFlagsSubsetOfPreviousLayer (hub .getTypeID (), reflectionMetadata ) && isReflectionMetadataEmpty (reflectionMetadata )) {
90
+ return ;
91
+ }
62
92
reflectionMetadataMap .put (hub .getTypeID (), reflectionMetadata );
63
93
}
64
94
95
+ private boolean isClassFlagsSubsetOfPreviousLayer (int hub , ReflectionMetadata reflectionMetadata ) {
96
+ int previousLayerFlags = previousLayerClassFlags .getOrDefault (hub , 0 );
97
+ return getCombinedClassFlags (reflectionMetadata , previousLayerFlags ) == previousLayerFlags ;
98
+ }
99
+
100
+ private static int getCombinedClassFlags (ReflectionMetadata reflectionMetadata , int previousLayerFlags ) {
101
+ return previousLayerFlags | reflectionMetadata .classFlags ;
102
+ }
103
+
104
+ private static boolean isReflectionMetadataEmpty (ReflectionMetadata reflectionMetadata ) {
105
+ return reflectionMetadata .fieldsEncodingIndex == -1 && reflectionMetadata .methodsEncodingIndex == -1 &&
106
+ reflectionMetadata .constructorsEncodingIndex == -1 && reflectionMetadata .recordComponentsEncodingIndex == -1 ;
107
+ }
108
+
65
109
public ReflectionMetadata getReflectionMetadata (DynamicHub hub ) {
66
110
return reflectionMetadataMap .get (hub .getTypeID ());
67
111
}
@@ -70,4 +114,46 @@ public ReflectionMetadata getReflectionMetadata(DynamicHub hub) {
70
114
public EnumSet <LayeredImageSingletonBuilderFlags > getImageBuilderFlags () {
71
115
return LayeredImageSingletonBuilderFlags .ALL_ACCESS ;
72
116
}
117
+
118
+ @ Override
119
+ public PersistFlags preparePersist (ImageSingletonWriter writer ) {
120
+ List <Integer > hubs = new ArrayList <>();
121
+ List <Integer > classFlagsList = new ArrayList <>();
122
+
123
+ var cursor = reflectionMetadataMap .getEntries ();
124
+ while (cursor .advance ()) {
125
+ int hub = cursor .getKey ();
126
+ hubs .add (hub );
127
+ classFlagsList .add (getCombinedClassFlags (cursor .getValue (), previousLayerClassFlags .getOrDefault (hub , 0 )));
128
+ }
129
+
130
+ for (var entry : previousLayerClassFlags .entrySet ()) {
131
+ if (!hubs .contains (entry .getKey ())) {
132
+ /*
133
+ * If new class flags were written in this layer, the class flags from previous
134
+ * layers need to be skipped.
135
+ */
136
+ hubs .add (entry .getKey ());
137
+ classFlagsList .add (entry .getValue ());
138
+ }
139
+ }
140
+
141
+ writer .writeIntList (LAYERED_REFLECTION_METADATA_HUBS , hubs );
142
+ writer .writeIntList (LAYERED_REFLECTION_METADATA_CLASS_FLAGS , classFlagsList );
143
+
144
+ return PersistFlags .CREATE ;
145
+ }
146
+
147
+ @ SuppressWarnings ("unused" )
148
+ public static Object createFromLoader (ImageSingletonLoader loader ) {
149
+ List <Integer > hubs = loader .readIntList (LAYERED_REFLECTION_METADATA_HUBS );
150
+ List <Integer > previousLayerClassFlags = loader .readIntList (LAYERED_REFLECTION_METADATA_CLASS_FLAGS );
151
+
152
+ Map <Integer , Integer > classDatas = new HashMap <>();
153
+ for (int i = 0 ; i < hubs .size (); ++i ) {
154
+ classDatas .put (hubs .get (i ), previousLayerClassFlags .get (i ));
155
+ }
156
+
157
+ return new LayeredReflectionMetadataSingleton (Collections .unmodifiableMap (classDatas ));
158
+ }
73
159
}
0 commit comments