From 025c394b3f6567bdb3a02a5692c38b0c73ea81a2 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Thu, 16 Jan 2025 17:12:37 +0100 Subject: [PATCH] Allow InitialLayerOnlyImageSingletons to be looked up in later layers. --- .../svm/core/jdk/StringInternSupport.java | 5 +++ .../InitialLayerOnlyImageSingleton.java | 12 +++++++ .../LayeredImageSingletonSupport.java | 8 ++++- .../SharedLayerSnapshotCapnProtoSchema.capnp | 1 + .../hosted/ImageSingletonsSupportImpl.java | 31 +++++++++++++++++-- .../imagelayer/LoadImageSingletonFeature.java | 11 ++++++- .../SVMImageLayerSingletonLoader.java | 26 +++++++++++++--- .../imagelayer/SVMImageLayerSnapshotUtil.java | 26 +++++++++------- .../imagelayer/SVMImageLayerWriter.java | 14 +++++++++ ...redLayerSnapshotCapnProtoSchemaHolder.java | 13 +++++++- .../SubstrateGraphBuilderPlugins.java | 11 +++++++ 11 files changed, 136 insertions(+), 22 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StringInternSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StringInternSupport.java index 88d1e14871c0..82b1c8e831b4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StringInternSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StringInternSupport.java @@ -196,6 +196,11 @@ static ConcurrentHashMap getInternedStrings() { return ImageSingletons.lookup(RuntimeInternedStrings.class).internedStrings; } + @Override + public boolean accessibleInFutureLayers() { + return true; + } + @Override public EnumSet getImageBuilderFlags() { return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/InitialLayerOnlyImageSingleton.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/InitialLayerOnlyImageSingleton.java index 4f566aa842ea..2eca3250dbea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/InitialLayerOnlyImageSingleton.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/InitialLayerOnlyImageSingleton.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.layeredimagesingleton; +import org.graalvm.nativeimage.ImageSingletons; + import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.util.VMError; @@ -34,4 +36,14 @@ default PersistFlags preparePersist(ImageSingletonWriter writer) { VMError.guarantee(ImageLayerBuildingSupport.buildingInitialLayer(), "This singleton should only be installed in the initial layer"); return PersistFlags.FORBIDDEN; } + + /** + * When true is returned, runtime code within future layers can call + * {@link ImageSingletons#lookup} and the singleton will be constant folded into the code. In + * the future layers it will still not be possible to call {@link ImageSingletons#lookup} at + * build time. + */ + default boolean accessibleInFutureLayers() { + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonSupport.java index 3cfb2bd62da9..c8786c73fb52 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonSupport.java @@ -30,6 +30,8 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import jdk.vm.ci.meta.JavaConstant; + @Platforms(Platform.HOSTED_ONLY.class) public interface LayeredImageSingletonSupport { @@ -47,5 +49,9 @@ static LayeredImageSingletonSupport singleton() { Collection> getMultiLayeredImageSingletonKeys(); - void freezeMultiLayeredImageSingletons(); + Collection> getFutureLayerAccessibleImageSingletonKeys(); + + void freezeLayeredImageSingletonMetadata(); + + JavaConstant getInitialLayerOnlyImageSingleton(Class key); } diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index c5adcbaa086d..8bdc63b43fff 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -209,6 +209,7 @@ struct ImageSingletonKey { keyClassName @0 :Text; persistFlag @1 :Int32; objectId @2 :SingletonObjId; + constantId @3 :ConstantId; } struct ImageSingletonObject { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java index 3599c60c85fe..0d85bde88607 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java @@ -36,6 +36,7 @@ import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.layeredimagesingleton.ApplicationLayerOnlyImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton.PersistFlags; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; @@ -47,6 +48,8 @@ import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.imagelayer.SVMImageLayerSingletonLoader; +import jdk.vm.ci.meta.JavaConstant; + public final class ImageSingletonsSupportImpl extends ImageSingletonsSupport implements LayeredImageSingletonSupport { @Override @@ -70,8 +73,19 @@ public Collection> getMultiLayeredImageSingletonKeys() { } @Override - public void freezeMultiLayeredImageSingletons() { - HostedManagement.getAndAssertExists().freezeMultiLayeredImageSingletons(); + public Collection> getFutureLayerAccessibleImageSingletonKeys() { + return HostedManagement.getAndAssertExists().getFutureLayerAccessibleImageSingletonKeys(); + } + + @Override + public void freezeLayeredImageSingletonMetadata() { + HostedManagement.getAndAssertExists().freezeLayeredImageSingletonMetadata(); + } + + @Override + public JavaConstant getInitialLayerOnlyImageSingleton(Class key) { + var loader = HostedImageLayerBuildingSupport.singleton().getSingletonLoader(); + return loader.loadInitialLayerOnlyImageSingleton(key); } @Override @@ -181,6 +195,7 @@ public static void persist() { private final Map, Object> configObjects; private final boolean checkUnsupported; private Set> multiLayeredImageSingletonKeys; + private Set> futureLayerAccessibleImageSingletonKeys; public HostedManagement() { this(false); @@ -189,6 +204,7 @@ public HostedManagement() { public HostedManagement(boolean checkUnsupported) { this.configObjects = new ConcurrentHashMap<>(); this.multiLayeredImageSingletonKeys = ConcurrentHashMap.newKeySet(); + this.futureLayerAccessibleImageSingletonKeys = ConcurrentHashMap.newKeySet(); this.checkUnsupported = checkUnsupported; } @@ -229,6 +245,10 @@ private void doAddInternal(Class key, Object value) { } } + if (singleton instanceof InitialLayerOnlyImageSingleton initial && initial.accessibleInFutureLayers()) { + futureLayerAccessibleImageSingletonKeys.add(key); + } + if (!singleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS)) { storedValue = new RuntimeOnlyWrapper(singleton); } @@ -245,8 +265,13 @@ Collection> getMultiLayeredImageSingletonKeys() { return multiLayeredImageSingletonKeys; } - void freezeMultiLayeredImageSingletons() { + Collection> getFutureLayerAccessibleImageSingletonKeys() { + return futureLayerAccessibleImageSingletonKeys; + } + + void freezeLayeredImageSingletonMetadata() { multiLayeredImageSingletonKeys = Set.copyOf(multiLayeredImageSingletonKeys); + futureLayerAccessibleImageSingletonKeys = Set.copyOf(futureLayerAccessibleImageSingletonKeys); } T doLookup(Class key, boolean stripRuntimeOnly, boolean allowMultiLayered) { 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 6b8699227754..793918b51d24 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 @@ -192,7 +192,7 @@ public void processRegisteredSingletons(AnalysisUniverse universe) { loader = (SVMImageLayerLoader) universe.getImageLayerLoader(); LayeredImageSingletonSupport layeredImageSingletonSupport = LayeredImageSingletonSupport.singleton(); - layeredImageSingletonSupport.freezeMultiLayeredImageSingletons(); + layeredImageSingletonSupport.freezeLayeredImageSingletonMetadata(); Consumer multiLayerEmbeddedRootsRegistration = (objArray) -> { var method = metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(MultiLayeredImageSingleton.class, "getAllLayers", Class.class)); @@ -211,6 +211,15 @@ public void processRegisteredSingletons(AnalysisUniverse universe) { if (multiLayeredSingletons.length != 0) { multiLayerEmbeddedRootsRegistration.accept(multiLayeredSingletons); } + + /* + * Make sure all image singletons accessible in future layers are persisted. + */ + for (Class key : layeredImageSingletonSupport.getFutureLayerAccessibleImageSingletonKeys()) { + var singleton = layeredImageSingletonSupport.lookup(key, true, false); + ImageHeapConstant constant = (ImageHeapConstant) universe.getSnippetReflection().forObject(singleton); + SVMImageLayerSnapshotUtil.forcePersistConstant(constant); + } } if (ImageLayerBuildingSupport.buildingInitialLayer()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java index 06942a9695e0..b1085fe2a9f0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java @@ -41,16 +41,21 @@ import org.graalvm.collections.UnmodifiableEconomicMap; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton.PersistFlags; +import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; import com.oracle.svm.util.ReflectionUtil; +import jdk.vm.ci.meta.JavaConstant; + public class SVMImageLayerSingletonLoader { private final HostedImageLayerBuildingSupport imageLayerBuildingSupport; private final SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Reader snapshot; + private Map, Integer> initialLayerOnlySingletonConstantIds; public SVMImageLayerSingletonLoader(HostedImageLayerBuildingSupport imageLayerBuildingSupport, SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Reader snapshot) { this.imageLayerBuildingSupport = imageLayerBuildingSupport; @@ -58,11 +63,8 @@ public SVMImageLayerSingletonLoader(HostedImageLayerBuildingSupport imageLayerBu } public Map>> loadImageSingletons(Object forbiddenObject) { - return loadImageSingletons0(forbiddenObject); - } - - private Map>> loadImageSingletons0(Object forbiddenObject) { Map idToObjectMap = new HashMap<>(); + Map, Integer> initialLayerKeyToIdMap = new HashMap<>(); for (ImageSingletonObject.Reader obj : snapshot.getSingletonObjects()) { String className = obj.getClassName().toString(); @@ -110,15 +112,31 @@ private Map>> loadImageSingletons0(Object forbiddenObject) Class clazz = imageLayerBuildingSupport.lookupClass(false, className); singletonInitializationMap.computeIfAbsent(forbiddenObject, (k) -> new HashSet<>()); singletonInitializationMap.get(forbiddenObject).add(clazz); + if (InitialLayerOnlyImageSingleton.class.isAssignableFrom(clazz)) { + int constantId = entry.getConstantId(); + if (constantId != -1) { + initialLayerKeyToIdMap.put(clazz, constantId); + } + } } else { assert persistInfo == PersistFlags.NOTHING : "Unexpected PersistFlags value: " + persistInfo; assert id == -1 : "Unrestored image singleton should not be linked to an object"; } } + initialLayerOnlySingletonConstantIds = Map.copyOf(initialLayerKeyToIdMap); + return singletonInitializationMap; } + public JavaConstant loadInitialLayerOnlyImageSingleton(Class key) { + int constantId = initialLayerOnlySingletonConstantIds.getOrDefault(key, -1); + if (constantId != -1) { + return imageLayerBuildingSupport.getLoader().getOrCreateConstant(constantId); + } + throw UserError.abort("Unable to load InitialLayerOnlyImageSingleton: %s. Please override accessibleInFutureLayers if you want this singleton to be reachable in future layers.", key); + } + public Class lookupClass(boolean optional, String className) { return imageLayerBuildingSupport.lookupClass(optional, className); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java index 10ae960c3ee8..c9bcb09540cc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java @@ -322,6 +322,19 @@ private static String getQualifiedName(AnalysisMethod method) { return method.getSignature().getReturnType().toJavaName(true) + " " + method.getQualifiedName(); } + public static void forcePersistConstant(ImageHeapConstant imageHeapConstant) { + AnalysisUniverse universe = imageHeapConstant.getType().getUniverse(); + universe.getHeapScanner().markReachable(imageHeapConstant, ObjectScanner.OtherReason.PERSISTED); + + imageHeapConstant.getType().registerAsTrackedAcrossLayers(imageHeapConstant); + /* If this is a Class constant persist the corresponding type. */ + ConstantReflectionProvider constantReflection = universe.getBigbang().getConstantReflectionProvider(); + AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(imageHeapConstant); + if (typeFromClassConstant != null) { + typeFromClassConstant.registerAsTrackedAcrossLayers(imageHeapConstant); + } + } + public static class SVMGraphEncoder extends ObjectCopier.Encoder { @SuppressWarnings("this-escape") public SVMGraphEncoder(Map externalValues) { @@ -407,18 +420,7 @@ protected ImageHeapConstantBuiltIn(SVMImageLayerLoader imageLayerLoader) { @Override public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { ImageHeapConstant imageHeapConstant = (ImageHeapConstant) obj; - - AnalysisUniverse universe = imageHeapConstant.getType().getUniverse(); - universe.getHeapScanner().markReachable(imageHeapConstant, ObjectScanner.OtherReason.PERSISTED); - - imageHeapConstant.getType().registerAsTrackedAcrossLayers(imageHeapConstant); - /* If this is a Class constant persist the corresponding type. */ - ConstantReflectionProvider constantReflection = universe.getBigbang().getConstantReflectionProvider(); - AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(imageHeapConstant); - if (typeFromClassConstant != null) { - typeFromClassConstant.registerAsTrackedAcrossLayers(imageHeapConstant); - } - + forcePersistConstant(imageHeapConstant); stream.writePackedUnsignedInt(ImageHeapConstant.getConstantID(imageHeapConstant)); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java index fd6d4d46ad9c..a23cb09b94a9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java @@ -105,6 +105,7 @@ 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.InitialLayerOnlyImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.RuntimeOnlyWrapper; import com.oracle.svm.core.meta.MethodPointer; @@ -179,6 +180,7 @@ public class SVMImageLayerWriter extends ImageLayerWriter { private final SharedLayerSnapshot.Builder snapshotBuilder = this.snapshotFileBuilder.initRoot(SharedLayerSnapshot.factory); private Map constantsMap; private final Map methodsMap = new ConcurrentHashMap<>(); + private final Map initialLayerOnlySingletonMap = new ConcurrentHashMap<>(); private FileInfo fileInfo; private GraphsOutput graphsOutput; private final boolean useSharedLayerGraphs; @@ -740,6 +742,13 @@ private void persistConstant(ImageHeapConstant imageHeapConstant, ConstantParent int identityHashCode = identityHashCodeProvider.identityHashCode(imageHeapConstant); builder.setIdentityHashCode(identityHashCode); + if (imageHeapConstant.isBackedByHostedObject() && InitialLayerOnlyImageSingleton.class.isAssignableFrom(type.getJavaClass())) { + InitialLayerOnlyImageSingleton singleton = aUniverse.getBigbang().getSnippetReflectionProvider().asObject(InitialLayerOnlyImageSingleton.class, imageHeapConstant.getHostedObject()); + if (singleton.accessibleInFutureLayers()) { + initialLayerOnlySingletonMap.put(singleton, id); + } + } + switch (imageHeapConstant) { case ImageHeapInstance imageHeapInstance -> { builder.initObject().setInstance(Void.VOID); @@ -994,6 +1003,11 @@ public void writeImageSingletonInfo(List, Object>> layeredIma sb.setKeyClassName(key); sb.setObjectId(info.id); sb.setPersistFlag(info.flags.ordinal()); + int constantId = -1; + if (singleton instanceof InitialLayerOnlyImageSingleton initialLayerOnlyImageSingleton && initialLayerOnlyImageSingleton.accessibleInFutureLayers()) { + constantId = initialLayerOnlySingletonMap.getOrDefault(initialLayerOnlyImageSingleton, -1); + } + sb.setConstantId(constantId); } var sortedByIDs = singletonInfoMap.entrySet().stream() diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java index 314092b6d105..3155822e08d1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java @@ -3622,7 +3622,7 @@ public enum Which { public static class ImageSingletonKey { - public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)1,(short)1); + public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)2,(short)1); public static final class Factory extends org.capnproto.StructFactory { public Factory() { } @@ -3678,6 +3678,13 @@ public final void setObjectId(int value) { _setIntField(1, value); } + public final int getConstantId() { + return _getIntField(2); + } + public final void setConstantId(int value) { + _setIntField(2, value); + } + } public static final class Reader extends org.capnproto.StructReader { @@ -3700,6 +3707,10 @@ public final int getObjectId() { return _getIntField(1); } + public final int getConstantId() { + return _getIntField(2); + } + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 1146afdfd859..4de0ba6d0f06 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -87,6 +87,7 @@ import com.oracle.svm.core.imagelayer.LoadImageSingletonFactory; import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; import com.oracle.svm.core.layeredimagesingleton.ApplicationLayerOnlyImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport; @@ -1161,6 +1162,16 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } + if (InitialLayerOnlyImageSingleton.class.isAssignableFrom(key) && ImageLayerBuildingSupport.buildingExtensionLayer()) { + /* + * This singleton is only installed in the initial layer heap. When allowed, all + * other layers lookups refer to this singleton. + */ + JavaConstant initialSingleton = LayeredImageSingletonSupport.singleton().getInitialLayerOnlyImageSingleton(key); + b.addPush(JavaKind.Object, ConstantNode.forConstant(initialSingleton, b.getMetaAccess(), b.getGraph())); + return true; + } + Object singleton = LayeredImageSingletonSupport.singleton().lookup(key, true, true); if (singleton instanceof LayeredImageSingleton layeredSingleton) { if (!layeredSingleton.getImageBuilderFlags().contains(LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS)) {