2727
2828import java .io .Serializable ;
2929import java .lang .invoke .SerializedLambda ;
30- import java .lang .reflect .Constructor ;
3130import java .lang .reflect .Modifier ;
32- import java .util .Objects ;
31+ import java .util .function .Consumer ;
32+ import java .util .function .Function ;
33+ import java .util .function .Predicate ;
3334
3435import org .graalvm .collections .EconomicMap ;
3536import org .graalvm .collections .MapCursor ;
4445import com .oracle .svm .core .heap .UnknownObjectField ;
4546import com .oracle .svm .core .hub .DynamicHub ;
4647import com .oracle .svm .core .layeredimagesingleton .LayeredImageSingletonSupport ;
47- import com .oracle .svm .shared .singletons .MultiLayeredImageSingleton ;
4848import com .oracle .svm .core .metadata .MetadataTracer ;
4949import com .oracle .svm .core .reflect .SubstrateConstructorAccessor ;
50+ import com .oracle .svm .shared .singletons .MultiLayeredImageSingleton ;
5051import com .oracle .svm .shared .singletons .traits .BuiltinTraits .AllAccess ;
5152import com .oracle .svm .shared .singletons .traits .BuiltinTraits .NoLayeredCallbacks ;
5253import com .oracle .svm .shared .singletons .traits .SingletonLayeredInstallationKind .MultiLayer ;
5354import com .oracle .svm .shared .singletons .traits .SingletonTraits ;
54- import com .oracle .svm .core .util .ImageHeapMap ;
5555import com .oracle .svm .shared .util .VMError ;
5656
5757import jdk .graal .compiler .java .LambdaUtils ;
5858
5959@ SingletonTraits (access = AllAccess .class , layeredCallbacks = NoLayeredCallbacks .class , layeredInstallationKind = MultiLayer .class )
60- public class SerializationSupport implements SerializationRegistry {
60+ public class SerializationSupport {
6161
6262 @ Platforms (Platform .HOSTED_ONLY .class )
6363 public static SerializationSupport currentLayer () {
@@ -108,60 +108,52 @@ private StubForAbstractClass() {
108108 }
109109 }
110110
111- private Constructor <?> stubConstructor ;
111+ private DynamicHub stubConstructorClass ;
112+ private DynamicHub serializedLambdaClass ;
112113
113- public static final class SerializationLookupKey {
114- private final Class <?> declaringClass ;
115- private final Class <?> targetConstructorClass ;
116-
117- private SerializationLookupKey (Class <?> declaringClass , Class <?> targetConstructorClass ) {
118- assert declaringClass != null && targetConstructorClass != null ;
119- this .declaringClass = declaringClass ;
120- this .targetConstructorClass = targetConstructorClass ;
121- }
114+ /**
115+ * The ids are either a {@link DynamicHubKey} or {@code DynamicHub.typeID}.
116+ */
117+ public record SerializationLookupKey (Object declaringClassId , Object targetConstructorClassId ) {
118+ }
122119
123- public Class <?> getDeclaringClass () {
124- return declaringClass ;
125- }
120+ @ UnknownObjectField (fullyQualifiedTypes = "org.graalvm.collections.EconomicMapImpl" , availability = AfterCompilation .class ) //
121+ private final EconomicMap <SerializationLookupKey , Object > constructorAccessors ;
126122
127- public Class <?> getTargetConstructorClass () {
128- return targetConstructorClass ;
129- }
123+ /**
124+ * The constructor accessors need to be rescanned manually because the
125+ * {@link SerializationSupport#constructorAccessors} map is only available after compilation.
126+ */
127+ @ Platforms (Platform .HOSTED_ONLY .class )
128+ private Consumer <Object > scanObject ;
130129
131- @ Override
132- public boolean equals (Object o ) {
133- if (this == o ) {
134- return true ;
135- }
136- if (o == null || getClass () != o .getClass ()) {
137- return false ;
138- }
139- SerializationLookupKey that = (SerializationLookupKey ) o ;
140- return declaringClass .equals (that .declaringClass ) && targetConstructorClass .equals (that .targetConstructorClass );
141- }
130+ public SerializationSupport () {
131+ constructorAccessors = EconomicMap .create ();
132+ }
142133
143- @ Override
144- public int hashCode () {
145- return Objects .hash (declaringClass , targetConstructorClass );
146- }
134+ public void setStubConstructor (DynamicHub stubConstructorClass ) {
135+ VMError .guarantee (this .stubConstructorClass == null , "Cannot reset stubConstructor" );
136+ this .stubConstructorClass = stubConstructorClass ;
147137 }
148138
149- private final EconomicMap <SerializationLookupKey , Object > constructorAccessors ;
139+ public void setSerializedLambdaClass (DynamicHub serializedLambdaClass ) {
140+ this .serializedLambdaClass = serializedLambdaClass ;
141+ }
150142
151- @ Platforms (Platform .HOSTED_ONLY .class )
152- public SerializationSupport () {
153- constructorAccessors = ImageHeapMap .create ("constructorAccessors" );
143+ private DynamicHub getSerializedLambdaClass () {
144+ return serializedLambdaClass ;
154145 }
155146
156- public void setStubConstructor (Constructor <?> stubConstructor ) {
157- VMError .guarantee (this .stubConstructor == null , "Cannot reset stubConstructor" );
158- this .stubConstructor = stubConstructor ;
147+ public void setScanObject (Consumer <Object > scanObject ) {
148+ this .scanObject = scanObject ;
159149 }
160150
161151 @ Platforms (Platform .HOSTED_ONLY .class )
162- public Object addConstructorAccessor (Class <?> declaringClass , Class <?> targetConstructorClass , Object constructorAccessor ) {
152+ public Object addConstructorAccessor (DynamicHub declaringClass , DynamicHub targetConstructorClass , Object constructorAccessor ) {
163153 VMError .guarantee (constructorAccessor instanceof SubstrateConstructorAccessor , "Not a SubstrateConstructorAccessor: %s" , constructorAccessor );
164- SerializationLookupKey key = new SerializationLookupKey (declaringClass , targetConstructorClass );
154+ SerializationLookupKey key = BuildPhaseProvider .isHostedUniverseBuilt () ? new SerializationLookupKey (declaringClass .getTypeID (), targetConstructorClass .getTypeID ())
155+ : new SerializationLookupKey (new DynamicHubKey (declaringClass ), new DynamicHubKey (targetConstructorClass ));
156+ scanObject .accept (constructorAccessor );
165157 return constructorAccessors .putIfAbsent (key , constructorAccessor );
166158 }
167159
@@ -193,7 +185,7 @@ public String getClassLoaderSerializationLookupKey(ClassLoader classLoader) {
193185 while (constructorAccessorsCursor .advance ()) {
194186 if (constructorAccessorsCursor .getValue ().getClass ().getClassLoader () == classLoader ) {
195187 var key = constructorAccessorsCursor .getKey ();
196- return key .declaringClass . getName () + key .targetConstructorClass . getName () ;
188+ return key .declaringClassId + " " + key .targetConstructorClassId ;
197189 }
198190 }
199191 throw VMError .shouldNotReachHere ("No constructor accessor uses the class loader %s" , classLoader );
@@ -234,16 +226,33 @@ public void registerSerializationTargetClass(AccessCondition cnd, DynamicHub hub
234226 }
235227
236228 public void replaceHubKeyWithTypeID () {
237- EconomicMap <Integer , RuntimeDynamicAccessMetadata > newEntries = EconomicMap .create ();
238- var cursor = classes .getEntries ();
229+ replaceHubKeyWithTypeID (classes , key -> key instanceof DynamicHubKey , SerializationSupport ::getTypeID );
230+ replaceHubKeyWithTypeID (constructorAccessors , SerializationSupport ::shouldReplaceSerializationLookupKey , SerializationSupport ::replaceSerializationLookupKey );
231+ }
232+
233+ private static <T , U > void replaceHubKeyWithTypeID (EconomicMap <T , U > map , Predicate <T > condition , Function <T , T > converter ) {
234+ EconomicMap <T , U > newEntries = EconomicMap .create ();
235+ var cursor = map .getEntries ();
239236 while (cursor .advance ()) {
240- Object key = cursor .getKey ();
241- if (key instanceof DynamicHubKey hubKey ) {
242- newEntries .put (hubKey . getTypeID ( ), cursor .getValue ());
237+ T key = cursor .getKey ();
238+ if (condition . test ( key ) ) {
239+ newEntries .put (converter . apply ( key ), cursor .getValue ());
243240 cursor .remove ();
244241 }
245242 }
246- classes .putAll (newEntries );
243+ map .putAll (newEntries );
244+ }
245+
246+ private static boolean shouldReplaceSerializationLookupKey (SerializationLookupKey key ) {
247+ return key .declaringClassId () instanceof DynamicHubKey && key .targetConstructorClassId () instanceof DynamicHubKey ;
248+ }
249+
250+ private static SerializationLookupKey replaceSerializationLookupKey (SerializationLookupKey key ) {
251+ return new SerializationLookupKey (getTypeID (key .declaringClassId ()), getTypeID (key .targetConstructorClassId ()));
252+ }
253+
254+ private static int getTypeID (Object classId ) {
255+ return ((DynamicHubKey ) classId ).getTypeID ();
247256 }
248257
249258 @ Platforms (Platform .HOSTED_ONLY .class )
@@ -261,28 +270,24 @@ public boolean isLambdaCapturingClassRegistered(String lambdaCapturingClass) {
261270 return lambdaCapturingClasses .containsKey (lambdaCapturingClass );
262271 }
263272
264- public static Object getSerializationConstructorAccessor (Class <?> serializationTargetClass , Class <?> targetConstructorClass ) {
273+ public static Object getRuntimeSerializationConstructorAccessor (Class <?> serializationTargetClass , Class <?> targetConstructorClass ) {
274+ SubstrateUtil .guaranteeRuntimeOnly ();
265275 Class <?> declaringClass = serializationTargetClass ;
266276
267277 if (LambdaUtils .isLambdaClass (declaringClass )) {
268278 declaringClass = SerializedLambda .class ;
269279 }
270280
271- if (SubstrateUtil .HOSTED ) {
272- Object constructorAccessor = currentLayer ().getSerializationConstructorAccessor0 (declaringClass , targetConstructorClass );
281+ if (MetadataTracer .enabled ()) {
282+ MetadataTracer .singleton ().traceSerializationType (declaringClass );
283+ }
284+ for (var singleton : layeredSingletons ()) {
285+ DynamicHub declaringHub = SubstrateUtil .cast (declaringClass , DynamicHub .class );
286+ DynamicHub targetConstructorHub = SubstrateUtil .cast (targetConstructorClass , DynamicHub .class );
287+ Object constructorAccessor = singleton .getSerializationConstructorAccessor0 (declaringHub , targetConstructorHub , declaringClass .getModifiers ());
273288 if (constructorAccessor != null ) {
274289 return constructorAccessor ;
275290 }
276- } else {
277- if (MetadataTracer .enabled ()) {
278- MetadataTracer .singleton ().traceSerializationType (declaringClass );
279- }
280- for (var singleton : layeredSingletons ()) {
281- Object constructorAccessor = singleton .getSerializationConstructorAccessor0 (declaringClass , targetConstructorClass );
282- if (constructorAccessor != null ) {
283- return constructorAccessor ;
284- }
285- }
286291 }
287292
288293 String targetConstructorClassName = targetConstructorClass .getName ();
@@ -291,23 +296,42 @@ public static Object getSerializationConstructorAccessor(Class<?> serializationT
291296 return null ;
292297 }
293298
294- @ Override
295- public Object getSerializationConstructorAccessor0 (Class <?> declaringClass , Class <?> rawTargetConstructorClass ) {
296- VMError .guarantee (stubConstructor != null , "Called too early, no stub constructor yet." );
297- Class <?> targetConstructorClass = Modifier .isAbstract (declaringClass .getModifiers ()) ? stubConstructor .getDeclaringClass () : rawTargetConstructorClass ;
298- return constructorAccessors .get (new SerializationLookupKey (declaringClass , targetConstructorClass ));
299+ @ Platforms (Platform .HOSTED_ONLY .class )
300+ public static Object getHostedSerializationConstructorAccessor (DynamicHub serializationTargetClass , DynamicHub targetConstructorClass ) {
301+ SerializationSupport serializationSupport = currentLayer ();
302+ DynamicHub declaringClass = serializationTargetClass ;
303+
304+ if (LambdaUtils .isLambdaClass (declaringClass .getHostedJavaClass ())) {
305+ declaringClass = serializationSupport .getSerializedLambdaClass ();
306+ }
307+
308+ VMError .guarantee (BuildPhaseProvider .isHostedUniverseBuilt (), "Called too early, hosted universe was not built yet." );
309+ Object constructorAccessor = serializationSupport .getSerializationConstructorAccessor0 (declaringClass , targetConstructorClass , declaringClass .getModifiers ());
310+ if (constructorAccessor != null ) {
311+ return constructorAccessor ;
312+ }
313+
314+ String targetConstructorClassName = targetConstructorClass .getName ();
315+ MissingSerializationRegistrationUtils .reportSerialization (declaringClass .getHostedJavaClass (),
316+ "type '" + declaringClass .getTypeName () + "' with target constructor class '" + targetConstructorClassName + "'" );
317+ return null ;
318+ }
319+
320+ public Object getSerializationConstructorAccessor0 (DynamicHub declaringHub , DynamicHub rawTargetConstructorHub , int modifiers ) {
321+ VMError .guarantee (stubConstructorClass != null , "Called too early, no stub constructor yet." );
322+ DynamicHub targetConstructorHub = Modifier .isAbstract (modifiers ) ? stubConstructorClass : rawTargetConstructorHub ;
323+ return constructorAccessors .get (new SerializationLookupKey (declaringHub .getTypeID (), targetConstructorHub .getTypeID ()));
299324 }
300325
301326 public static boolean isRegisteredForSerialization (DynamicHub hub ) {
302- for (SerializationRegistry singleton : SerializationSupport .layeredSingletons ()) {
327+ for (SerializationSupport singleton : SerializationSupport .layeredSingletons ()) {
303328 if (singleton .isRegisteredForSerialization0 (hub )) {
304329 return true ;
305330 }
306331 }
307332 return false ;
308333 }
309334
310- @ Override
311335 public boolean isRegisteredForSerialization0 (DynamicHub dynamicHub ) {
312336 var conditionSet = classes .get (dynamicHub .getTypeID ());
313337 return conditionSet != null && conditionSet .satisfied ();
0 commit comments