From 528af6f1ffdcbc0faf2fbc27c6de0f6b680efbd9 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 17 Jul 2024 19:26:32 +0200 Subject: [PATCH 1/5] Use the ImageClassLoader to reload methods from external libraries in the application layer --- .../jdk/graal/compiler/util/ObjectCopier.java | 2 +- .../graal/pointsto/ClassInclusionPolicy.java | 48 ++++++++++++++----- .../graal/pointsto/PointsToAnalysis.java | 4 +- .../graal/pointsto/ReachabilityAnalysis.java | 2 +- .../graal/pointsto/heap/ImageLayerLoader.java | 32 ++++++++----- .../pointsto/heap/ImageLayerSnapshotUtil.java | 8 ++++ .../ReachabilityAnalysisEngine.java | 2 +- .../ImageSingletonLoader.java | 2 + .../svm/hosted/NativeImageGenerator.java | 11 +++-- .../analysis/NativeImagePointsToAnalysis.java | 10 ++++ .../svm/hosted/heap/SVMImageLayerLoader.java | 40 +++++++++++++--- .../imagelayer/LoadImageSingletonFeature.java | 5 +- 12 files changed, 124 insertions(+), 42 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java index 776891944fbb..faa78f81f31c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java @@ -468,7 +468,7 @@ public Decoder(ClassLoader loader) { this.loader = loader; } - Class loadClass(String className) { + public Class loadClass(String className) { try { return Class.forName(className, false, loader); } catch (ClassNotFoundException e) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java index 4e08c6243fe1..a8a45f02c834 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -105,6 +105,11 @@ public void includeClass(Class cls) { */ public abstract void includeMethod(Executable method); + /** + * Includes the given method in the image. + */ + public abstract void includeMethod(AnalysisMethod method); + /** * Includes the given field in the image. */ @@ -151,23 +156,35 @@ public boolean isMethodIncluded(Executable method) { @Override public void includeMethod(Executable method) { bb.postTask(debug -> { - /* - * Non-abstract methods from an abstract class or default methods from an interface - * are not registered as implementation invoked by the analysis because their - * declaring class cannot be marked as instantiated and AnalysisType.getTypeFlow - * only includes instantiated types (see TypeFlow.addObserver). For now, to ensure - * those methods are included in the image, they are manually registered as - * implementation invoked. - */ Class declaringClass = method.getDeclaringClass(); - if (!Modifier.isAbstract(method.getModifiers()) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) { - AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method); - analysisMethod.registerAsDirectRootMethod(reason); - analysisMethod.registerAsImplementationInvoked(reason); - } + AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method); + registerMethod(method.getModifiers(), declaringClass, analysisMethod); + bb.forcedAddRootMethod(analysisMethod, false, reason); + }); + } + + @Override + public void includeMethod(AnalysisMethod method) { + bb.postTask(debug -> { + Class declaringClass = method.getDeclaringClass().getJavaClass(); + registerMethod(method.getModifiers(), declaringClass, method); bb.forcedAddRootMethod(method, false, reason); }); } + + private void registerMethod(int methodModifiers, Class declaringClass, AnalysisMethod analysisMethod) { + /* + * Non-abstract methods from an abstract class or default methods from an interface are + * not registered as implementation invoked by the analysis because their declaring + * class cannot be marked as instantiated and AnalysisType.getTypeFlow only includes + * instantiated types (see TypeFlow.addObserver). For now, to ensure those methods are + * included in the image, they are manually registered as implementation invoked. + */ + if (!Modifier.isAbstract(methodModifiers) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) { + analysisMethod.registerAsDirectRootMethod(reason); + analysisMethod.registerAsImplementationInvoked(reason); + } + } } /** @@ -184,6 +201,11 @@ public DefaultAllInclusionPolicy(Object reason) { public void includeMethod(Executable method) { bb.postTask(debug -> bb.addRootMethod(method, false, reason)); } + + @Override + public void includeMethod(AnalysisMethod method) { + bb.postTask(debug -> bb.addRootMethod(method, false, reason)); + } } protected boolean isAccessible(Member member) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index cb16fb4f2014..35a8a156e99f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -298,9 +298,9 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob } @Override - public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + public AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { AnalysisError.guarantee(isBaseLayerAnalysisEnabled()); - PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(metaAccess.lookupJavaMethod(method)); + PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(method); postTask(ignore -> { MethodTypeFlow typeFlow = analysisMethod.getTypeFlow(); /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java index 62ead975de45..a24b6ffa9fb7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java @@ -97,7 +97,7 @@ public interface ReachabilityAnalysis { * @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean, Object, * MultiMethod.MultiMethodKey...) */ - AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); + AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); /** * Waits until the analysis is done. diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 7df8ffe0f29f..5b82dcf9d1e4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -304,7 +304,7 @@ public class ImageLayerLoader { protected final Map constants = new ConcurrentHashMap<>(); private final List loadPaths; private final Map baseLayerTypes = new ConcurrentHashMap<>(); - private final Map typeToHubIdentityHashCode = new HashMap<>(); + private final Map typeToHubIdentityHashCode = new ConcurrentHashMap<>(); private final Map baseLayerMethods = new ConcurrentHashMap<>(); /** Map from the type id to its identifier in the jsonMap. */ @@ -581,7 +581,7 @@ public void initializeBaseLayerType(AnalysisType type) { * Tries to look up the base layer type in the current VM. Some types cannot be looked up by * name (for example $$Lambda types), so this method can return null. */ - public static Class lookupBaseLayerTypeInHostVM(String type) { + public Class lookupBaseLayerTypeInHostVM(String type) { int arrayType = 0; String componentType = type; /* @@ -594,7 +594,7 @@ public static Class lookupBaseLayerTypeInHostVM(String type) { } Class clazz = lookupPrimitiveClass(componentType); if (clazz == null) { - clazz = ReflectionUtil.lookupClass(true, componentType); + clazz = lookupClass(true, componentType); } if (clazz == null) { return null; @@ -637,7 +637,7 @@ private void loadMethod(EconomicMap methodData) { Executable method = null; Class clazz = lookupBaseLayerTypeInHostVM(className); if (clazz != null) { - Class[] argumentClasses = arguments.stream().map(ImageLayerLoader::lookupBaseLayerTypeInHostVM).toList().toArray(new Class[0]); + Class[] argumentClasses = arguments.stream().map(this::lookupBaseLayerTypeInHostVM).toList().toArray(new Class[0]); method = lookupMethodByReflection(name, clazz, argumentClasses); } @@ -680,13 +680,17 @@ private void loadMethod(EconomicMap methodData) { } private static Executable lookupMethodByReflection(String name, Class clazz, Class[] argumentClasses) { - Executable method; - if (name.equals(CONSTRUCTOR_NAME)) { - method = ReflectionUtil.lookupConstructor(true, clazz, argumentClasses); - } else { - method = ReflectionUtil.lookupMethod(true, clazz, name, argumentClasses); + try { + Executable method; + if (name.equals(CONSTRUCTOR_NAME)) { + method = ReflectionUtil.lookupConstructor(true, clazz, argumentClasses); + } else { + method = ReflectionUtil.lookupMethod(true, clazz, name, argumentClasses); + } + return method; + } catch (NoClassDefFoundError e) { + return null; } - return method; } private void createBaseLayerMethod(EconomicMap methodData, int mid, String name) { @@ -1277,14 +1281,18 @@ private EconomicMap getElementData(String registry, String eleme } @SuppressWarnings("unchecked") - protected static Enum getEnumValue(EconomicMap enumData) { + protected Enum getEnumValue(EconomicMap enumData) { String className = get(enumData, ENUM_CLASS_TAG); - Class enumClass = ReflectionUtil.lookupClass(false, className); + Class enumClass = lookupClass(false, className); String name = get(enumData, ENUM_NAME_TAG); /* asSubclass produces an "unchecked" warning */ return Enum.valueOf(enumClass.asSubclass(Enum.class), name); } + public Class lookupClass(boolean optional, String className) { + return ReflectionUtil.lookupClass(optional, className); + } + public static T get(EconomicMap innerMap, String elementIdentifier) { return cast(innerMap.get(elementIdentifier)); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 58f1cdeb921b..e3d598606e84 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -234,9 +234,12 @@ public GraphEncoder(List externalValues, ImageLayerWriter imageLayerWrite } public static class GraphDecoder extends ObjectCopier.Decoder { + private final ImageLayerLoader imageLayerLoader; + @SuppressWarnings("this-escape") public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { super(classLoader); + this.imageLayerLoader = imageLayerLoader; addBuiltin(new NodeClassBuiltIn()); addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader)); addBuiltin(new AnalysisTypeBuiltIn(null, imageLayerLoader)); @@ -245,6 +248,11 @@ public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, addBuiltin(new FieldLocationIdentityBuiltIn(null, imageLayerLoader)); addBuiltin(new NamedLocationIdentityArrayBuiltIn()); } + + @Override + public Class loadClass(String className) { + return imageLayerLoader.lookupClass(false, className); + } } public static class NodeClassBuiltIn extends ObjectCopier.Builtin { diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index 51777d1c055b..695b081a919b 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -112,7 +112,7 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob } @Override - public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + public AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { return addRootMethod(method, invokeSpecial, reason, otherRoots); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java index fc97c2303c87..37bc08f01e8f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java @@ -36,4 +36,6 @@ public interface ImageSingletonLoader { String readString(String keyName); List readStringList(String keyName); + + Class lookupClass(String className); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 764b9387f5c9..ef37b443687d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -98,7 +98,6 @@ import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapScanner; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; @@ -232,6 +231,7 @@ import com.oracle.svm.hosted.heap.ObservableImageHeapMapProviderImpl; import com.oracle.svm.hosted.heap.SVMImageHeapScanner; import com.oracle.svm.hosted.heap.SVMImageHeapVerifier; +import com.oracle.svm.hosted.heap.SVMImageLayerLoader; import com.oracle.svm.hosted.image.AbstractImage; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.image.NativeImageCodeCache; @@ -530,8 +530,11 @@ public void run(Map entryPoints, var hostedOptionValues = new HostedOptionValues(optionProvider.getHostedValues()); HostedImageLayerBuildingSupport imageLayerSupport = HostedImageLayerBuildingSupport.initialize(hostedOptionValues); - ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement(imageLayerSupport.getLoader() != null || imageLayerSupport.getWriter() != null), - imageLayerSupport); + SVMImageLayerLoader imageLayerLoader = imageLayerSupport.getLoader(); + if (imageLayerLoader != null) { + imageLayerLoader.setImageClassLoader(loader); + } + ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement(imageLayerLoader != null || imageLayerSupport.getWriter() != null), imageLayerSupport); ImageSingletons.add(LayeredImageSingletonSupport.class, (LayeredImageSingletonSupport) ImageSingletonsSupportImpl.get()); ImageSingletons.add(ProgressReporter.class, reporter); @@ -979,7 +982,7 @@ protected void setupNativeImage(OptionValues options, Map field != null && classInclusionPolicy.isFieldIncluded(field)) .forEach(classInclusionPolicy::includeField); + + /* + * Only the class initializers that are executed at run time should be included in + * the base layer. + */ + AnalysisMethod classInitializer = type.getClassInitializer(); + if (classInitializer != null && !ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(type) && classInitializer.getCode() != null) { + classInclusionPolicy.includeMethod(classInitializer); + } } }); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java index 854d9f29edf4..544020ddfe36 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java @@ -53,7 +53,9 @@ import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; @@ -61,6 +63,7 @@ import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo; import com.oracle.svm.hosted.meta.HostedArrayClass; @@ -88,6 +91,7 @@ public class SVMImageLayerLoader extends ImageLayerLoader { private final Field dynamicHubArrayHubField; private HostedUniverse hostedUniverse; + private ImageClassLoader imageClassLoader; public SVMImageLayerLoader(List loaderPaths) { super(new SVMImageLayerSnapshotUtil(), loaderPaths); @@ -98,10 +102,27 @@ public void setHostedUniverse(HostedUniverse hostedUniverse) { this.hostedUniverse = hostedUniverse; } + public void setImageClassLoader(ImageClassLoader imageClassLoader) { + this.imageClassLoader = imageClassLoader; + } + public HostedUniverse getHostedUniverse() { return hostedUniverse; } + @Override + public Class lookupClass(boolean optional, String className) { + TypeResult> typeResult = imageClassLoader.findClass(className); + if (!typeResult.isPresent()) { + if (optional) { + return null; + } else { + throw AnalysisError.shouldNotReachHere("Class not found: " + className); + } + } + return typeResult.get(); + } + @Override protected Annotation[] getAnnotations(EconomicMap elementData) { List annotationNames = get(elementData, ANNOTATIONS_TAG); @@ -175,7 +196,7 @@ protected boolean delegateProcessing(String constantType, Object constantValue, String methodName = (String) constantValue; Class definingClass = lookupBaseLayerTypeInHostVM((String) constantData.get(2)); List parameters = cast(constantData.get(3)); - Class[] parameterTypes = parameters.stream().map(ImageLayerLoader::lookupBaseLayerTypeInHostVM).toList().toArray(new Class[0]); + Class[] parameterTypes = parameters.stream().map(this::lookupBaseLayerTypeInHostVM).toList().toArray(new Class[0]); values[i] = new RelocatableConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); return true; } @@ -289,9 +310,9 @@ private Map>> loadImageSingletons0(Object forbiddenObject) // create singleton object instance Object result; try { - Class clazz = ReflectionUtil.lookupClass(false, className); + Class clazz = lookupClass(false, className); Method createMethod = ReflectionUtil.lookupMethod(clazz, "createFromLoader", ImageSingletonLoader.class); - result = createMethod.invoke(null, new ImageSingletonLoaderImpl(keyStore)); + result = createMethod.invoke(null, new ImageSingletonLoaderImpl(keyStore, imageClassLoader)); } catch (Throwable t) { throw VMError.shouldNotReachHere("Failed to recreate image singleton", t); } @@ -309,12 +330,12 @@ private Map>> loadImageSingletons0(Object forbiddenObject) if (persistInfo == PersistFlags.CREATE) { assert id != -1 : "Create image singletons should be linked to an object"; Object singletonObject = idToObjectMap.get(id); - Class clazz = ReflectionUtil.lookupClass(false, key); + Class clazz = lookupClass(false, key); singletonInitializationMap.computeIfAbsent(singletonObject, (k) -> new HashSet<>()); singletonInitializationMap.get(singletonObject).add(clazz); } else if (persistInfo == PersistFlags.FORBIDDEN) { assert id == -1 : "Unrestored image singleton should not be linked to an object"; - Class clazz = ReflectionUtil.lookupClass(false, key); + Class clazz = lookupClass(false, key); singletonInitializationMap.computeIfAbsent(forbiddenObject, (k) -> new HashSet<>()); singletonInitializationMap.get(forbiddenObject).add(clazz); } else { @@ -330,9 +351,11 @@ private Map>> loadImageSingletons0(Object forbiddenObject) class ImageSingletonLoaderImpl implements ImageSingletonLoader { private final UnmodifiableEconomicMap keyStore; + private final ImageClassLoader imageClassLoader; - ImageSingletonLoaderImpl(UnmodifiableEconomicMap keyStore) { + ImageSingletonLoaderImpl(UnmodifiableEconomicMap keyStore, ImageClassLoader imageClassLoader) { this.keyStore = keyStore; + this.imageClassLoader = imageClassLoader; } @SuppressWarnings("unchecked") @@ -380,4 +403,9 @@ public List readStringList(String keyName) { assert type.equals("S(") : type; return cast(value.get(1)); } + + @Override + public Class lookupClass(String className) { + return imageClassLoader.findClass(className).get(); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java index a384b9001a13..7f76723acf0a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java @@ -575,6 +575,7 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { @SuppressWarnings("unused") public static Object createFromLoader(ImageSingletonLoader loader) { + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); Iterator keyClasses = loader.readStringList("keyClasses").iterator(); Iterator slotAssignments = loader.readIntList("slotAssignments").iterator(); Iterator slotKinds = loader.readStringList("slotKinds").iterator(); @@ -583,7 +584,7 @@ public static Object createFromLoader(ImageSingletonLoader loader) { while (keyClasses.hasNext()) { String keyName = keyClasses.next(); - Class keyClass = ReflectionUtil.lookupClass(false, keyName); + Class keyClass = imageLayerLoader.lookupClass(false, keyName); int slotAssignment = slotAssignments.next(); SlotRecordKind slotKind = SlotRecordKind.valueOf(slotKinds.next()); @@ -596,7 +597,7 @@ public static Object createFromLoader(ImageSingletonLoader loader) { Iterator idKeyNames = loader.readStringList("multiLayerKeyNames").iterator(); while (keyClasses.hasNext()) { String keyClassName = keyClasses.next(); - Class keyClass = ReflectionUtil.lookupClass(false, keyClassName); + Class keyClass = imageLayerLoader.lookupClass(false, keyClassName); String idKeyName = idKeyNames.next(); var list = loader.readIntList(idKeyName); assert list != null; From 3747ebe05e5f582e52ef705d130ef128092efb3a Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 23 Aug 2024 20:38:48 +0200 Subject: [PATCH 2/5] Ensure the parameters of FactoryMethod are saturated when building a shared layer --- .../com/oracle/graal/pointsto/AbstractAnalysisEngine.java | 7 +++++++ .../src/com/oracle/graal/pointsto/BigBang.java | 5 +++++ .../com/oracle/graal/pointsto/ClassInclusionPolicy.java | 6 +++++- .../com/oracle/svm/hosted/code/FactoryMethodSupport.java | 7 ++++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 48337db3e49f..e4a6f3ed1741 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -364,6 +364,13 @@ public void registerTypeForBaseImage(Class cls) { } } + @Override + public void registerMethodForBaseImage(AnalysisMethod method) { + if (classInclusionPolicy.isMethodIncluded(method)) { + classInclusionPolicy.includeMethod(method); + } + } + public static U getOrDefault(T cls, Function getMembers, U backup) { try { return getMembers.apply(cls); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index 90f84898dbff..7ebe3be86051 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -142,4 +142,9 @@ default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType, default void registerTypeForBaseImage(Class cls) { } + + @SuppressWarnings("unused") + default void registerMethodForBaseImage(AnalysisMethod method) { + + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java index a8a45f02c834..a8e014138b1f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -66,12 +66,16 @@ public boolean isClassIncluded(Class cls) { * Determine if the given method needs to be included in the image according to the policy. */ public boolean isMethodIncluded(Executable method) { + return isMethodIncluded(bb.getMetaAccess().lookupJavaMethod(method)); + } + + public boolean isMethodIncluded(AnalysisMethod method) { /* * Methods annotated with @Fold should not be included in the base image as they must be * inlined. An extension image would inline the method as well and would not use the method * from the base image. */ - return !AnnotationAccess.isAnnotationPresent(bb.getMetaAccess().lookupJavaMethod(method), Fold.class); + return !AnnotationAccess.isAnnotationPresent(method, Fold.class); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java index 86d1b3c0a2f5..7796c1cb7aef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java @@ -37,6 +37,7 @@ import com.oracle.svm.core.code.FactoryThrowMethodHolder; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.phases.HostedGraphKit; import jdk.graal.compiler.nodes.java.AbstractNewObjectNode; @@ -86,7 +87,11 @@ public AnalysisMethod lookup(AnalysisMetaAccess aMetaAccess, AnalysisMethod aCon return new FactoryMethod(name, unwrappedConstructor, unwrappedDeclaringClass, unwrappedSignature, unwrappedConstantPool, throwAllocatedObject); }); - return aMetaAccess.getUniverse().lookup(factoryMethod); + AnalysisMethod aMethod = aMetaAccess.getUniverse().lookup(factoryMethod); + if (HostedImageLayerBuildingSupport.buildingSharedLayer()) { + aMetaAccess.getUniverse().getBigbang().registerMethodForBaseImage(aMethod); + } + return aMethod; } protected AbstractNewObjectNode createNewInstance(HostedGraphKit kit, ResolvedJavaType type, boolean fillContents) { From 959ddca298303be34917ec7d863476236a39a7e7 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 26 Aug 2024 16:18:43 +0200 Subject: [PATCH 3/5] Persist ClassInitializationInfo for BaseLayerType --- .../graal/pointsto/heap/ImageLayerLoader.java | 2 +- .../pointsto/heap/ImageLayerSnapshotUtil.java | 10 ++++ .../ClassInitializationInfo.java | 16 +++++- .../analysis/DynamicHubInitializer.java | 15 ++++-- .../svm/hosted/heap/SVMImageLayerLoader.java | 51 +++++++++++++++++++ .../svm/hosted/heap/SVMImageLayerWriter.java | 31 +++++++++++ 6 files changed, 117 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 5b82dcf9d1e4..ffb2d5fe37ca 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -308,7 +308,7 @@ public class ImageLayerLoader { private final Map baseLayerMethods = new ConcurrentHashMap<>(); /** Map from the type id to its identifier in the jsonMap. */ - private final Map typeIdToIdentifier = new HashMap<>(); + protected final Map typeIdToIdentifier = new HashMap<>(); /** Map from the method id to its identifier in the jsonMap. */ private final Map methodIdToIdentifier = new HashMap<>(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index e3d598606e84..36be14fe0d1f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -120,6 +120,16 @@ public class ImageLayerSnapshotUtil { public static final String IDENTITY_HASH_CODE_TAG = "identityHashCode"; public static final String HUB_IDENTITY_HASH_CODE_TAG = "hub identityHashCode"; public static final String IS_INITIALIZED_AT_BUILD_TIME_TAG = "is initialized at build time"; + public static final String IS_NO_INITIALIZER_NO_TRACKING_TAG = "in no initializer no tracking"; + public static final String IS_INITIALIZED_NO_TRACKING_TAG = "is initialized no tracking"; + public static final String IS_FAILED_NO_TRACKING_TAG = "is failed no tracking"; + public static final String INFO_IS_INITIALIZED_TAG = "info is initialized"; + public static final String INFO_IS_IN_ERROR_STATE_TAG = "info is in error state"; + public static final String INFO_IS_LINKED_TAG = "info is linked"; + public static final String INFO_HAS_INITIALIZER_TAG = "info has initializer"; + public static final String INFO_IS_BUILD_TIME_INITIALIZED_TAG = "info is build time initialized"; + public static final String INFO_IS_TRACKED_TAG = "info is tracked"; + public static final String INFO_CLASS_INITIALIZER_TAG = "info class initializer"; public static final String ID_TAG = "id"; public static final String ANALYSIS_PARSED_GRAPH_TAG = "analysis parsed graph"; public static final String STRENGTHENED_GRAPH_TAG = "strengthened graph"; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java index 45bbcc0e3639..1f1c1338f952 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/classinitialization/ClassInitializationInfo.java @@ -110,7 +110,7 @@ public boolean requiresSlowPath() { return slowPathRequired; } - enum InitState { + public enum InitState { /** * Successfully linked/verified (but not initialized yet). Linking happens during image * building, so we do not need to track states before linking. @@ -206,7 +206,7 @@ public void setTypeReached() { } @Platforms(Platform.HOSTED_ONLY.class) - private ClassInitializationInfo(InitState initState, boolean hasInitializer, boolean buildTimeInitialized, boolean typeReachedTracked) { + public ClassInitializationInfo(InitState initState, boolean hasInitializer, boolean buildTimeInitialized, boolean typeReachedTracked) { this(initState, typeReachedTracked); this.hasInitializer = hasInitializer; this.buildTimeInitialized = buildTimeInitialized; @@ -256,6 +256,18 @@ public boolean isInErrorState() { return initState == InitState.InitializationError; } + public boolean isLinked() { + return initState == InitState.Linked; + } + + public boolean isTracked() { + return typeReached != TypeReached.UNTRACKED; + } + + public FunctionPointerHolder getClassInitializer() { + return classInitializer; + } + private boolean isReentrantInitialization(IsolateThread thread) { return thread.equal(initThread); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java index ade3c618f7a8..c1fc48bfc24a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java @@ -52,6 +52,7 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.jdk.HostedClassLoaderPackageManagement; import com.oracle.svm.util.ReflectionUtil; @@ -218,12 +219,16 @@ private void buildClassInitializationInfo(ImageHeapScanner heapScanner, Analysis AnalysisError.guarantee(hub.getClassInitializationInfo() == null, "Class initialization info already computed for %s.", type.toJavaName(true)); boolean initializedAtBuildTime = SimulateClassInitializerSupport.singleton().trySimulateClassInitializer(bb, type); ClassInitializationInfo info; - boolean typeReachedTracked = ClassInitializationSupport.singleton().requiresInitializationNodeForTypeReached(type); - if (initializedAtBuildTime) { - info = type.getClassInitializer() == null ? ClassInitializationInfo.forNoInitializerInfo(typeReachedTracked) - : ClassInitializationInfo.forInitializedInfo(typeReachedTracked); + if (type.getWrapped() instanceof BaseLayerType) { + info = HostedImageLayerBuildingSupport.singleton().getLoader().getClassInitializationInfo(type); } else { - info = buildRuntimeInitializationInfo(type, typeReachedTracked); + boolean typeReachedTracked = ClassInitializationSupport.singleton().requiresInitializationNodeForTypeReached(type); + if (initializedAtBuildTime) { + info = type.getClassInitializer() == null ? ClassInitializationInfo.forNoInitializerInfo(typeReachedTracked) + : ClassInitializationInfo.forInitializedInfo(typeReachedTracked); + } else { + info = buildRuntimeInitializationInfo(type, typeReachedTracked); + } } hub.setClassInitializationInfo(info); if (rescan) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java index 544020ddfe36..d435896556c0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java @@ -29,8 +29,19 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.C_ENTRY_POINT_LITERAL_CODE_POINTER; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_KEYS; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_OBJECTS; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_CLASS_INITIALIZER_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_HAS_INITIALIZER_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_BUILD_TIME_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_IN_ERROR_STATE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_LINKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_TRACKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_FAILED_NO_TRACKING_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_NO_TRACKING_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_NO_INITIALIZER_NO_TRACKING_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_POINTER_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TYPES_TAG; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -56,6 +67,7 @@ import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.classinitialization.ClassInitializationInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; @@ -110,6 +122,45 @@ public HostedUniverse getHostedUniverse() { return hostedUniverse; } + public ClassInitializationInfo getClassInitializationInfo(AnalysisType type) { + int tid = type.getId(); + EconomicMap typesMap = get(jsonMap, TYPES_TAG); + EconomicMap typeMap = get(typesMap, typeIdToIdentifier.get(tid)); + + boolean isNoInitializerNoTracking = get(typeMap, IS_NO_INITIALIZER_NO_TRACKING_TAG); + boolean isInitializedNoTracking = get(typeMap, IS_INITIALIZED_NO_TRACKING_TAG); + boolean isFailedNoTracking = get(typeMap, IS_FAILED_NO_TRACKING_TAG); + + if (isNoInitializerNoTracking) { + return ClassInitializationInfo.forNoInitializerInfo(false); + } else if (isInitializedNoTracking) { + return ClassInitializationInfo.forInitializedInfo(false); + } else if (isFailedNoTracking) { + return ClassInitializationInfo.forFailedInfo(false); + } else { + boolean isInitialized = get(typeMap, INFO_IS_INITIALIZED_TAG); + boolean isInErrorState = get(typeMap, INFO_IS_IN_ERROR_STATE_TAG); + boolean isLinked = get(typeMap, INFO_IS_LINKED_TAG); + boolean hasInitializer = get(typeMap, INFO_HAS_INITIALIZER_TAG); + boolean isBuildTimeInitialized = get(typeMap, INFO_IS_BUILD_TIME_INITIALIZED_TAG); + boolean isTracked = get(typeMap, INFO_IS_TRACKED_TAG); + + ClassInitializationInfo.InitState initState; + if (isInitialized) { + initState = ClassInitializationInfo.InitState.FullyInitialized; + } else if (isInErrorState) { + initState = ClassInitializationInfo.InitState.InitializationError; + } else { + assert isLinked : "Invalid state"; + Integer classInitializerId = get(typeMap, INFO_CLASS_INITIALIZER_TAG); + MethodPointer classInitializer = classInitializerId == null ? null : new MethodPointer(getAnalysisMethod(classInitializerId)); + return new ClassInitializationInfo(classInitializer, isTracked); + } + + return new ClassInitializationInfo(initState, hasInitializer, isBuildTimeInitialized, isTracked); + } + } + @Override public Class lookupClass(boolean optional, String className) { TypeResult> typeResult = imageClassLoader.findClass(className); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index e4c654067d75..e93b389e3870 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -29,7 +29,17 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.HUB_IDENTITY_HASH_CODE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_KEYS; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_OBJECTS; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_CLASS_INITIALIZER_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_HAS_INITIALIZER_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_BUILD_TIME_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_IN_ERROR_STATE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_LINKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INFO_IS_TRACKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_FAILED_NO_TRACKING_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_AT_BUILD_TIME_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_NO_TRACKING_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_NO_INITIALIZER_NO_TRACKING_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_POINTER_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_TAG; @@ -55,8 +65,10 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.FunctionPointerHolder; import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.classinitialization.ClassInitializationInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; @@ -117,6 +129,25 @@ protected void persistType(AnalysisType type, EconomicMap typeMa typeMap.put(IS_INITIALIZED_AT_BUILD_TIME_TAG, ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(type)); + ClassInitializationInfo info = hub.getClassInitializationInfo(); + if (info != null) { + typeMap.put(IS_NO_INITIALIZER_NO_TRACKING_TAG, info == ClassInitializationInfo.forNoInitializerInfo(false)); + typeMap.put(IS_INITIALIZED_NO_TRACKING_TAG, info == ClassInitializationInfo.forInitializedInfo(false)); + typeMap.put(IS_FAILED_NO_TRACKING_TAG, info == ClassInitializationInfo.forFailedInfo(false)); + typeMap.put(INFO_IS_INITIALIZED_TAG, info.isInitialized()); + typeMap.put(INFO_IS_IN_ERROR_STATE_TAG, info.isInErrorState()); + typeMap.put(INFO_IS_LINKED_TAG, info.isLinked()); + typeMap.put(INFO_HAS_INITIALIZER_TAG, info.hasInitializer()); + typeMap.put(INFO_IS_BUILD_TIME_INITIALIZED_TAG, info.isBuildTimeInitialized()); + typeMap.put(INFO_IS_TRACKED_TAG, info.isTracked()); + FunctionPointerHolder classInitializer = info.getClassInitializer(); + if (classInitializer != null) { + MethodPointer methodPointer = (MethodPointer) classInitializer.functionPointer; + AnalysisMethod classInitializerMethod = (AnalysisMethod) methodPointer.getMethod(); + typeMap.put(INFO_CLASS_INITIALIZER_TAG, classInitializerMethod.getId()); + } + } + super.persistType(type, typeMap); } From 495455a6eccd3ba8cde67618586792e9da11463e Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 28 Aug 2024 15:10:24 +0200 Subject: [PATCH 4/5] Correctly reload generated serialization types --- .../graal/pointsto/heap/ImageLayerLoader.java | 8 ++++ .../pointsto/heap/ImageLayerLoaderHelper.java | 5 +++ .../pointsto/heap/ImageLayerSnapshotUtil.java | 6 ++- .../graal/pointsto/heap/ImageLayerWriter.java | 2 + .../pointsto/heap/ImageLayerWriterHelper.java | 6 +++ .../heap/SVMImageLayerLoaderHelper.java | 45 ++++++++++++++++--- .../heap/SVMImageLayerSnapshotUtil.java | 4 +- .../heap/SVMImageLayerWriterHelper.java | 22 ++++++++- .../serialize/SerializationFeature.java | 6 ++- 9 files changed, 93 insertions(+), 11 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index ffb2d5fe37ca..d8ee577e4e57 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -348,6 +348,10 @@ public List getLoadPaths() { return loadPaths; } + public AnalysisUniverse getUniverse() { + return universe; + } + public void setUniverse(AnalysisUniverse newUniverse) { this.universe = newUniverse; } @@ -449,6 +453,10 @@ protected void prepareConstantRelinking(EconomicMap constantData private void loadType(EconomicMap typeData) { int tid = get(typeData, ID_TAG); + if (imageLayerLoaderHelper.loadType(typeData, tid)) { + return; + } + String name = get(typeData, CLASS_JAVA_NAME_TAG); Class clazz = lookupBaseLayerTypeInHostVM(name); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java index f94f5a6c526a..01bd77248601 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java @@ -33,6 +33,11 @@ public ImageLayerLoaderHelper(ImageLayerLoader imageLayerLoader) { this.imageLayerLoader = imageLayerLoader; } + @SuppressWarnings("unused") + protected boolean loadType(EconomicMap typeData, int tid) { + return false; + } + @SuppressWarnings("unused") protected boolean loadMethod(EconomicMap methodData, int mid) { return false; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 36be14fe0d1f..0e333da2eee0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -102,6 +102,10 @@ public class ImageLayerSnapshotUtil { public static final String COMPONENT_TYPE_TAG = "component type"; public static final String SUPER_CLASS_TAG = "super class"; public static final String INTERFACES_TAG = "interfaces"; + public static final String WRAPPED_TYPE_TAG = "wrapped type"; + public static final String GENERATED_SERIALIZATION_TAG = "generated serialization"; + public static final String RAW_DECLARING_CLASS_TAG = "raw declaring class"; + public static final String RAW_TARGET_CONSTRUCTOR_CLASS_TAG = "raw target constructor class"; public static final String CONSTANTS_TAG = "constants"; public static final String CONSTANTS_TO_RELINK_TAG = "constants to relink"; public static final String TID_TAG = "tid"; @@ -110,7 +114,7 @@ public class ImageLayerSnapshotUtil { public static final String ARGUMENT_IDS_TAG = "argument ids"; public static final String RETURN_TYPE_TAG = "return type"; public static final String IS_VAR_ARGS_TAG = "is varArg"; - public static final String METHOD_TYPE_TAG = "method type"; + public static final String WRAPPED_METHOD_TAG = "wrapped method"; public static final String METHOD_TYPE_PARAMETERS_TAG = "method type parameters"; public static final String METHOD_TYPE_RETURN_TAG = "method type return"; public static final String FACTORY_TAG = "factory"; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index d09f0d1e9604..253f6610100c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -314,6 +314,8 @@ protected void persistType(AnalysisType type, EconomicMap typeMa typeMap.put(IS_INSTANTIATED, type.isInstantiated()); typeMap.put(IS_UNSAFE_ALLOCATED, type.isUnsafeAllocated()); typeMap.put(IS_REACHABLE, type.isReachable()); + + imageLayerWriterHelper.persistType(type, typeMap); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java index cbf6f837d280..9a942a6ca894 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java @@ -27,6 +27,7 @@ import org.graalvm.collections.EconomicMap; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; public class ImageLayerWriterHelper { protected final ImageLayerWriter imageLayerWriter; @@ -35,6 +36,11 @@ public ImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) { this.imageLayerWriter = imageLayerWriter; } + @SuppressWarnings("unused") + protected void persistType(AnalysisType type, EconomicMap typeMap) { + /* No additional information to persist */ + } + @SuppressWarnings("unused") protected void persistMethod(AnalysisMethod method, EconomicMap methodMap) { /* No additional information to persist */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java index e9e358dafc3e..5d0b6b9628ba 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java @@ -26,33 +26,68 @@ import static com.oracle.graal.pointsto.heap.ImageLayerLoader.get; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.FACTORY_TAG; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_TYPE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.GENERATED_SERIALIZATION_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RAW_DECLARING_CLASS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RAW_TARGET_CONSTRUCTOR_CLASS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TARGET_CONSTRUCTOR_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.THROW_ALLOCATED_OBJECT_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.WRAPPED_METHOD_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.WRAPPED_TYPE_TAG; + +import java.lang.reflect.Constructor; import org.graalvm.collections.EconomicMap; import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.heap.ImageLayerLoaderHelper; +import com.oracle.svm.core.reflect.serialize.SerializationSupport; import com.oracle.svm.hosted.code.FactoryMethodSupport; +import com.oracle.svm.hosted.reflect.serialize.SerializationFeature; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.internal.reflect.ReflectionFactory; public class SVMImageLayerLoaderHelper extends ImageLayerLoaderHelper { public SVMImageLayerLoaderHelper(ImageLayerLoader imageLayerLoader) { super(imageLayerLoader); } + @Override + protected boolean loadType(EconomicMap typeData, int tid) { + String wrappedType = get(typeData, WRAPPED_TYPE_TAG); + if (wrappedType == null) { + return false; + } + if (wrappedType.equals(GENERATED_SERIALIZATION_TAG)) { + String rawDeclaringClassName = get(typeData, RAW_DECLARING_CLASS_TAG); + String rawTargetConstructorClassName = get(typeData, RAW_TARGET_CONSTRUCTOR_CLASS_TAG); + Class rawDeclaringClass = imageLayerLoader.lookupClass(false, rawDeclaringClassName); + Class rawTargetConstructorClass = imageLayerLoader.lookupClass(false, rawTargetConstructorClassName); + SerializationSupport serializationSupport = SerializationSupport.singleton(); + Constructor rawTargetConstructor = ReflectionUtil.lookupConstructor(rawTargetConstructorClass); + Constructor constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(rawDeclaringClass, rawTargetConstructor); + serializationSupport.addConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass, SerializationFeature.getConstructorAccessor(constructor)); + Class constructorAccessor = serializationSupport.getSerializationConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass).getClass(); + imageLayerLoader.getMetaAccess().lookupJavaType(constructorAccessor); + return true; + } + + return super.loadType(typeData, tid); + } + @Override protected boolean loadMethod(EconomicMap methodData, int mid) { - String methodType = get(methodData, METHOD_TYPE_TAG); - if (methodType == null) { + String wrappedMethod = get(methodData, WRAPPED_METHOD_TAG); + if (wrappedMethod == null) { return false; } - if (methodType.equals(FACTORY_TAG)) { + if (wrappedMethod.equals(FACTORY_TAG)) { int constructorId = get(methodData, TARGET_CONSTRUCTOR_TAG); boolean throwAllocatedObject = get(methodData, THROW_ALLOCATED_OBJECT_TAG); FactoryMethodSupport.singleton().lookup(imageLayerLoader.getMetaAccess(), imageLayerLoader.getAnalysisMethod(constructorId), throwAllocatedObject); return true; } - return false; + + return super.loadMethod(methodData, mid); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java index ffc17a12b6f6..a829d10a6a27 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java @@ -90,7 +90,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { - private static final String GENERATED_SERIALIZATION = "jdk.internal.reflect.GeneratedSerializationConstructorAccessor"; + public static final String GENERATED_SERIALIZATION = "jdk.internal.reflect.GeneratedSerializationConstructorAccessor"; public static final Field companion = ReflectionUtil.lookupField(DynamicHub.class, "companion"); public static final Field classInitializationInfo = ReflectionUtil.lookupField(DynamicHub.class, "classInitializationInfo"); @@ -149,7 +149,7 @@ protected boolean shouldAddExternalValue(Class type) { @Override public String getTypeIdentifier(AnalysisType type) { if (type.toJavaName(true).contains(GENERATED_SERIALIZATION)) { - getGeneratedSerializationName(type); + return getGeneratedSerializationName(type); } if (isProxyType(type)) { return type.toJavaName(true); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java index 85f05c51eb6d..9ce455f23d23 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java @@ -25,15 +25,22 @@ package com.oracle.svm.hosted.heap; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.FACTORY_TAG; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_TYPE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.GENERATED_SERIALIZATION_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RAW_DECLARING_CLASS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RAW_TARGET_CONSTRUCTOR_CLASS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TARGET_CONSTRUCTOR_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.THROW_ALLOCATED_OBJECT_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.WRAPPED_METHOD_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.WRAPPED_TYPE_TAG; +import static com.oracle.svm.hosted.heap.SVMImageLayerSnapshotUtil.GENERATED_SERIALIZATION; import org.graalvm.collections.EconomicMap; import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.heap.ImageLayerWriterHelper; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.reflect.serialize.SerializationSupport; import com.oracle.svm.hosted.code.FactoryMethod; public class SVMImageLayerWriterHelper extends ImageLayerWriterHelper { @@ -41,10 +48,21 @@ public SVMImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) { super(imageLayerWriter); } + @Override + protected void persistType(AnalysisType type, EconomicMap typeMap) { + if (type.toJavaName(true).contains(GENERATED_SERIALIZATION)) { + typeMap.put(WRAPPED_TYPE_TAG, GENERATED_SERIALIZATION_TAG); + var key = SerializationSupport.singleton().getKeyFromConstructorAccessorClass(type.getJavaClass()); + typeMap.put(RAW_DECLARING_CLASS_TAG, key.getDeclaringClass().getName()); + typeMap.put(RAW_TARGET_CONSTRUCTOR_CLASS_TAG, key.getTargetConstructorClass().getName()); + } + super.persistType(type, typeMap); + } + @Override protected void persistMethod(AnalysisMethod method, EconomicMap methodMap) { if (method.wrapped instanceof FactoryMethod factoryMethod) { - methodMap.put(METHOD_TYPE_TAG, FACTORY_TAG); + methodMap.put(WRAPPED_METHOD_TAG, FACTORY_TAG); AnalysisMethod targetConstructor = method.getUniverse().lookup(factoryMethod.getTargetConstructor()); if (!method.isReachable() && !imageLayerWriter.isMethodPersisted(targetConstructor)) { imageLayerWriter.persistAnalysisParsedGraph(targetConstructor); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 0dc3c74f3ada..2775baaf1d21 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -306,6 +306,10 @@ private static Stream allExecutablesDeclaredInClas Arrays.stream(t.getDeclaredConstructors(false))), t.getClassInitializer() == null ? Stream.empty() : Stream.of(t.getClassInitializer())); } + + public static Object getConstructorAccessor(Constructor constructor) { + return SerializationBuilder.getConstructorAccessor(constructor); + } } final class SerializationDenyRegistry implements RuntimeSerializationSupport { @@ -691,7 +695,7 @@ private static Constructor newConstructorForSerialization(Class serializat } } - private static Object getConstructorAccessor(Constructor constructor) { + static Object getConstructorAccessor(Constructor constructor) { try { return getConstructorAccessorMethod.invoke(constructor); } catch (ReflectiveOperationException e) { From 85d850ef14b7fbfd5e3acd9351ce3685f80d20ff Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 28 Aug 2024 15:11:25 +0200 Subject: [PATCH 5/5] Handle DelegatingClassLoader created by GeneratedSerialization types in Layered Images --- .../serialize/SerializationSupport.java | 23 +++++++++++++++++++ .../oracle/svm/hosted/ClassLoaderFeature.java | 10 ++++++++ .../HostedClassLoaderPackageManagement.java | 15 ++++++++++++ 3 files changed, 48 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java index 50efbc5162c6..70f0cfbf92dd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java @@ -155,6 +155,29 @@ public SerializationLookupKey getKeyFromConstructorAccessorClass(Class constr return null; } + @Platforms(Platform.HOSTED_ONLY.class) + public boolean isGeneratedSerializationClassLoader(ClassLoader classLoader) { + var constructorAccessorsCursor = constructorAccessors.getEntries(); + while (constructorAccessorsCursor.advance()) { + if (constructorAccessorsCursor.getValue().getClass().getClassLoader() == classLoader) { + return true; + } + } + return false; + } + + @Platforms(Platform.HOSTED_ONLY.class) + public String getClassLoaderSerializationLookupKey(ClassLoader classLoader) { + var constructorAccessorsCursor = constructorAccessors.getEntries(); + while (constructorAccessorsCursor.advance()) { + if (constructorAccessorsCursor.getValue().getClass().getClassLoader() == classLoader) { + var key = constructorAccessorsCursor.getKey(); + return key.declaringClass.getName() + key.targetConstructorClass.getName(); + } + } + throw VMError.shouldNotReachHere("No constructor accessor uses the class loader %s", classLoader); + } + private final EconomicMap, RuntimeConditionSet> classes = EconomicMap.create(); private final EconomicMap lambdaCapturingClasses = EconomicMap.create(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java index 8f14286bed92..8021c85703e9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassLoaderFeature.java @@ -93,6 +93,8 @@ ImageHeapConstant replaceClassLoadersWithLayerConstant(CrossLayerConstantRegistr return registry.getConstant(PLATFORM_KEY_NAME); } else if (loader == bootClassLoader) { return registry.getConstant(BOOT_KEY_NAME); + } else if (HostedClassLoaderPackageManagement.isGeneratedSerializationClassLoader(loader)) { + return registry.getConstant(HostedClassLoaderPackageManagement.getClassLoaderSerializationLookupKey(loader)); } else { throw VMError.shouldNotReachHere("Currently unhandled class loader seen in extension layer: %s", loader); } @@ -134,6 +136,14 @@ public Object transform(Object receiver, Object originalValue) { assert receiver instanceof ClassLoader : receiver; assert originalValue instanceof ConcurrentHashMap : "Underlying representation has changed: " + originalValue; + if (ImageLayerBuildingSupport.buildingInitialLayer()) { + var registry = CrossLayerConstantRegistry.singletonOrNull(); + ClassLoader classLoader = (ClassLoader) receiver; + if (HostedClassLoaderPackageManagement.isGeneratedSerializationClassLoader(classLoader)) { + registry.registerHeapConstant(HostedClassLoaderPackageManagement.getClassLoaderSerializationLookupKey(classLoader), receiver); + } + } + /* Retrieving initial package state for this class loader. */ ConcurrentHashMap packages = HostedClassLoaderPackageManagement.singleton().getRegisteredPackages((ClassLoader) receiver); /* If no package state is available then we must create a clean state. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java index e3f9fd4170d4..f7e30a012d43 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/HostedClassLoaderPackageManagement.java @@ -46,6 +46,7 @@ import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.reflect.serialize.SerializationSupport; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.BootLoaderSupport; import com.oracle.svm.hosted.ClassLoaderFeature; @@ -83,6 +84,9 @@ public class HostedClassLoaderPackageManagement implements LayeredImageSingleton private static final String APP_KEY = "AppPackageNames"; private static final String PLATFORM_KEY = "PlatformPackageNames"; private static final String BOOT_KEY = "BootPackageNames"; + private static final String GENERATED_SERIALIZATION_KEY = "GeneratedSerializationNames"; + + private static final String GENERATED_SERIALIZATION_PACKAGE = "jdk.internal.reflect"; private static final Method packageGetPackageInfo = ReflectionUtil.lookupMethod(Package.class, "getPackageInfo"); @@ -152,6 +156,9 @@ private boolean isPackageRegistered(ClassLoader classLoader, String packageName, if (priorAppPackageNames.contains(packageName)) { return true; } + } else if (isGeneratedSerializationClassLoader(classLoader)) { + VMError.guarantee(packageName.equals(GENERATED_SERIALIZATION_PACKAGE), "Unexpected package %s in generated serialization class loader", packageValue); + return true; } else { throw VMError.shouldNotReachHere("Currently unhandled class loader seen in extension layer: %s", classLoader); } @@ -161,6 +168,14 @@ private boolean isPackageRegistered(ClassLoader classLoader, String packageName, return loaderPackages != null && loaderPackages.containsKey(packageName); } + public static boolean isGeneratedSerializationClassLoader(ClassLoader classLoader) { + return SerializationSupport.singleton().isGeneratedSerializationClassLoader(classLoader); + } + + public static String getClassLoaderSerializationLookupKey(ClassLoader classLoader) { + return GENERATED_SERIALIZATION_KEY + SerializationSupport.singleton().getClassLoaderSerializationLookupKey(classLoader); + } + /** * Register the package with its runtimeClassLoader. */