31
31
import java .lang .invoke .SerializedLambda ;
32
32
import java .lang .reflect .Constructor ;
33
33
import java .lang .reflect .Modifier ;
34
+ import java .util .EnumSet ;
34
35
import java .util .Objects ;
35
36
36
37
import org .graalvm .collections .EconomicMap ;
37
38
import org .graalvm .collections .MapCursor ;
38
- import org .graalvm .nativeimage .ImageSingletons ;
39
39
import org .graalvm .nativeimage .Platform ;
40
40
import org .graalvm .nativeimage .Platforms ;
41
41
import org .graalvm .nativeimage .impl .ConfigurationCondition ;
42
42
43
+ import com .oracle .svm .core .BuildPhaseProvider ;
44
+ import com .oracle .svm .core .SubstrateUtil ;
43
45
import com .oracle .svm .core .configure .RuntimeConditionSet ;
46
+ import com .oracle .svm .core .hub .DynamicHub ;
47
+ import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonBuilderFlags ;
48
+ import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonSupport ;
49
+ import com .oracle .svm .core .layeredimagesingleton .MultiLayeredImageSingleton ;
50
+ import com .oracle .svm .core .layeredimagesingleton .UnsavedSingleton ;
44
51
import com .oracle .svm .core .reflect .SubstrateConstructorAccessor ;
45
52
import com .oracle .svm .core .util .ImageHeapMap ;
46
53
import com .oracle .svm .core .util .VMError ;
47
54
48
55
import jdk .graal .compiler .java .LambdaUtils ;
49
56
50
- public class SerializationSupport implements SerializationRegistry {
57
+ public class SerializationSupport implements MultiLayeredImageSingleton , SerializationRegistry , UnsavedSingleton {
51
58
52
- public static SerializationSupport singleton () {
53
- return (SerializationSupport ) ImageSingletons .lookup (SerializationRegistry .class );
59
+ @ Platforms (Platform .HOSTED_ONLY .class )
60
+ public static SerializationSupport currentLayer () {
61
+ return LayeredImageSingletonSupport .singleton ().lookup (SerializationSupport .class , false , true );
62
+ }
63
+
64
+ public static SerializationSupport [] layeredSingletons () {
65
+ return MultiLayeredImageSingleton .getAllLayers (SerializationSupport .class );
54
66
}
55
67
56
68
/**
@@ -184,19 +196,48 @@ public String getClassLoaderSerializationLookupKey(ClassLoader classLoader) {
184
196
throw VMError .shouldNotReachHere ("No constructor accessor uses the class loader %s" , classLoader );
185
197
}
186
198
187
- private final EconomicMap <Class <?>, RuntimeConditionSet > classes = EconomicMap .create ();
199
+ /**
200
+ * This class is used as key in maps that use {@link Class} as key at runtime in layered images,
201
+ * because the hash code of {@link Class} objects cannot be injected in extension layers and is
202
+ * thus inconsistent across layers. The state of those maps is then incorrect at run time. The
203
+ * {@link DynamicHub} cannot be used directly either as its hash code at run time is the one of
204
+ * the {@link Class} object.
205
+ * <p>
206
+ * Temporary key for maps ideally indexed by their {@link Class} or {@link DynamicHub}. At
207
+ * runtime, these maps should be indexed by {@link DynamicHub#getTypeID}
208
+ */
209
+ public record DynamicHubKey (DynamicHub hub ) {
210
+ public int getTypeID () {
211
+ return hub .getTypeID ();
212
+ }
213
+ }
214
+
215
+ private final EconomicMap <Object /* DynamicHubKey or DynamicHub.typeID */ , RuntimeConditionSet > classes = EconomicMap .create ();
188
216
private final EconomicMap <String , RuntimeConditionSet > lambdaCapturingClasses = EconomicMap .create ();
189
217
190
218
@ Platforms (Platform .HOSTED_ONLY .class )
191
- public void registerSerializationTargetClass (ConfigurationCondition cnd , Class <?> serializationTargetClass ) {
219
+ public void registerSerializationTargetClass (ConfigurationCondition cnd , DynamicHub hub ) {
192
220
synchronized (classes ) {
193
- var previous = classes .putIfAbsent (serializationTargetClass , RuntimeConditionSet .createHosted (cnd ));
221
+ var previous = classes .putIfAbsent (BuildPhaseProvider . isHostedUniverseBuilt () ? hub . getTypeID () : new DynamicHubKey ( hub ) , RuntimeConditionSet .createHosted (cnd ));
194
222
if (previous != null ) {
195
223
previous .addCondition (cnd );
196
224
}
197
225
}
198
226
}
199
227
228
+ public void replaceHubKeyWithTypeID () {
229
+ EconomicMap <Integer , RuntimeConditionSet > newEntries = EconomicMap .create ();
230
+ var cursor = classes .getEntries ();
231
+ while (cursor .advance ()) {
232
+ Object key = cursor .getKey ();
233
+ if (key instanceof DynamicHubKey hubKey ) {
234
+ newEntries .put (hubKey .getTypeID (), cursor .getValue ());
235
+ cursor .remove ();
236
+ }
237
+ }
238
+ classes .putAll (newEntries );
239
+ }
240
+
200
241
@ Platforms (Platform .HOSTED_ONLY .class )
201
242
public void registerLambdaCapturingClass (ConfigurationCondition cnd , String lambdaCapturingClass ) {
202
243
synchronized (lambdaCapturingClasses ) {
@@ -212,37 +253,63 @@ public boolean isLambdaCapturingClassRegistered(String lambdaCapturingClass) {
212
253
return lambdaCapturingClasses .containsKey (lambdaCapturingClass );
213
254
}
214
255
215
- @ Override
216
- public Object getSerializationConstructorAccessor (Class <?> rawDeclaringClass , Class <?> rawTargetConstructorClass ) {
217
- Class <?> declaringClass = rawDeclaringClass ;
256
+ public static Object getSerializationConstructorAccessor (Class <?> serializationTargetClass , Class <?> targetConstructorClass ) {
257
+ Class <?> declaringClass = serializationTargetClass ;
218
258
219
259
if (LambdaUtils .isLambdaClass (declaringClass )) {
220
260
declaringClass = SerializedLambda .class ;
221
261
}
222
262
263
+ if (SubstrateUtil .HOSTED ) {
264
+ Object constructorAccessor = currentLayer ().getSerializationConstructorAccessor0 (declaringClass , targetConstructorClass );
265
+ if (constructorAccessor != null ) {
266
+ return constructorAccessor ;
267
+ }
268
+ } else {
269
+ for (var singleton : layeredSingletons ()) {
270
+ Object constructorAccessor = singleton .getSerializationConstructorAccessor0 (declaringClass , targetConstructorClass );
271
+ if (constructorAccessor != null ) {
272
+ return constructorAccessor ;
273
+ }
274
+ }
275
+ }
276
+
277
+ String targetConstructorClassName = targetConstructorClass .getName ();
278
+ if (ThrowMissingRegistrationErrors .hasBeenSet ()) {
279
+ MissingSerializationRegistrationUtils .missingSerializationRegistration (declaringClass ,
280
+ "type " + declaringClass .getTypeName () + " with target constructor class: " + targetConstructorClassName );
281
+ } else {
282
+ throw VMError .unsupportedFeature ("SerializationConstructorAccessor class not found for declaringClass: " + declaringClass .getName () +
283
+ " (targetConstructorClass: " + targetConstructorClassName + "). Usually adding " + declaringClass .getName () +
284
+ " to serialization-config.json fixes the problem." );
285
+ }
286
+ return null ;
287
+ }
288
+
289
+ @ Override
290
+ public Object getSerializationConstructorAccessor0 (Class <?> declaringClass , Class <?> rawTargetConstructorClass ) {
223
291
VMError .guarantee (stubConstructor != null , "Called too early, no stub constructor yet." );
224
292
Class <?> targetConstructorClass = Modifier .isAbstract (declaringClass .getModifiers ()) ? stubConstructor .getDeclaringClass () : rawTargetConstructorClass ;
225
- Object constructorAccessor = constructorAccessors .get (new SerializationLookupKey (declaringClass , targetConstructorClass ));
293
+ return constructorAccessors .get (new SerializationLookupKey (declaringClass , targetConstructorClass ));
294
+ }
226
295
227
- if (constructorAccessor != null ) {
228
- return constructorAccessor ;
229
- } else {
230
- String targetConstructorClassName = targetConstructorClass .getName ();
231
- if (ThrowMissingRegistrationErrors .hasBeenSet ()) {
232
- MissingSerializationRegistrationUtils .missingSerializationRegistration (declaringClass ,
233
- "type " + declaringClass .getTypeName () + " with target constructor class: " + targetConstructorClassName );
234
- } else {
235
- throw VMError .unsupportedFeature ("SerializationConstructorAccessor class not found for declaringClass: " + declaringClass .getName () +
236
- " (targetConstructorClass: " + targetConstructorClassName + "). Usually adding " + declaringClass .getName () +
237
- " to serialization-config.json fixes the problem." );
296
+ public static boolean isRegisteredForSerialization (DynamicHub hub ) {
297
+ for (SerializationRegistry singleton : SerializationSupport .layeredSingletons ()) {
298
+ if (singleton .isRegisteredForSerialization0 (hub )) {
299
+ return true ;
238
300
}
239
- return null ;
240
301
}
302
+ return false ;
241
303
}
242
304
243
305
@ Override
244
- public boolean isRegisteredForSerialization ( Class <?> clazz ) {
245
- var conditionSet = classes .get (clazz );
306
+ public boolean isRegisteredForSerialization0 ( DynamicHub dynamicHub ) {
307
+ var conditionSet = classes .get (dynamicHub . getTypeID () );
246
308
return conditionSet != null && conditionSet .satisfied ();
247
309
}
310
+
311
+ @ Override
312
+ public EnumSet <LayeredImageSingletonBuilderFlags > getImageBuilderFlags () {
313
+ return LayeredImageSingletonBuilderFlags .ALL_ACCESS ;
314
+ }
248
315
}
0 commit comments