From fb9ade3cc1c9af3222662eebcb2b0fefc9360236 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 14 Jul 2025 17:20:27 +0200 Subject: [PATCH 1/2] Refactor HostVM layer API --- .../com/oracle/graal/pointsto/api/HostVM.java | 12 ++++-- .../pointsto/heap/HeapSnapshotVerifier.java | 4 +- .../graal/pointsto/heap/ImageHeapScanner.java | 2 +- .../graal/pointsto/meta/AnalysisField.java | 2 +- .../graal/pointsto/meta/AnalysisMethod.java | 2 +- .../graal/pointsto/meta/AnalysisType.java | 2 +- .../graal/pointsto/meta/AnalysisUniverse.java | 4 +- .../oracle/svm/hosted/ProgressReporter.java | 2 +- .../src/com/oracle/svm/hosted/SVMHost.java | 42 +++++++++---------- .../analysis/DynamicHubInitializer.java | 2 +- 10 files changed, 39 insertions(+), 35 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 5b46d74892db..17c9b7be39d7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -184,10 +184,6 @@ public boolean isCoreType(@SuppressWarnings("unused") AnalysisType type) { return false; } - public boolean useBaseLayer() { - return false; - } - public boolean analyzedInPriorLayer(@SuppressWarnings("unused") AnalysisMethod method) { return false; } @@ -432,6 +428,14 @@ public boolean buildingImageLayer() { return false; } + public boolean buildingSharedLayer() { + return false; + } + + public boolean buildingExtensionLayer() { + return false; + } + @SuppressWarnings("unused") public boolean installableInLayer(AnalysisField aField) { return true; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index c02730ed3e55..88dc3bf77b7c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -333,11 +333,11 @@ private ImageHeapConstant getSnapshot(JavaConstant constant, ScanReason reason) result = (ImageHeapConstant) constant; } else { Object task = imageHeap.getSnapshot(constant); - if (task == null && bb.getUniverse().hostVM().useBaseLayer() && bb.getUniverse().getImageLayerLoader().hasValueForConstant(constant)) { + if (task == null && bb.getUniverse().hostVM().buildingExtensionLayer() && bb.getUniverse().getImageLayerLoader().hasValueForConstant(constant)) { /* The constant might not have been accessed in the extension image yet */ task = bb.getUniverse().getImageLayerLoader().getValueForConstant(constant); } - if (task == null && bb.getUniverse().hostVM().useBaseLayer()) { + if (task == null && bb.getUniverse().hostVM().buildingExtensionLayer()) { /* * This does not distinguish between base and extension layer constants at the * moment. Doing so would require some refactoring to determine earlier if the diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index ed9942fdda4a..38edfd08218a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -266,7 +266,7 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta if (existingTask == null) { AnalysisFuture newTask; ImageLayerLoader imageLayerLoader = universe.getImageLayerLoader(); - if (hostVM.useBaseLayer() && imageLayerLoader.hasValueForConstant(javaConstant)) { + if (hostVM.buildingExtensionLayer() && imageLayerLoader.hasValueForConstant(javaConstant)) { ImageHeapConstant value = imageLayerLoader.getValueForConstant(javaConstant); ensureFieldPositionsComputed(value, nonNullReason); AnalysisError.guarantee(value.getHostedObject().equals(javaConstant)); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index 530308bae78f..585a55cdba76 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -141,7 +141,7 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) sinkFlow = new ContextInsensitiveFieldTypeFlow(this, getType()); } - if (universe.hostVM().useBaseLayer() && declaringClass.isInBaseLayer()) { + if (universe.hostVM().buildingExtensionLayer() && declaringClass.isInBaseLayer()) { int fid = universe.getImageLayerLoader().lookupHostedFieldInBaseLayer(this); if (fid != -1) { /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index 197d4b999af8..e89faa9103ed 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -219,7 +219,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, qualifiedName = format("%H.%n(%P)"); modifiers = wrapped.getModifiers(); - if (universe.hostVM().useBaseLayer() && declaringClass.isInBaseLayer()) { + if (universe.hostVM().buildingExtensionLayer() && declaringClass.isInBaseLayer()) { int mid = universe.getImageLayerLoader().lookupHostedMethodInBaseLayer(this); if (mid != -1) { /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index 85927f9144fe..5ddce7cce422 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -287,7 +287,7 @@ public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKi } /* Set id after accessing super types, so that all these types get a lower id number. */ - if (universe.hostVM().useBaseLayer()) { + if (universe.hostVM().buildingExtensionLayer()) { int tid = universe.getImageLayerLoader().lookupHostedTypeInBaseLayer(this); if (tid != -1) { /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index e09ba6b7ad9d..96ea87f8980b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -216,7 +216,7 @@ public JavaType lookupAllowUnresolved(JavaType rawType) { AnalysisType result = optionalLookup(type); if (result == null) { result = createType(type); - if (hostVM.useBaseLayer() && result.isInBaseLayer()) { + if (hostVM.buildingExtensionLayer() && result.isInBaseLayer()) { imageLayerLoader.initializeBaseLayerType(result); } } @@ -308,7 +308,7 @@ private AnalysisType createType(ResolvedJavaType type) { * ensures that typesById doesn't contain any null values. This could happen since the * AnalysisType constructor increments the nextTypeId counter. */ - if (hostVM.useBaseLayer() && imageLayerLoader.hasDynamicHubIdentityHashCode(newValue.getId())) { + if (hostVM.buildingExtensionLayer() && imageLayerLoader.hasDynamicHubIdentityHashCode(newValue.getId())) { hostVM.registerType(newValue, imageLayerLoader.getDynamicHubIdentityHashCode(newValue.getId())); } else { hostVM.registerType(newValue); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index 0857ded57a97..e2154812424b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -536,7 +536,7 @@ public static List reportedReachableMethods(AnalysisUniverse uni private static List reportedElements(AnalysisUniverse universe, Collection elements, Predicate elementsFilter, Predicate baseLayerFilter) { Stream reachableElements = elements.stream().filter(elementsFilter); - return universe.hostVM().useBaseLayer() ? reachableElements.filter(baseLayerFilter).toList() : reachableElements.toList(); + return universe.hostVM().buildingExtensionLayer() ? reachableElements.filter(baseLayerFilter).toList() : reachableElements.toList(); } public ReporterClosable printUniverse() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index f1a80be200d6..8f2438214805 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -212,7 +212,9 @@ public enum UsageKind { private final SymbolEncoder encoder = SymbolEncoder.singleton(); private final int layerId; - private final boolean useBaseLayer; + private final boolean buildingImageLayer = ImageLayerBuildingSupport.buildingImageLayer(); + private final boolean buildingSharedLayer = ImageLayerBuildingSupport.buildingSharedLayer(); + private final boolean buildingExtensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); // All elements below are from the host VM universe, not the analysis universe private Set sharedLayerExcludedFields; @@ -221,9 +223,6 @@ public enum UsageKind { private final Boolean optionAllowUnsafeAllocationOfAllInstantiatedTypes = SubstrateOptions.AllowUnsafeAllocationOfAllInstantiatedTypes.getValue(); private final boolean isClosedTypeWorld = SubstrateOptions.useClosedTypeWorld(); - private final boolean enableTrackAcrossLayers; - private final boolean enableReachableInCurrentLayer; - private final boolean buildingImageLayer = ImageLayerBuildingSupport.buildingImageLayer(); private final LayeredStaticFieldSupport layeredStaticFieldSupport; private final MetaAccessProvider originalMetaAccess; @@ -256,15 +255,11 @@ public SVMHost(OptionValues options, ImageClassLoader loader, ClassInitializatio } else { parsingSupport = null; } - layerId = ImageLayerBuildingSupport.buildingImageLayer() ? DynamicImageLayerInfo.getCurrentLayerNumber() : 0; - useBaseLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); - if (ImageLayerBuildingSupport.buildingSharedLayer()) { + layerId = buildingImageLayer ? DynamicImageLayerInfo.getCurrentLayerNumber() : 0; + if (buildingSharedLayer) { initializeSharedLayerExcludedFields(); } - - enableTrackAcrossLayers = ImageLayerBuildingSupport.buildingSharedLayer(); - enableReachableInCurrentLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); - layeredStaticFieldSupport = ImageLayerBuildingSupport.buildingImageLayer() ? LayeredStaticFieldSupport.singleton() : null; + layeredStaticFieldSupport = buildingImageLayer ? LayeredStaticFieldSupport.singleton() : null; optionKeyType = lookupOriginalType(OptionKey.class); featureType = lookupOriginalType(Feature.class); @@ -283,8 +278,18 @@ public boolean isCoreType(AnalysisType type) { } @Override - public boolean useBaseLayer() { - return useBaseLayer; + public boolean buildingImageLayer() { + return buildingImageLayer; + } + + @Override + public boolean buildingSharedLayer() { + return buildingSharedLayer; + } + + @Override + public boolean buildingExtensionLayer() { + return buildingExtensionLayer; } /** @@ -989,7 +994,7 @@ public boolean sortFields() { * If building layered images sort the fields by kind and name to ensure stable order. * Sorting fields in general may lead to some issues. (GR-62599) */ - return ImageLayerBuildingSupport.buildingImageLayer(); + return buildingImageLayer; } /** If it's not one of the known builder types it must be an original VM type. */ @@ -1175,17 +1180,12 @@ public boolean isClosedTypeWorld() { @Override public boolean enableTrackAcrossLayers() { - return enableTrackAcrossLayers; + return buildingSharedLayer(); } @Override public boolean enableReachableInCurrentLayer() { - return enableReachableInCurrentLayer; - } - - @Override - public boolean buildingImageLayer() { - return buildingImageLayer; + return buildingExtensionLayer; } @Override 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 b90143020695..83d56929c9d6 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 @@ -172,7 +172,7 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) * GR-60254. */ private boolean shouldRescanHub(ImageHeapScanner heapScanner, DynamicHub hub) { - if (hostVM.useBaseLayer()) { + if (hostVM.buildingExtensionLayer()) { ImageHeapConstant hubConstant = (ImageHeapConstant) heapScanner.createImageHeapConstant(hub, OtherReason.HUB); return hubConstant == null || !hubConstant.isInBaseLayer(); } From 9f64dc7a4d7ad789836dc770f9ed996e267f32c1 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 11 Jun 2025 18:36:08 +0200 Subject: [PATCH 2/2] Allow to delay methods to the application layer --- .../graal/pointsto/PointsToAnalysis.java | 2 +- .../com/oracle/graal/pointsto/api/HostVM.java | 10 ++ .../graal/pointsto/flow/InvokeTypeFlow.java | 15 +++ .../graal/pointsto/flow/MethodFlowsGraph.java | 5 +- .../pointsto/flow/MethodTypeFlowBuilder.java | 5 + .../graal/pointsto/meta/AnalysisMethod.java | 82 +++++++++++++++- .../pointsto/results/StrengthenGraphs.java | 7 +- .../graal/amd64/SubstrateAMD64Backend.java | 44 +++++---- .../graal/snippets/NonSnippetLowerings.java | 16 +++- .../imagelayer/DynamicImageLayerInfo.java | 4 + .../SharedLayerSnapshotCapnProtoSchema.capnp | 29 +++--- .../src/com/oracle/svm/hosted/SVMHost.java | 7 ++ .../oracle/svm/hosted/code/CompileQueue.java | 11 ++- .../oracle/svm/hosted/image/NativeImage.java | 10 +- .../imagelayer/HostedDynamicLayerInfo.java | 78 ++++++++++++++- .../imagelayer/LayerDelayedMethodFeature.java | 51 ++++++++++ .../imagelayer/SVMImageLayerLoader.java | 3 + .../imagelayer/SVMImageLayerWriter.java | 4 + ...redLayerSnapshotCapnProtoSchemaHolder.java | 95 +++++++++++-------- .../oracle/svm/hosted/meta/HostedMethod.java | 6 +- 20 files changed, 386 insertions(+), 98 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerDelayedMethodFeature.java 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 1a3ddd3e0a46..01e18127eda7 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 @@ -346,7 +346,7 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob @Override public AnalysisMethod forcedAddRootMethod(AnalysisMethod method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { - AnalysisError.guarantee(isBaseLayerAnalysisEnabled()); + AnalysisError.guarantee(isBaseLayerAnalysisEnabled() || hostVM.buildingImageLayer()); registerDefaultMethod(method, reason); PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(method); postTask(ignore -> { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 17c9b7be39d7..41bd89ee0372 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -284,6 +284,16 @@ public boolean hasNeverInlineDirective(ResolvedJavaMethod method) { return true; } + /** + * Check if the method has to be inlined. + * + * @param method the target method + */ + public boolean hasAlwaysInlineDirective(ResolvedJavaMethod method) { + /* No force inlining by the static analysis unless explicitly overwritten by the VM. */ + return false; + } + public InlineBeforeAnalysisGraphDecoder createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) { /* No inlining by the static analysis unless explicitly overwritten by the VM. */ return new InlineBeforeAnalysisGraphDecoder(bb, InlineBeforeAnalysisPolicy.NO_INLINING, resultGraph, bb.getProviders(method), null); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java index eb20ac2eb757..8d0f8dc4e250 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java @@ -278,6 +278,10 @@ protected void linkCallee(PointsToAnalysis bb, boolean isStatic, MethodFlowsGrap if (!calleeFlows.isStub()) { bb.analysisPolicy().registerAsImplementationInvoked(this, calleeFlows.getMethod()); } + + if (calleeFlows.getMethod().isDelayed()) { + saturateForOpenTypeWorld(bb); + } } /* @@ -426,4 +430,15 @@ public boolean canBeStaticallyBound() { public MultiMethodKey getCallerMultiMethodKey() { return callerMultiMethodKey; } + + /** + * Saturates the actual return of the invoke type flow to ensure that the type state represents + * all the types that could exist in the open world. + */ + public void saturateForOpenTypeWorld(PointsToAnalysis bb) { + if (actualReturn != null) { + actualReturn.enableFlow(bb); + actualReturn.onSaturated(bb); + } + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java index c83de0531504..b5527168241a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java @@ -490,10 +490,7 @@ void saturateForOpenTypeWorld(PointsToAnalysis bb) { */ for (InvokeTypeFlow invokeTypeFlow : getInvokes()) { if (!invokeTypeFlow.isDirectInvoke() && !bb.isClosed(invokeTypeFlow.getReceiverType())) { - if (invokeTypeFlow.actualReturn != null) { - invokeTypeFlow.actualReturn.enableFlow(bb); - invokeTypeFlow.actualReturn.onSaturated(bb); - } + invokeTypeFlow.saturateForOpenTypeWorld(bb); } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index eb169807dd57..43fef1215822 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -706,6 +706,11 @@ protected void apply(boolean forceReparse, Object reason) { method.setReachableInCurrentLayer(); + if (method.isDelayed()) { + /* The method will be analyzed in the application layer */ + return; + } + if (method.analyzedInPriorLayer()) { /* * We don't need to analyze this method. We already know its return type state from the diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index e89faa9103ed..2fe7543e0af7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -51,6 +51,7 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; +import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.ImageLayerLoader; import com.oracle.graal.pointsto.api.ImageLayerWriter; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; @@ -126,6 +127,7 @@ public record Signature(String name, AnalysisType[] parameterTypes) { public final ResolvedJavaMethod wrapped; private final int id; + private final boolean buildingSharedLayer; /** Marks a method loaded from a base layer. */ private final boolean isInBaseLayer; private final boolean analyzedInPriorLayer; @@ -196,9 +198,12 @@ public record Signature(String name, AnalysisType[] parameterTypes) { */ private boolean hasOpaqueReturn; + private CompilationBehavior compilationBehavior = CompilationBehavior.DEFAULT; + @SuppressWarnings({"this-escape", "unchecked"}) protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, MultiMethodKey multiMethodKey, Map multiMethodMap) { super(universe.hostVM.enableTrackAcrossLayers()); + HostVM hostVM = universe.hostVM(); this.wrapped = wrapped; declaringClass = universe.lookup(wrapped.getDeclaringClass()); @@ -213,13 +218,14 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, } else { signature = getUniverse().lookup(wrappedSignature, wrapped.getDeclaringClass()); } - hasNeverInlineDirective = universe.hostVM().hasNeverInlineDirective(wrapped); + hasNeverInlineDirective = hostVM.hasNeverInlineDirective(wrapped); name = createName(wrapped, multiMethodKey); qualifiedName = format("%H.%n(%P)"); modifiers = wrapped.getModifiers(); - if (universe.hostVM().buildingExtensionLayer() && declaringClass.isInBaseLayer()) { + buildingSharedLayer = hostVM.buildingSharedLayer(); + if (hostVM.buildingExtensionLayer() && declaringClass.isInBaseLayer()) { int mid = universe.getImageLayerLoader().lookupHostedMethodInBaseLayer(this); if (mid != -1) { /* @@ -236,7 +242,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, id = universe.computeNextMethodId(); isInBaseLayer = false; } - analyzedInPriorLayer = isInBaseLayer && universe.hostVM().analyzedInPriorLayer(this); + analyzedInPriorLayer = isInBaseLayer && hostVM.analyzedInPriorLayer(this); ExceptionHandler[] original = wrapped.getExceptionHandlers(); exceptionHandlers = new ExceptionHandler[original.length]; @@ -281,6 +287,7 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey) super(original.enableTrackAcrossLayers); wrapped = original.wrapped; id = original.id; + buildingSharedLayer = original.buildingSharedLayer; isInBaseLayer = original.isInBaseLayer; analyzedInPriorLayer = original.analyzedInPriorLayer; declaringClass = original.declaringClass; @@ -306,6 +313,35 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey) this.enableReachableInCurrentLayer = original.enableReachableInCurrentLayer; } + public void setCompilationBehavior(CompilationBehavior compilationBehavior) { + this.compilationBehavior = compilationBehavior; + } + + public CompilationBehavior getCompilationBehavior() { + return compilationBehavior; + } + + /** + * Delays this method to the application layer. This should not be called after the method was + * already parsed to avoid analyzing all the method's callees. + */ + public void setFullyDelayedToApplicationLayer() { + HostVM hostVM = getUniverse().getBigbang().getHostVM(); + AnalysisError.guarantee(hostVM.buildingImageLayer(), "Methods can only be delayed in layered images"); + AnalysisError.guarantee(parsedGraphCacheState.get() == GraphCacheEntry.UNPARSED, "The method %s was marked as delayed to the application layer but was already parsed", this); + AnalysisError.guarantee(!hostVM.hasAlwaysInlineDirective(this), "Method %s with an always inline directive cannot be delayed to the application layer as such methods cannot be inlined", this); + AnalysisError.guarantee(isConcrete(), "Method %s is not concrete and cannot be delayed to the application layer", this); + this.compilationBehavior = CompilationBehavior.FULLY_DELAYED_TO_APPLICATION_LAYER; + } + + /** + * Returns true if this method is marked as delayed to the application layer and the current + * layer is a shared layer. + */ + public boolean isDelayed() { + return compilationBehavior == CompilationBehavior.FULLY_DELAYED_TO_APPLICATION_LAYER && buildingSharedLayer; + } + private static String createName(ResolvedJavaMethod wrapped, MultiMethodKey multiMethodKey) { String aName = wrapped.getName(); if (multiMethodKey != ORIGINAL_METHOD) { @@ -847,7 +883,8 @@ public Type[] getGenericParameterTypes() { @Override public boolean canBeInlined() { - return !hasNeverInlineDirective(); + /* Delayed methods should not be inlined in the current layer */ + return !hasNeverInlineDirective() && !isDelayed(); } @Override @@ -1202,6 +1239,7 @@ private AnalysisParsedGraph setGraph(BigBang bb, Stage stage, GraphCacheEntry ex /* We lost the race, another thread is doing the parsing. */ return null; } + AnalysisError.guarantee(!isDelayed(), "The method %s was parsed even though it was marked as delayed to the application layer", this); GraphCacheEntry newEntry = graphSupplier.get(bb, this, expectedValue); @@ -1360,4 +1398,40 @@ public boolean hasOpaqueReturn() { } protected abstract AnalysisMethod createMultiMethod(AnalysisMethod analysisMethod, MultiMethodKey newMultiMethodKey); + + /** + * This state represents how a method should be compiled in layered images. The state of a + * method can only be decided in the first layer if it is marked as tracked across layers. The + * state has to stay the same across all the extension layers. If not specified, the state of a + * method will be {@link CompilationBehavior#DEFAULT}. + */ + public enum CompilationBehavior { + + /** + * Method remains unanalyzed until the application layer and any inlining in a shared layer + * is prevented. A call to the method in a shared layer will be replaced by an indirect + * call. The compilation of those methods is then forced in the application layer and the + * corresponding symbol is declared as global. + * + * A delayed method that is not referenced in any shared layer is treated as a + * {@link CompilationBehavior#DEFAULT} method in the application layer and does not have to + * be compiled. If it is only referenced in the application layer, it might be inlined and + * not compiled at all. + */ + FULLY_DELAYED_TO_APPLICATION_LAYER, + + /** + * Method can be inlined into other methods, both before analysis and during compilation, + * and will be compiled as a distinct compilation unit as stipulated by the normal native + * image generation process (i.e., the method is installed as a root and/or a reference to + * the method exists via a call and/or an explicit MethodReference). + */ + DEFAULT, + + /** + * Method is pinned to a specific shared layer, meaning it has to be analyzed and compiled + * in this specific layer. A method can only be pinned to a shared layer. + */ + PINNED_TO_SHARED_LAYER, + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index eaeb35757679..222fdb1cb6e9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -40,6 +40,7 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; +import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; @@ -193,6 +194,8 @@ public boolean equals(Object obj) { /** Used to avoid aggressive optimizations for open type world analysis. */ protected final boolean isClosedTypeWorld; + protected final boolean buildingSharedLayer; + public StrengthenGraphs(BigBang bb, Universe converter) { this.bb = bb; this.converter = converter; @@ -208,7 +211,9 @@ public StrengthenGraphs(BigBang bb, Universe converter) { beforeCounters = null; afterCounters = null; } - this.isClosedTypeWorld = converter.hostVM().isClosedTypeWorld(); + HostVM hostVM = converter.hostVM(); + this.isClosedTypeWorld = hostVM.isClosedTypeWorld(); + this.buildingSharedLayer = hostVM.buildingSharedLayer(); } private static void reportNeverNullInstanceFields(BigBang bb) { diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index 5cafa4a3b7dc..27543c2b58fc 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -687,15 +687,22 @@ protected Value emitIndirectForeignCallAddress(ForeignCallLinkage linkage) { SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage; SharedMethod targetMethod = (SharedMethod) callTarget.getMethod(); if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) { - /* - * Load the address for the start of the text section and then add in the offset for - * this specific method. - */ - var methodLocation = DynamicImageLayerInfo.singleton().getPriorLayerMethodLocation(targetMethod); - AllocatableValue basePointerAddress = newVariable(getLIRKindTool().getWordKind()); - append(new AMD64CGlobalDataLoadAddressOp(methodLocation.base(), basePointerAddress)); - Value codeOffsetInSection = emitConstant(getLIRKindTool().getWordKind(), JavaConstant.forLong(methodLocation.offset())); - return getArithmetic().emitAdd(basePointerAddress, codeOffsetInSection, false); + DynamicImageLayerInfo dynamicImageLayerInfo = DynamicImageLayerInfo.singleton(); + if (dynamicImageLayerInfo.isMethodCompilationDelayed(targetMethod)) { + AllocatableValue methodAddress = newVariable(getLIRKindTool().getWordKind()); + append(new AMD64CGlobalDataLoadAddressOp(dynamicImageLayerInfo.getSymbolForDelayedMethod(targetMethod), methodAddress)); + return methodAddress; + } else { + /* + * Load the address for the start of the text section and then add in the offset + * for this specific method. + */ + var methodLocation = dynamicImageLayerInfo.getPriorLayerMethodLocation(targetMethod); + AllocatableValue basePointerAddress = newVariable(getLIRKindTool().getWordKind()); + append(new AMD64CGlobalDataLoadAddressOp(methodLocation.base(), basePointerAddress)); + Value codeOffsetInSection = emitConstant(getLIRKindTool().getWordKind(), JavaConstant.forLong(methodLocation.offset())); + return getArithmetic().emitAdd(basePointerAddress, codeOffsetInSection, false); + } } if (!shouldEmitOnlyIndirectCalls()) { return null; @@ -1497,13 +1504,18 @@ private static JavaConstant getZeroConstant(AllocatableValue dst) { public AMD64LIRInstruction createLoadMethodPointerConstant(AllocatableValue dst, SubstrateMethodPointerConstant constant) { if (ImageLayerBuildingSupport.buildingExtensionLayer()) { if (constant.pointer().getMethod() instanceof SharedMethod sharedMethod && sharedMethod.forceIndirectCall()) { - /* - * AMD64LoadMethodPointerConstantOp retrieves the address via a PC-relative - * load. This is not possible to do in extension layers when referring to - * methods defined in prior layers. - */ - var methodLocation = DynamicImageLayerInfo.singleton().getPriorLayerMethodLocation(sharedMethod); - return new AMD64CGlobalDataLoadAddressOp(methodLocation.base(), dst, methodLocation.offset()); + DynamicImageLayerInfo dynamicImageLayerInfo = DynamicImageLayerInfo.singleton(); + if (dynamicImageLayerInfo.isMethodCompilationDelayed(sharedMethod)) { + return new AMD64CGlobalDataLoadAddressOp(dynamicImageLayerInfo.getSymbolForDelayedMethod(sharedMethod), dst); + } else { + /* + * AMD64LoadMethodPointerConstantOp retrieves the address via a PC-relative + * load. This is not possible to do in extension layers when referring to + * methods defined in prior layers. + */ + var methodLocation = dynamicImageLayerInfo.getPriorLayerMethodLocation(sharedMethod); + return new AMD64CGlobalDataLoadAddressOp(methodLocation.base(), dst, methodLocation.offset()); + } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index 3bdb830c6f47..7860b856c2ee 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -402,11 +402,17 @@ public void lower(FixedNode node, LoweringTool tool) { * address offset of the text section start and then add in the offset for * this specific method. */ - var methodLocation = DynamicImageLayerInfo.singleton().getPriorLayerMethodLocation(targetMethod); - AddressNode methodPointerAddress = graph.addOrUniqueWithInputs( - new OffsetAddressNode(new CGlobalDataLoadAddressNode(methodLocation.base()), - ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), methodLocation.offset()))); - loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, methodPointerAddress); + DynamicImageLayerInfo dynamicImageLayerInfo = DynamicImageLayerInfo.singleton(); + if (dynamicImageLayerInfo.isMethodCompilationDelayed(targetMethod)) { + loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, + graph.addOrUniqueWithInputs(new CGlobalDataLoadAddressNode(dynamicImageLayerInfo.getSymbolForDelayedMethod(targetMethod)))); + } else { + var methodLocation = dynamicImageLayerInfo.getPriorLayerMethodLocation(targetMethod); + AddressNode methodPointerAddress = graph.addOrUniqueWithInputs( + new OffsetAddressNode(new CGlobalDataLoadAddressNode(methodLocation.base()), + ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), methodLocation.offset()))); + loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, methodPointerAddress); + } } else if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) { loweredCallTarget = createDirectCall(graph, callTarget, parameters, signature, callType, invokeKind, targetMethod, node); } else if (!targetMethod.hasImageCodeOffset()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java index a77872e8554d..2116735e9e76 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java @@ -50,6 +50,10 @@ public static DynamicImageLayerInfo singleton() { return ImageSingletons.lookup(DynamicImageLayerInfo.class); } + public abstract boolean isMethodCompilationDelayed(SharedMethod method); + + public abstract CGlobalDataInfo getSymbolForDelayedMethod(SharedMethod targetMethod); + public record PriorLayerMethodLocation(CGlobalDataInfo base, int offset) { } diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index 50bec81d1590..732672d00ab8 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -106,32 +106,33 @@ struct PersistedAnalysisMethod { analysisGraphIsIntrinsic @25 :Bool; strengthenedGraphLocation @26 :Text; hostedMethodIndex @27 :HostedMethodIndex; + compilationBehaviorOrdinal @28 :Int8; wrappedMethod :union { - none @28 :Void; # default + none @29 :Void; # default factoryMethod :group { - targetConstructorId @29 :MethodId; - throwAllocatedObject @30 :Bool; - instantiatedTypeId @31 :TypeId; + targetConstructorId @30 :MethodId; + throwAllocatedObject @31 :Bool; + instantiatedTypeId @32 :TypeId; } outlinedSB :group { - methodTypeReturn @32 :Text; - methodTypeParameters @33 :List(Text); + methodTypeReturn @33 :Text; + methodTypeParameters @34 :List(Text); } cEntryPointCallStub :group { - originalMethodId @34 :MethodId; - notPublished @35 :Bool; + originalMethodId @35 :MethodId; + notPublished @36 :Bool; } wrappedMember :group { union { - reflectionExpandSignature @36 :Void; - javaCallVariantWrapper @37 :Void; + reflectionExpandSignature @37 :Void; + javaCallVariantWrapper @38 :Void; } - name @38 :Text; - declaringClassName @39 :Text; - argumentTypeNames @40 :List(Text); + name @39 :Text; + declaringClassName @40 :Text; + argumentTypeNames @41 :List(Text); } polymorphicSignature :group { - callers @41 :List(MethodId); + callers @42 :List(MethodId); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 8f2438214805..1963813ef687 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -74,6 +74,7 @@ import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.common.meta.GuaranteeFolded; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.MissingRegistrationSupport; import com.oracle.svm.core.NeverInline; @@ -163,6 +164,7 @@ import jdk.internal.loader.NativeLibraries; import jdk.internal.reflect.Reflection; import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MetaAccessProvider; @@ -856,6 +858,11 @@ public boolean hasNeverInlineDirective(ResolvedJavaMethod method) { .anyMatch(filter -> filter.matches(method)); } + @Override + public boolean hasAlwaysInlineDirective(ResolvedJavaMethod method) { + return AnnotationAccess.isAnnotationPresent(method, AlwaysInline.class) || AnnotationAccess.isAnnotationPresent(method, ForceInline.class); + } + private InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiMethodKey multiMethodKey) { if (parsingSupport != null) { return parsingSupport.inlineBeforeAnalysisPolicy(multiMethodKey, inlineBeforeAnalysisPolicy); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 11258b71e808..4a6fbd8c9cbc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -860,10 +860,10 @@ private void doInlineTrivial(DebugContext debug, HostedMethod method) { private boolean makeInlineDecision(HostedMethod method, HostedMethod callee) { if (!SubstrateOptions.UseSharedLayerStrengthenedGraphs.getValue() && callee.compilationInfo.getCompilationGraph() == null) { /* - * We have compiled this method in a prior layer, but don't have the graph available - * here. + * We have compiled this method in a prior layer or this method's compilation is delayed + * to the application layer, but don't have the graph available here. */ - assert callee.isCompiledInPriorLayer() : method; + assert callee.isCompiledInPriorLayer() || callee.wrapped.isDelayed() : method; return false; } if (universe.hostVM().neverInlineTrivial(method.getWrapped(), callee.getWrapped())) { @@ -1205,9 +1205,10 @@ private static void handleSpecialization(final HostedMethod method, CallTargetNo } protected void ensureCompiled(HostedMethod method, CompileReason reason) { - if (method.isCompiledInPriorLayer()) { + if (method.isCompiledInPriorLayer() || method.wrapped.isDelayed()) { /* - * Since this method was compiled in a prior layer we should not compile it again. + * Since this method was compiled in a prior layer or its compilation is delayed to the + * application layer we should not compile it. */ return; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 4eda442b68c8..ecfec31e4c5a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -556,6 +556,9 @@ public void build(String imageName, DebugContext debug) { if (ImageLayerBuildingSupport.buildingImageLayer()) { LayeredDispatchTableFeature.singleton().defineDispatchTableSlotSymbols(objectFile, textSection, codeCache, metaAccess); } + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + HostedDynamicLayerInfo.singleton().checkMissingDelayedMethods(); + } /* * Mark locations that depend on the memory address of code (text), data, or the heap at @@ -1026,11 +1029,16 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f final Map methodsBySignature = new HashMap<>(); // 1. fq with return type + boolean buildingSharedLayer = ImageLayerBuildingSupport.buildingSharedLayer(); + boolean buildingApplicationLayer = ImageLayerBuildingSupport.buildingApplicationLayer(); + HostedDynamicLayerInfo hostedDynamicLayerInfo = buildingApplicationLayer ? HostedDynamicLayerInfo.singleton() : null; + for (Pair pair : codeCache.getOrderedCompilations()) { HostedMethod current = pair.getLeft(); final String symName = localSymbolNameForMethod(current); final String signatureString = current.getUniqueShortName(); - defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, ImageLayerBuildingSupport.buildingSharedLayer(), pair.getRight()); + boolean global = buildingSharedLayer || (buildingApplicationLayer && hostedDynamicLayerInfo.forceGlobalMethodSymbol(symName)); + defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, global, pair.getRight()); watchdog.recordActivity(); } // 2. fq without return type -- only for entry points! diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java index 3230729d69e2..ac365f6c99a8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.PointerBase; @@ -44,6 +45,7 @@ import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate; import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; @@ -52,6 +54,7 @@ import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.image.NativeImage; import com.oracle.svm.hosted.meta.HostedMethod; @@ -63,20 +66,52 @@ public class HostedDynamicLayerInfo extends DynamicImageLayerInfo implements Lay private final Set priorLayerMethodSymbols = new HashSet<>(); private final List libNames; private final Map priorInstalledOffsetCache = ImageLayerBuildingSupport.buildingExtensionLayer() ? new ConcurrentHashMap<>() : null; + /** + * The symbols of methods that are fully delayed to the application layer and are invoked in a + * shared layer. All those symbols need to be linked in the application layer to avoid any + * undefined reference, so the corresponding methods will be registered as root in the + * application layer. A single {@link CGlobalData} has to be created for each symbol, so it is + * cached in a map. + */ + private final Map> delayedMethodSymbols = ImageLayerBuildingSupport.buildingSharedLayer() ? new ConcurrentHashMap<>() : null; + /** + * The id of the methods corresponding to the symbols of + * {@link HostedDynamicLayerInfo#delayedMethodSymbols}. + */ + private final Set delayedMethodIds = ImageLayerBuildingSupport.buildingSharedLayer() ? ConcurrentHashMap.newKeySet() : null; + /** + * The symbols of methods delayed to the application layer from previous shared layers. + */ + private final Set previousLayerDelayedMethodSymbols; + /** + * The ids of methods delayed to the application layer from previous shared layers. + */ + private final Set previousLayerDelayedMethodIds; + /** + * The symbols of delayed methods that are properly compiled in the application layer. + */ + private final Set compiledDelayedMethodSymbols = ImageLayerBuildingSupport.buildingApplicationLayer() ? ConcurrentHashMap.newKeySet() : null; HostedDynamicLayerInfo() { - this(0, null, new ArrayList<>()); + this(0, null, new ArrayList<>(), Set.of(), Set.of()); } public static HostedDynamicLayerInfo singleton() { return (HostedDynamicLayerInfo) ImageSingletons.lookup(DynamicImageLayerInfo.class); } - private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, - List libNames) { + private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, List libNames, + Set previousLayerDelayedMethodSymbols, Set previousLayerDelayedMethodIds) { super(layerNumber); this.libNames = new ArrayList<>(libNames); this.cGlobalData = codeSectionStartSymbol == null ? null : CGlobalDataFactory.forSymbol(codeSectionStartSymbol); + this.previousLayerDelayedMethodSymbols = previousLayerDelayedMethodSymbols; + this.previousLayerDelayedMethodIds = previousLayerDelayedMethodIds; + } + + @Override + public boolean isMethodCompilationDelayed(SharedMethod sMethod) { + return ((HostedMethod) sMethod).wrapped.isDelayed(); } @Override @@ -141,6 +176,26 @@ public void registerHostedMethod(HostedMethod hMethod) { } } + @Override + public CGlobalDataInfo getSymbolForDelayedMethod(SharedMethod targetMethod) { + String symbolName = localSymbolNameForMethod(targetMethod); + var symbol = delayedMethodSymbols.computeIfAbsent(symbolName, key -> CGlobalDataFactory.forSymbol(symbolName)); + delayedMethodIds.add(((HostedMethod) targetMethod).wrapped.getId()); + return CGlobalDataFeature.singleton().registerAsAccessedOrGet(symbol); + } + + public boolean forceGlobalMethodSymbol(String symbol) { + boolean isDelayedInPreviousLayer = previousLayerDelayedMethodSymbols.contains(symbol); + if (isDelayedInPreviousLayer) { + compiledDelayedMethodSymbols.add(symbol); + } + return isDelayedInPreviousLayer; + } + + public void checkMissingDelayedMethods() { + VMError.guarantee(compiledDelayedMethodSymbols.equals(previousLayerDelayedMethodSymbols), "All delayed method symbols should be assigned to a compilation unit in the application layer"); + } + public void defineSymbolsForPriorLayerMethods(ObjectFile objectFile) { assert BuildPhaseProvider.isHeapLayoutFinished(); /* @@ -160,6 +215,10 @@ public boolean isImageLayerLib(String lib) { return libNames.contains(lib); } + public Set getPreviousLayerDelayedMethodIds() { + return previousLayerDelayedMethodIds; + } + @Override public EnumSet getImageBuilderFlags() { return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; @@ -186,6 +245,14 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { writer.writeStringList("libNames", libNames); + Set nextLayerDelayedMethodSymbols = new HashSet<>(previousLayerDelayedMethodSymbols); + nextLayerDelayedMethodSymbols.addAll(delayedMethodSymbols.keySet()); + writer.writeStringList("delayedMethodSymbols", nextLayerDelayedMethodSymbols.stream().toList()); + + Set nextLayerDelayedMethodIds = new HashSet<>(previousLayerDelayedMethodIds); + nextLayerDelayedMethodIds.addAll(delayedMethodIds); + writer.writeIntList("delayedMethodIds", nextLayerDelayedMethodIds.stream().toList()); + return PersistFlags.CREATE; } @@ -199,6 +266,9 @@ public static Object createFromLoader(ImageSingletonLoader loader) { var libNames = loader.readStringList("libNames"); - return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, libNames); + var previousLayerDelayedMethodSymbols = loader.readStringList("delayedMethodSymbols").stream().collect(Collectors.toUnmodifiableSet()); + var previousLayerDelayedMethodIds = loader.readIntList("delayedMethodIds").stream().collect(Collectors.toUnmodifiableSet()); + + return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, libNames, previousLayerDelayedMethodSymbols, previousLayerDelayedMethodIds); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerDelayedMethodFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerDelayedMethodFeature.java new file mode 100644 index 000000000000..cd6c59628a91 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerDelayedMethodFeature.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.imagelayer; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.hosted.FeatureImpl; + +@AutomaticallyRegisteredFeature +public class LayerDelayedMethodFeature implements InternalFeature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return ImageLayerBuildingSupport.buildingApplicationLayer(); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess a) { + SVMImageLayerLoader loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; + BigBang bigbang = access.getUniverse().getBigbang(); + for (int methodId : HostedDynamicLayerInfo.singleton().getPreviousLayerDelayedMethodIds()) { + AnalysisMethod method = loader.getAnalysisMethodForBaseLayerId(methodId); + bigbang.forcedAddRootMethod(method, method.isConstructor(), "Fully delayed to application layer"); + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java index c9db1f9ca390..2dd11226e561 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java @@ -1010,6 +1010,9 @@ public void addBaseLayerMethod(AnalysisMethod analysisMethod) { registerFlag(md.getIsInvoked(), debug -> analysisMethod.registerAsInvoked(PERSISTED)); registerFlag(md.getIsImplementationInvoked(), debug -> analysisMethod.registerAsImplementationInvoked(PERSISTED)); registerFlag(md.getIsIntrinsicMethod(), debug -> analysisMethod.registerAsIntrinsicMethod(PERSISTED)); + + AnalysisMethod.CompilationBehavior compilationBehavior = AnalysisMethod.CompilationBehavior.values()[md.getCompilationBehaviorOrdinal()]; + analysisMethod.setCompilationBehavior(compilationBehavior); } private PersistedAnalysisMethod.Reader getMethodData(AnalysisMethod analysisMethod) { 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 0a281b3a35ef..e181c611161b 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 @@ -618,11 +618,15 @@ private void persistMethod(AnalysisMethod method, Supplier { public Factory() { } @@ -1278,14 +1278,21 @@ public final void setHostedMethodIndex(int value) { _setIntField(6, value); } + public final byte getCompilationBehaviorOrdinal() { + return _getByteField(22); + } + public final void setCompilationBehaviorOrdinal(byte value) { + _setByteField(22, value); + } + public final WrappedMethod.Builder getWrappedMethod() { return new PersistedAnalysisMethod.WrappedMethod.Builder(segment, data, pointers, dataSize, pointerCount); } public final WrappedMethod.Builder initWrappedMethod() { - _setBooleanField(172,false); - _setShortField(11,(short)0); - _setIntField(7,0); + _setShortField(14,(short)0); _setIntField(8,0); + _setBooleanField(288,false); + _setIntField(10,0); _clearPointerField(10); _clearPointerField(11); _clearPointerField(12); @@ -1441,6 +1448,10 @@ public final int getHostedMethodIndex() { return _getIntField(6); } + public final byte getCompilationBehaviorOrdinal() { + return _getByteField(22); + } + public WrappedMethod.Reader getWrappedMethod() { return new PersistedAnalysisMethod.WrappedMethod.Reader(segment, data, pointers, dataSize, pointerCount, nestingLimit); } @@ -1448,7 +1459,7 @@ public WrappedMethod.Reader getWrappedMethod() { } public static class WrappedMethod { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } @@ -1473,7 +1484,7 @@ public static final class Builder extends com.oracle.svm.shaded.org.capnproto.St super(segment, data, pointers, dataSize, pointerCount); } public Which which() { - switch(_getShortField(11)) { + switch(_getShortField(14)) { case 0 : return Which.NONE; case 1 : return Which.FACTORY_METHOD; case 2 : return Which.OUTLINED_S_B; @@ -1495,7 +1506,7 @@ assert which() == PersistedAnalysisMethod.WrappedMethod.Which.NONE: return com.oracle.svm.shaded.org.capnproto.Void.VOID; } public final void setNone(com.oracle.svm.shaded.org.capnproto.Void value) { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.NONE.ordinal()); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.NONE.ordinal()); } public final boolean isFactoryMethod() { @@ -1505,10 +1516,10 @@ public final FactoryMethod.Builder getFactoryMethod() { return new PersistedAnalysisMethod.WrappedMethod.FactoryMethod.Builder(segment, data, pointers, dataSize, pointerCount); } public final FactoryMethod.Builder initFactoryMethod() { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.FACTORY_METHOD.ordinal()); - _setBooleanField(172,false); - _setIntField(7,0); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.FACTORY_METHOD.ordinal()); _setIntField(8,0); + _setBooleanField(288,false); + _setIntField(10,0); return new PersistedAnalysisMethod.WrappedMethod.FactoryMethod.Builder(segment, data, pointers, dataSize, pointerCount); } @@ -1519,7 +1530,7 @@ public final OutlinedSB.Builder getOutlinedSB() { return new PersistedAnalysisMethod.WrappedMethod.OutlinedSB.Builder(segment, data, pointers, dataSize, pointerCount); } public final OutlinedSB.Builder initOutlinedSB() { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.OUTLINED_S_B.ordinal()); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.OUTLINED_S_B.ordinal()); _clearPointerField(10); _clearPointerField(11); return new PersistedAnalysisMethod.WrappedMethod.OutlinedSB.Builder(segment, data, pointers, dataSize, pointerCount); @@ -1532,9 +1543,9 @@ public final CEntryPointCallStub.Builder getCEntryPointCallStub() { return new PersistedAnalysisMethod.WrappedMethod.CEntryPointCallStub.Builder(segment, data, pointers, dataSize, pointerCount); } public final CEntryPointCallStub.Builder initCEntryPointCallStub() { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.C_ENTRY_POINT_CALL_STUB.ordinal()); - _setBooleanField(172,false); - _setIntField(7,0); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.C_ENTRY_POINT_CALL_STUB.ordinal()); + _setBooleanField(256,false); + _setIntField(10,0); return new PersistedAnalysisMethod.WrappedMethod.CEntryPointCallStub.Builder(segment, data, pointers, dataSize, pointerCount); } @@ -1545,8 +1556,8 @@ public final WrappedMember.Builder getWrappedMember() { return new PersistedAnalysisMethod.WrappedMethod.WrappedMember.Builder(segment, data, pointers, dataSize, pointerCount); } public final WrappedMember.Builder initWrappedMember() { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.WRAPPED_MEMBER.ordinal()); - _setShortField(14,(short)0); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.WRAPPED_MEMBER.ordinal()); + _setShortField(20,(short)0); _clearPointerField(10); _clearPointerField(11); _clearPointerField(12); @@ -1560,7 +1571,7 @@ public final PolymorphicSignature.Builder getPolymorphicSignature() { return new PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.Builder(segment, data, pointers, dataSize, pointerCount); } public final PolymorphicSignature.Builder initPolymorphicSignature() { - _setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.POLYMORPHIC_SIGNATURE.ordinal()); + _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.Which.POLYMORPHIC_SIGNATURE.ordinal()); _clearPointerField(10); return new PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.Builder(segment, data, pointers, dataSize, pointerCount); } @@ -1573,7 +1584,7 @@ public static final class Reader extends com.oracle.svm.shaded.org.capnproto.Str } public Which which() { - switch(_getShortField(11)) { + switch(_getShortField(14)) { case 0 : return Which.NONE; case 1 : return Which.FACTORY_METHOD; case 2 : return Which.OUTLINED_S_B; @@ -1639,7 +1650,7 @@ public enum Which { _NOT_IN_SCHEMA, } public static class FactoryMethod { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } @@ -1667,24 +1678,24 @@ public final Reader asReader() { return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); } public final int getTargetConstructorId() { - return _getIntField(7); + return _getIntField(8); } public final void setTargetConstructorId(int value) { - _setIntField(7, value); + _setIntField(8, value); } public final boolean getThrowAllocatedObject() { - return _getBooleanField(172); + return _getBooleanField(288); } public final void setThrowAllocatedObject(boolean value) { - _setBooleanField(172, value); + _setBooleanField(288, value); } public final int getInstantiatedTypeId() { - return _getIntField(8); + return _getIntField(10); } public final void setInstantiatedTypeId(int value) { - _setIntField(8, value); + _setIntField(10, value); } } @@ -1695,15 +1706,15 @@ public static final class Reader extends com.oracle.svm.shaded.org.capnproto.Str } public final int getTargetConstructorId() { - return _getIntField(7); + return _getIntField(8); } public final boolean getThrowAllocatedObject() { - return _getBooleanField(172); + return _getBooleanField(288); } public final int getInstantiatedTypeId() { - return _getIntField(8); + return _getIntField(10); } } @@ -1712,7 +1723,7 @@ public final int getInstantiatedTypeId() { public static class OutlinedSB { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } @@ -1793,7 +1804,7 @@ public final com.oracle.svm.shaded.org.capnproto.TextList.Reader getMethodTypePa public static class CEntryPointCallStub { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } @@ -1821,17 +1832,17 @@ public final Reader asReader() { return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); } public final int getOriginalMethodId() { - return _getIntField(7); + return _getIntField(10); } public final void setOriginalMethodId(int value) { - _setIntField(7, value); + _setIntField(10, value); } public final boolean getNotPublished() { - return _getBooleanField(172); + return _getBooleanField(256); } public final void setNotPublished(boolean value) { - _setBooleanField(172, value); + _setBooleanField(256, value); } } @@ -1842,11 +1853,11 @@ public static final class Reader extends com.oracle.svm.shaded.org.capnproto.Str } public final int getOriginalMethodId() { - return _getIntField(7); + return _getIntField(10); } public final boolean getNotPublished() { - return _getBooleanField(172); + return _getBooleanField(256); } } @@ -1855,7 +1866,7 @@ public final boolean getNotPublished() { public static class WrappedMember { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } @@ -1880,7 +1891,7 @@ public static final class Builder extends com.oracle.svm.shaded.org.capnproto.St super(segment, data, pointers, dataSize, pointerCount); } public Which which() { - switch(_getShortField(14)) { + switch(_getShortField(20)) { case 0 : return Which.REFLECTION_EXPAND_SIGNATURE; case 1 : return Which.JAVA_CALL_VARIANT_WRAPPER; default: return Which._NOT_IN_SCHEMA; @@ -1898,7 +1909,7 @@ assert which() == PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.REFL return com.oracle.svm.shaded.org.capnproto.Void.VOID; } public final void setReflectionExpandSignature(com.oracle.svm.shaded.org.capnproto.Void value) { - _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.REFLECTION_EXPAND_SIGNATURE.ordinal()); + _setShortField(20, (short)PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.REFLECTION_EXPAND_SIGNATURE.ordinal()); } public final boolean isJavaCallVariantWrapper() { @@ -1910,7 +1921,7 @@ assert which() == PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.JAVA return com.oracle.svm.shaded.org.capnproto.Void.VOID; } public final void setJavaCallVariantWrapper(com.oracle.svm.shaded.org.capnproto.Void value) { - _setShortField(14, (short)PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.JAVA_CALL_VARIANT_WRAPPER.ordinal()); + _setShortField(20, (short)PersistedAnalysisMethod.WrappedMethod.WrappedMember.Which.JAVA_CALL_VARIANT_WRAPPER.ordinal()); } public final boolean hasName() { @@ -1963,7 +1974,7 @@ public static final class Reader extends com.oracle.svm.shaded.org.capnproto.Str } public Which which() { - switch(_getShortField(14)) { + switch(_getShortField(20)) { case 0 : return Which.REFLECTION_EXPAND_SIGNATURE; case 1 : return Which.JAVA_CALL_VARIANT_WRAPPER; default: return Which._NOT_IN_SCHEMA; @@ -2019,7 +2030,7 @@ public enum Which { public static class PolymorphicSignature { - public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)5,(short)13); + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)6,(short)13); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { public Factory() { } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 5e0a4c3f3535..7fcd8e15d8b6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -309,7 +309,11 @@ public ImageCodeInfo getImageCodeInfo() { @Override public boolean forceIndirectCall() { - return isCompiledInPriorLayer(); + /* + * Methods delayed to the application layer need to be called indirectly as they are not + * available in the current layer. + */ + return isCompiledInPriorLayer() || wrapped.isDelayed(); } @Override