Skip to content

Commit 5492857

Browse files
committed
Make SerializationSupport.constructorAccessors use DynamicHub id instead of Class Object as key
1 parent e417151 commit 5492857

9 files changed

Lines changed: 156 additions & 168 deletions

File tree

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
import java.util.function.BiFunction;
8686
import java.util.function.IntFunction;
8787

88-
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
8988
import org.graalvm.collections.EconomicSet;
9089
import org.graalvm.nativeimage.AnnotationAccess;
9190
import org.graalvm.nativeimage.ImageSingletons;
@@ -142,6 +141,7 @@
142141
import com.oracle.svm.core.util.BasedOnJDKFile;
143142
import com.oracle.svm.core.util.LazyFinalReference;
144143
import com.oracle.svm.guest.staging.Uninterruptible;
144+
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
145145
import com.oracle.svm.shared.util.VMError;
146146
import com.oracle.svm.util.AnnotationUtil;
147147
import com.oracle.svm.util.GuestAccess;
@@ -2545,7 +2545,7 @@ public FieldAccessor newFieldAccessor(Field field0, boolean override) {
25452545

25462546
@Substitute
25472547
private Constructor<?> generateConstructor(Class<?> cl, Constructor<?> constructorToCall) {
2548-
ConstructorAccessor acc = (ConstructorAccessor) SerializationSupport.getSerializationConstructorAccessor(cl, constructorToCall.getDeclaringClass());
2548+
ConstructorAccessor acc = (ConstructorAccessor) SerializationSupport.getRuntimeSerializationConstructorAccessor(cl, constructorToCall.getDeclaringClass());
25492549
/*
25502550
* Unlike other root constructors, this constructor is not copied for mutation but directly
25512551
* mutated, as it is not cached. To cache this constructor, setAccessible call must be done

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationRegistry.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java

Lines changed: 96 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@
2727

2828
import java.io.Serializable;
2929
import java.lang.invoke.SerializedLambda;
30-
import java.lang.reflect.Constructor;
3130
import 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

3435
import org.graalvm.collections.EconomicMap;
3536
import org.graalvm.collections.MapCursor;
@@ -44,20 +45,19 @@
4445
import com.oracle.svm.core.heap.UnknownObjectField;
4546
import com.oracle.svm.core.hub.DynamicHub;
4647
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
47-
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
4848
import com.oracle.svm.core.metadata.MetadataTracer;
4949
import com.oracle.svm.core.reflect.SubstrateConstructorAccessor;
50+
import com.oracle.svm.shared.singletons.MultiLayeredImageSingleton;
5051
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.AllAccess;
5152
import com.oracle.svm.shared.singletons.traits.BuiltinTraits.NoLayeredCallbacks;
5253
import com.oracle.svm.shared.singletons.traits.SingletonLayeredInstallationKind.MultiLayer;
5354
import com.oracle.svm.shared.singletons.traits.SingletonTraits;
54-
import com.oracle.svm.core.util.ImageHeapMap;
5555
import com.oracle.svm.shared.util.VMError;
5656

5757
import 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();

substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ struct PersistedAnalysisType {
5555
wrappedType :union {
5656
none @31 :Void; # default
5757
serializationGenerated :group {
58-
rawDeclaringClass @32 :Text;
59-
rawTargetConstructor @33 :Text;
58+
rawDeclaringClassId @32 :TypeId;
59+
rawTargetConstructorId @33 :TypeId;
6060
}
6161
lambda :group {
6262
capturingClass @34 :Text;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
import com.oracle.svm.core.meta.MethodRef;
9393
import com.oracle.svm.core.reflect.proxy.DynamicProxySupport;
9494
import com.oracle.svm.core.reflect.serialize.SerializationSupport;
95-
import com.oracle.svm.shared.util.VMError;
9695
import com.oracle.svm.hosted.FeatureImpl;
9796
import com.oracle.svm.hosted.SVMHost;
9897
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
@@ -128,6 +127,7 @@
128127
import com.oracle.svm.shaded.org.capnproto.PrimitiveList;
129128
import com.oracle.svm.shaded.org.capnproto.StructList;
130129
import com.oracle.svm.shaded.org.capnproto.Text;
130+
import com.oracle.svm.shared.util.VMError;
131131
import com.oracle.svm.util.AnnotationUtil;
132132
import com.oracle.svm.util.GuestAccess;
133133
import com.oracle.svm.util.JVMCIReflectionUtil;
@@ -446,14 +446,18 @@ protected boolean delegateLoadType(PersistedAnalysisType.Reader typeData) {
446446
}
447447
if (wrappedType.isSerializationGenerated()) {
448448
SerializationGenerated.Reader sg = wrappedType.getSerializationGenerated();
449-
String rawDeclaringClassName = sg.getRawDeclaringClass().toString();
450-
String rawTargetConstructorClassName = sg.getRawTargetConstructor().toString();
451-
Class<?> rawDeclaringClass = imageLayerBuildingSupport.lookupClass(false, rawDeclaringClassName);
452-
Class<?> rawTargetConstructorClass = imageLayerBuildingSupport.lookupClass(false, rawTargetConstructorClassName);
449+
int rawDeclaringClassId = sg.getRawDeclaringClassId();
450+
int rawTargetConstructorClassId = sg.getRawTargetConstructorId();
451+
AnalysisType rawDeclaringType = getAnalysisTypeForBaseLayerId(rawDeclaringClassId);
452+
AnalysisType rawTargetConstructorType = getAnalysisTypeForBaseLayerId(rawTargetConstructorClassId);
453+
Class<?> rawDeclaringClass = rawDeclaringType.getJavaClass();
454+
Class<?> rawTargetConstructorClass = rawTargetConstructorType.getJavaClass();
453455
Constructor<?> rawTargetConstructor = ReflectionUtil.lookupConstructor(rawTargetConstructorClass);
454456
Constructor<?> constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(rawDeclaringClass, rawTargetConstructor);
455-
SerializationSupport.currentLayer().addConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass, SerializationFeature.getConstructorAccessor(constructor));
456-
Class<?> constructorAccessor = SerializationSupport.getSerializationConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass).getClass();
457+
DynamicHub rawDeclaringHub = typeToHub(rawDeclaringType);
458+
DynamicHub rawTargetConstructorHub = typeToHub(rawTargetConstructorType);
459+
SerializationSupport.currentLayer().addConstructorAccessor(rawDeclaringHub, rawTargetConstructorHub, SerializationFeature.getConstructorAccessor(constructor));
460+
Class<?> constructorAccessor = SerializationSupport.getHostedSerializationConstructorAccessor(rawDeclaringHub, rawTargetConstructorHub).getClass();
457461
metaAccess.lookupJavaType(constructorAccessor);
458462
return true;
459463
} else if (wrappedType.isLambda()) {

0 commit comments

Comments
 (0)