From 9ffab4f1b8dec996ca059722d36f8fbfda78a897 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 28 Oct 2024 17:28:18 +0100 Subject: [PATCH 1/2] Early load the strengthened graphs to allow inlining after compilation in the application layer --- .../pointsto/standalone/PointsToAnalyzer.java | 4 +- .../pointsto/AbstractAnalysisEngine.java | 3 - .../com/oracle/graal/pointsto/api/HostVM.java | 4 + .../pointsto/flow/MethodTypeFlowBuilder.java | 2 + .../graal/pointsto/heap/ImageLayerLoader.java | 77 +++++++++++++-- .../pointsto/heap/ImageLayerSnapshotUtil.java | 19 +++- .../graal/pointsto/heap/ImageLayerWriter.java | 8 +- .../graal/pointsto/meta/AnalysisMethod.java | 25 +++++ .../pointsto/results/StrengthenGraphs.java | 30 ++++-- .../com/oracle/svm/core/SubstrateOptions.java | 19 +++- .../src/com/oracle/svm/hosted/SVMHost.java | 7 ++ .../oracle/svm/hosted/code/CompileQueue.java | 44 +++++++-- .../heap/SVMImageLayerSnapshotUtil.java | 99 +++++++++++++++---- .../svm/hosted/heap/SVMImageLayerWriter.java | 4 +- .../hosted/image/LIRNativeImageCodeCache.java | 2 +- .../HostedImageLayerBuildingSupport.java | 3 +- 16 files changed, 292 insertions(+), 58 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index 18de8ba7cebc..ffe6248157bf 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -163,7 +163,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); HostedValuesProvider hostedValuesProvider = new HostedValuesProvider(aMetaAccess, aUniverse); - ImageLayerSnapshotUtil imageLayerSnapshotUtil = new ImageLayerSnapshotUtil(); + ImageLayerSnapshotUtil imageLayerSnapshotUtil = new ImageLayerSnapshotUtil(false); ImageLayerLoader imageLayerLoader = new ImageLayerLoader(); imageLayerLoader.setImageLayerSnapshotUtil(imageLayerSnapshotUtil); imageLayerLoader.setUniverse(aUniverse); @@ -172,7 +172,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { snippetReflection, aConstantReflection, new AnalysisObjectScanningObserver(bigbang), analysisClassLoader, hostedValuesProvider); aUniverse.setHeapScanner(heapScanner); imageLayerLoader.executeHeapScannerTasks(); - ImageLayerWriter imageLayerWriter = new ImageLayerWriter(true); + ImageLayerWriter imageLayerWriter = new ImageLayerWriter(true, true); imageLayerWriter.setImageLayerSnapshotUtil(imageLayerSnapshotUtil); imageLayerWriter.setImageHeap(heap); HeapSnapshotVerifier heapVerifier = new StandaloneHeapSnapshotVerifier(bigbang, heap, heapScanner); 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 93ca08f7f329..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 @@ -232,9 +232,6 @@ public void cleanupAfterAnalysis() { universe.getHeapScanner().cleanupAfterAnalysis(); universe.getHeapVerifier().cleanupAfterAnalysis(); - if (universe.getImageLayerLoader() != null) { - universe.getImageLayerLoader().cleanupAfterAnalysis(); - } } @Override 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 52089bb43432..ae7691b1cc77 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 @@ -343,6 +343,10 @@ public boolean enableTrackAcrossLayers() { return false; } + public boolean enableReachableInCurrentLayer() { + return false; + } + /** * Helpers to determine what analysis actions should be taken for a given Multi-Method version. */ 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 c056127c1d59..161001f3aa9b 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 @@ -698,6 +698,8 @@ protected void apply(boolean forceReparse, Object reason) { assert !processed : "can only call apply once per MethodTypeFlowBuilder"; processed = true; + method.setReachableInCurrentLayer(); + 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/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 4bd399b9b07c..2155922c9719 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 @@ -91,6 +91,7 @@ import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.util.ObjectCopier; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @@ -179,7 +180,7 @@ public void loadLayerAnalysis() { loadLayerAnalysis0(); } - public void cleanupAfterAnalysis() { + public void cleanupAfterCompilation() { if (graphsChannel != null) { try { graphsChannel.close(); @@ -594,21 +595,18 @@ public void initializeBaseLayerMethod(AnalysisMethod analysisMethod) { * {@link ImageLayerWriter#persistAnalysisParsedGraph} for implementation. */ public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) { - return getMethodData(analysisMethod).hasAnalysisGraphLocation(); + return hasGraph(analysisMethod, PersistedAnalysisMethod.Reader::hasAnalysisGraphLocation); } public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) { PersistedAnalysisMethod.Reader methodData = getMethodData(analysisMethod); boolean intrinsic = methodData.getAnalysisGraphIsIntrinsic(); EncodedGraph analyzedGraph = getEncodedGraph(analysisMethod, methodData.getAnalysisGraphLocation()); - if (hasStrengthenedGraph(analysisMethod)) { - throw AnalysisError.shouldNotReachHere("Strengthened graphs are not supported until late loading is implemented."); - } return new AnalysisParsedGraph(analyzedGraph, intrinsic); } public boolean hasStrengthenedGraph(AnalysisMethod analysisMethod) { - return getMethodData(analysisMethod).hasStrengthenedGraphLocation(); + return hasGraph(analysisMethod, PersistedAnalysisMethod.Reader::hasStrengthenedGraphLocation); } public EncodedGraph getStrengthenedGraph(AnalysisMethod analysisMethod) { @@ -616,6 +614,14 @@ public EncodedGraph getStrengthenedGraph(AnalysisMethod analysisMethod) { return getEncodedGraph(analysisMethod, methodData.getStrengthenedGraphLocation()); } + private boolean hasGraph(AnalysisMethod analysisMethod, Function hasGraphFunction) { + var methodData = getMethodData(analysisMethod); + if (methodData == null) { + return false; + } + return hasGraphFunction.apply(methodData); + } + protected EncodedGraph getEncodedGraph(AnalysisMethod analysisMethod, Text.Reader location) { byte[] encodedAnalyzedGraph = readEncodedGraph(location.toString()); return (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); @@ -643,6 +649,65 @@ private byte[] readEncodedGraph(String location) { return bb.array(); } + /** + * This method is needed to ensure all the base layer analysis elements from the strengthened + * graph are created early enough and seen by the analysis. This is done by decoding the graph + * using a decoder that loads analysis elements instead of hosted elements. + */ + public void loadPriorStrengthenedGraphAnalysisElements(AnalysisMethod analysisMethod) { + if (hasStrengthenedGraph(analysisMethod)) { + PersistedAnalysisMethod.Reader methodData = getMethodData(analysisMethod); + byte[] encodedAnalyzedGraph = readEncodedGraph(methodData.getStrengthenedGraphLocation().toString()); + EncodedGraph graph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphAnalysisElementsDecoder(this, analysisMethod, universe.getSnippetReflection()), + encodedAnalyzedGraph); + for (Object o : graph.getObjects()) { + if (o instanceof AnalysisMethod m) { + m.setReachableInCurrentLayer(); + } else if (o instanceof JavaMethodProfile javaMethodProfile) { + for (var m : javaMethodProfile.getMethods()) { + if (m.getMethod() instanceof AnalysisMethod aMethod) { + aMethod.setReachableInCurrentLayer(); + } + } + } else if (o instanceof ImageHeapConstant constant) { + loadMaterializedChildren(constant); + } + } + } + } + + private void loadMaterializedChildren(ImageHeapConstant constant) { + if (constant instanceof ImageHeapInstance imageHeapInstance && !imageHeapInstance.nullFieldValues()) { + loadMaterializedChildren(constant, imageHeapInstance.getFieldValues()); + } else if (constant instanceof ImageHeapObjectArray imageHeapObjectArray) { + loadMaterializedChildren(constant, imageHeapObjectArray.getElementValues()); + } + } + + private void loadMaterializedChildren(ImageHeapConstant constant, Object[] values) { + PersistedConstant.Reader baseLayerConstant = findConstant(ImageHeapConstant.getConstantID(constant)); + if (baseLayerConstant != null) { + StructList.Reader data = baseLayerConstant.getObject().getData(); + for (int i = 0; i < data.size(); ++i) { + ConstantReference.Reader childConstant = data.get(i); + if (childConstant.isObjectConstant()) { + if (childConstant.isNotMaterialized()) { + continue; + } + loadMaterializedChild(values[i]); + } + } + } + } + + private void loadMaterializedChild(Object child) { + if (child instanceof AnalysisFuture analysisFuture) { + if (analysisFuture.ensureDone() instanceof ImageHeapConstant imageHeapConstant) { + loadMaterializedChildren(imageHeapConstant); + } + } + } + protected static int getId(String line) { return Integer.parseInt(line.split(" = ")[1]); } 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 a770e6607931..26a84079e363 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 @@ -68,11 +68,15 @@ public class ImageLayerSnapshotUtil { /** This needs to be initialized after analysis, as some fields are not available before. */ protected Map externalValues; - public ImageLayerSnapshotUtil() { - try { - this.externalValueFields = ObjectCopier.getExternalValueFields(); - } catch (IOException e) { - throw AnalysisError.shouldNotReachHere("Unexpected exception when creating external value fields list", e); + public ImageLayerSnapshotUtil(boolean computeExternalValues) { + if (computeExternalValues) { + try { + this.externalValueFields = ObjectCopier.getExternalValueFields(); + } catch (IOException e) { + throw AnalysisError.shouldNotReachHere("Unexpected exception when creating external value fields list", e); + } + } else { + this.externalValueFields = List.of(); } } @@ -132,6 +136,11 @@ public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { return new GraphEncoder(externalValues, imageLayerWriter); } + @SuppressWarnings("unused") + public GraphDecoder getGraphAnalysisElementsDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod); + } + @SuppressWarnings("unused") public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod); 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 e8e37a9b897c..72a84ca9b28d 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 @@ -188,13 +188,9 @@ void finish() { } } - public ImageLayerWriter() { - this(true); - } - - public ImageLayerWriter(boolean useSharedLayerGraphs) { + public ImageLayerWriter(boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { this.useSharedLayerGraphs = useSharedLayerGraphs; - this.useSharedLayerStrengthenedGraphs = false; + this.useSharedLayerStrengthenedGraphs = useSharedLayerStrengthenedGraphs; } public void setImageLayerSnapshotUtil(ImageLayerSnapshotUtil imageLayerSnapshotUtil) { 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 4e2fe934a00b..140204eb4f70 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 @@ -53,6 +53,7 @@ import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; @@ -112,6 +113,9 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ static final AtomicReferenceFieldUpdater allImplementationsUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisMethod.class, Object.class, "allImplementations"); + private static final AtomicReferenceFieldUpdater reachableInCurrentLayerUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisMethod.class, Boolean.class, "reachableInCurrentLayer"); + public record Signature(String name, AnalysisType[] parameterTypes) { } @@ -166,6 +170,8 @@ public record Signature(String name, AnalysisType[] parameterTypes) { @SuppressWarnings("unused") private volatile Object implementationInvokedNotifications; @SuppressWarnings("unused") private volatile Object isIntrinsicMethod; @SuppressWarnings("unused") private volatile Object isInlined; + @SuppressWarnings("unused") private volatile Boolean reachableInCurrentLayer; + private final boolean enableReachableInCurrentLayer; private final AtomicReference parsedGraphCacheState = new AtomicReference<>(GRAPH_CACHE_UNPARSED); private static final Object GRAPH_CACHE_UNPARSED = "unparsed"; @@ -266,6 +272,8 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, startTrackInvocations(); } parsingContextMaxDepth = PointstoOptions.ParsingContextMaxDepth.getValue(declaringClass.universe.hostVM.options()); + + this.enableReachableInCurrentLayer = universe.hostVM.enableReachableInCurrentLayer(); } @SuppressWarnings("this-escape") @@ -294,6 +302,8 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey) if (PointstoOptions.TrackAccessChain.getValue(declaringClass.universe.hostVM().options())) { startTrackInvocations(); } + + this.enableReachableInCurrentLayer = original.enableReachableInCurrentLayer; } private static String createName(ResolvedJavaMethod wrapped, MultiMethodKey multiMethodKey) { @@ -459,6 +469,21 @@ public boolean analyzedInPriorLayer() { return analyzedInPriorLayer; } + public boolean reachableInCurrentLayer() { + return enableReachableInCurrentLayer && reachableInCurrentLayer != null && reachableInCurrentLayer; + } + + public void setReachableInCurrentLayer() { + if (enableReachableInCurrentLayer && !reachableInCurrentLayer()) { + AtomicUtils.atomicSetAndRun(this, true, reachableInCurrentLayerUpdater, () -> { + ImageLayerLoader imageLayerLoader = getUniverse().getImageLayerLoader(); + if (imageLayerLoader != null) { + imageLayerLoader.loadPriorStrengthenedGraphAnalysisElements(this); + } + }); + } + } + /** * Registers this method as intrinsified to Graal nodes via a {@link InvocationPlugin graph * builder plugin}. Such a method is treated similar to an invoked method. For example, method 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 0e5d143918a2..c1deccc191b5 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 @@ -234,19 +234,24 @@ public final void applyResults(AnalysisMethod method) { ? ptaMethod.getTypeFlow().getMethodFlowsGraph().getNodeFlows().getKeys() : null; var debug = new DebugContext.Builder(bb.getOptions(), new GraalDebugHandlersFactory(bb.getSnippetReflectionProvider())).build(); - var graph = method.decodeAnalyzedGraph(debug, nodeReferences); - if (graph == null) { - return; - } if (method.analyzedInPriorLayer()) { /* - * The method was already strengthened in a prior layer, so there is no need to - * strengthen it in this layer. + * The method was already strengthened in a prior layer. If the graph was persisted, it + * will be loaded on demand during compilation, so there is no need to strengthen it in + * this layer. + * + * GR-59646: The graphs from the base layer could be strengthened again in the + * application layer using closed world assumptions. */ return; } + var graph = method.decodeAnalyzedGraph(debug, nodeReferences); + if (graph == null) { + return; + } + graph.resetDebug(debug); if (beforeCounters != null) { beforeCounters.collect(graph); @@ -503,6 +508,11 @@ public void simplify(Node n, SimplifierTool tool) { Stamp newStamp = strengthenStamp(oldStamp); if (newStamp != null) { LogicNode replacement = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) oldStamp.improveWith(newStamp), node.getValue(), node.profile(), node.getAnchor())); + /* + * GR-59681: Once isAssignable is implemented for BaseLayerType, this check can + * be removed + */ + AnalysisError.guarantee(node != replacement, "The new stamp needs to be different from the old stamp"); node.replaceAndDelete(replacement); tool.addToWorkList(replacement); } @@ -560,7 +570,13 @@ public void simplify(Node n, SimplifierTool tool) { Stamp oldStamp = node.piStamp(); Stamp newStamp = strengthenStamp(oldStamp); if (newStamp != null) { - node.strengthenPiStamp(oldStamp.improveWith(newStamp)); + Stamp newPiStamp = oldStamp.improveWith(newStamp); + /* + * GR-59681: Once isAssignable is implemented for BaseLayerType, this check can + * be removed + */ + AnalysisError.guarantee(!newPiStamp.equals(oldStamp), "The new stamp needs to be different from the old stamp"); + node.strengthenPiStamp(newPiStamp); tool.addToWorkList(node); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index b0582b5cbbe9..5ca5744b6619 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -109,12 +109,27 @@ public class SubstrateOptions { @Option(help = "Build shared library")// public static final HostedOptionKey SharedLibrary = new HostedOptionKey<>(false); - @Option(help = "Persist and reload graphs across layers. If false, graphs defined in the base layer can be reparsed by the current layer and inlined before analysis, " + + @Option(help = "Persist and reload all graphs across layers. If false, graphs defined in the base layer can be reparsed by the current layer and inlined before analysis, " + "but will not be inlined after analysis has completed via our other inlining infrastructure")// public static final HostedOptionKey UseSharedLayerGraphs = new HostedOptionKey<>(true) { @Override protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { - NeverInline.update(values, "SubstrateStringConcatHelper.simpleConcat"); + if (!newValue) { + UseSharedLayerStrengthenedGraphs.update(values, false); + } + } + }; + + @Option(help = "Persist and reload strengthened graphs across layers. If false, inlining after analysis will be disabled")// + public static final HostedOptionKey UseSharedLayerStrengthenedGraphs = new HostedOptionKey<>(false) { + @Override + protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { + if (newValue) { + UserError.guarantee(UseSharedLayerStrengthenedGraphs.getValueOrDefault(values), + "UseSharedLayerStrengthenedGraph is a subset of UseSharedLayerGraphs, so the former cannot be enabled alone."); + } else { + NeverInline.update(values, "SubstrateStringConcatHelper.simpleConcat"); + } } }; 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 6cdd53b0da75..4706223a0eb6 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 @@ -199,6 +199,7 @@ public enum UsageKind { private final Boolean optionAllowUnsafeAllocationOfAllInstantiatedTypes = SubstrateOptions.AllowUnsafeAllocationOfAllInstantiatedTypes.getValue(); private final boolean isClosedTypeWorld = SubstrateOptions.useClosedTypeWorld(); private final boolean enableTrackAcrossLayers; + private final boolean enableReachableInCurrentLayer; /** Modules containing all {@code svm.core} and {@code svm.hosted} classes. */ private final Set builderModules; @@ -236,6 +237,7 @@ public SVMHost(OptionValues options, ImageClassLoader loader, ClassInitializatio } enableTrackAcrossLayers = ImageLayerBuildingSupport.buildingSharedLayer(); + enableReachableInCurrentLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); builderModules = ImageSingletons.contains(OpenTypeWorldFeature.class) ? ImageSingletons.lookup(OpenTypeWorldFeature.class).getBuilderModules() : null; } @@ -950,6 +952,11 @@ public boolean enableTrackAcrossLayers() { return enableTrackAcrossLayers; } + @Override + public boolean enableReachableInCurrentLayer() { + return enableReachableInCurrentLayer; + } + private final List> neverInlineTrivialHandlers = new CopyOnWriteArrayList<>(); public void registerNeverInlineTrivialHandler(BiPredicate handler) { 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 8ded7f4ebc6a..e133e7508f2d 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 @@ -42,6 +42,7 @@ import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; @@ -70,6 +71,7 @@ import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; @@ -449,6 +451,9 @@ public void finish(DebugContext debug) { if (ImageSingletons.contains(HostedHeapDumpFeature.class)) { ImageSingletons.lookup(HostedHeapDumpFeature.class).compileQueueAfterCompilation(); } + if (ImageLayerBuildingSupport.buildingExtensionLayer()) { + HostedImageLayerBuildingSupport.singleton().getLoader().cleanupAfterCompilation(); + } } protected void checkUninterruptibleAnnotations() { @@ -847,8 +852,7 @@ private void doInlineTrivial(DebugContext debug, HostedMethod method) { } private boolean makeInlineDecision(HostedMethod method, HostedMethod callee) { - // GR-57832 this will be removed - if (callee.compilationInfo.getCompilationGraph() == null) { + 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. @@ -856,7 +860,6 @@ private boolean makeInlineDecision(HostedMethod method, HostedMethod callee) { assert callee.isCompiledInPriorLayer() : method; return false; } - if (universe.hostVM().neverInlineTrivial(method.getWrapped(), callee.getWrapped())) { return false; } @@ -982,10 +985,15 @@ public void scheduleDeoptTargets() { } private static boolean parseInCurrentLayer(HostedMethod method) { + if (method.wrapped.isInBaseLayer() && !method.wrapped.reachableInCurrentLayer()) { + return false; + } var hasAnalyzedGraph = method.wrapped.getAnalyzedGraph() != null; - if (!hasAnalyzedGraph) { - assert method.isCompiledInPriorLayer() || method.compilationInfo.inParseQueue.get() : method; + if (!hasAnalyzedGraph && method.wrapped.reachableInCurrentLayer() && HostedImageLayerBuildingSupport.buildingExtensionLayer()) { + ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + hasAnalyzedGraph = imageLayerLoader.hasStrengthenedGraph(method.wrapped); } + assert hasAnalyzedGraph || method.isCompiledInPriorLayer() || method.compilationInfo.inParseQueue.get() : method; return hasAnalyzedGraph; } @@ -1006,6 +1014,11 @@ protected void ensureParsed(HostedMethod method, HostedMethod callerMethod, Comp } protected final void doParse(DebugContext debug, ParseTask task) { + HostedMethod method = task.method; + if (HostedImageLayerBuildingSupport.buildingExtensionLayer()) { + loadPriorStrengthenedGraph(method); + } + ParseFunction customFunction = task.method.compilationInfo.getCustomParseFunction(); if (customFunction != null) { customFunction.parse(debug, task.method, task.reason, runtimeConfig); @@ -1019,6 +1032,25 @@ protected final void doParse(DebugContext debug, ParseTask task) { } } + private static void loadPriorStrengthenedGraph(HostedMethod method) { + if (method.wrapped.getAnalyzedGraph() == null && method.wrapped.reachableInCurrentLayer()) { + /* + * Only the strengthened graphs of methods that need to be analyzed in the current layer + * are loaded. + */ + ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + boolean hasStrengthenedGraph = imageLayerLoader.hasStrengthenedGraph(method.wrapped); + assert method.isCompiledInPriorLayer() || method.compilationInfo.inParseQueue.get() || hasStrengthenedGraph : method; + if (hasStrengthenedGraph) { + /* + * GR-59679: The loading of graphs could be even more lazy than this. It could be + * loaded only when the inlining will be performed + */ + method.wrapped.setAnalyzedGraph(imageLayerLoader.getStrengthenedGraph(method.wrapped)); + } + } + } + @SuppressWarnings("try") private void defaultParseFunction(DebugContext debug, HostedMethod method, CompileReason reason, RuntimeConfiguration config, ParseHooks hooks) { if (method.getAnnotation(NodeIntrinsic.class) != null) { @@ -1095,7 +1127,7 @@ private void ensureParsed(HostedMethod method, CompileReason reason, CallTargetN * already applied during parsing before we reach this point, so we look at the "simple" * implementation invoked status. */ - if (invokeTarget.wrapped.isSimplyImplementationInvoked() || invokeTarget.wrapped.isInBaseLayer()) { + if (invokeTarget.wrapped.isSimplyImplementationInvoked()) { handleSpecialization(method, targetNode, invokeTarget, invokeTarget); ensureParsed(invokeTarget, method, new DirectCallReason(method, reason)); } 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 3ffcead2c4b7..a62ff5e45693 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 @@ -65,6 +65,7 @@ import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.thread.VMThreadLocalCollector; import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; @@ -99,7 +100,7 @@ public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { @SuppressWarnings("this-escape") public SVMImageLayerSnapshotUtil(ImageClassLoader imageClassLoader) { - super(); + super(true); this.imageClassLoader = imageClassLoader; addSVMExternalValueFields(); } @@ -229,6 +230,11 @@ public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { return new SVMGraphEncoder(externalValues, imageLayerWriter); } + @Override + public GraphDecoder getGraphAnalysisElementsDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new SVMGraphAnalysisElementsDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, analysisMethod, snippetReflectionProvider); + } + @Override public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { return new SVMGraphDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, analysisMethod, snippetReflectionProvider); @@ -238,6 +244,7 @@ public static class SVMGraphEncoder extends GraphEncoder { @SuppressWarnings("this-escape") public SVMGraphEncoder(Map externalValues, ImageLayerWriter imageLayerWriter) { super(externalValues, imageLayerWriter); + addBuiltin(new AnalysisTypeBuiltIn(null)); addBuiltin(new HostedMethodBuiltIn(null)); addBuiltin(new HostedOptionValuesBuiltIn()); addBuiltin(new HostedSnippetReflectionProviderBuiltIn(null)); @@ -247,12 +254,10 @@ public SVMGraphEncoder(Map externalValues, ImageLayerWriter image } } - public static class SVMGraphDecoder extends GraphDecoder { + public abstract static class AbstractSVMGraphDecoder extends GraphDecoder { @SuppressWarnings("this-escape") - public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + public AbstractSVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { super(classLoader, svmImageLayerLoader, analysisMethod); - addBuiltin(new HostedTypeBuiltIn(svmImageLayerLoader)); - addBuiltin(new HostedMethodBuiltIn(svmImageLayerLoader)); addBuiltin(new HostedOptionValuesBuiltIn()); addBuiltin(new HostedSnippetReflectionProviderBuiltIn(snippetReflectionProvider)); addBuiltin(new CInterfaceLocationIdentityBuiltIn()); @@ -261,10 +266,28 @@ public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLaye } } - public static class HostedTypeBuiltIn extends ObjectCopier.Builtin { - private final SVMImageLayerLoader svmImageLayerLoader; + public static class SVMGraphAnalysisElementsDecoder extends AbstractSVMGraphDecoder { + @SuppressWarnings("this-escape") + public SVMGraphAnalysisElementsDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + super(classLoader, svmImageLayerLoader, analysisMethod, snippetReflectionProvider); + addBuiltin(new AnalysisTypeBuiltIn(svmImageLayerLoader)); + addBuiltin(new AnalysisMethodBuiltIn(svmImageLayerLoader)); + } + } - protected HostedTypeBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + public static class SVMGraphDecoder extends AbstractSVMGraphDecoder { + @SuppressWarnings("this-escape") + public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + super(classLoader, svmImageLayerLoader, analysisMethod, snippetReflectionProvider); + addBuiltin(new HostedTypeBuiltIn(svmImageLayerLoader)); + addBuiltin(new HostedMethodBuiltIn(svmImageLayerLoader)); + } + } + + public abstract static class AbstractHostedTypeBuiltIn extends ObjectCopier.Builtin { + protected final SVMImageLayerLoader svmImageLayerLoader; + + protected AbstractHostedTypeBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { super(HostedType.class, HostedInstanceClass.class, HostedArrayClass.class); this.svmImageLayerLoader = svmImageLayerLoader; } @@ -274,19 +297,40 @@ protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream str int id = ((HostedType) obj).getWrapped().getId(); stream.writePackedUnsignedInt(id); } + } + + public static class AnalysisTypeBuiltIn extends AbstractHostedTypeBuiltIn { + protected AnalysisTypeBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + super(svmImageLayerLoader); + } @Override protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - AnalysisType type = svmImageLayerLoader.getAnalysisTypeForBaseLayerId(id); - return svmImageLayerLoader.getHostedUniverse().lookup(type); + return getAnalysisType(svmImageLayerLoader, stream); } } - public static class HostedMethodBuiltIn extends ObjectCopier.Builtin { - private final SVMImageLayerLoader svmImageLayerLoader; + public static class HostedTypeBuiltIn extends AbstractHostedTypeBuiltIn { + protected HostedTypeBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + super(svmImageLayerLoader); + } - protected HostedMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + HostedUniverse hostedUniverse = svmImageLayerLoader.getHostedUniverse(); + return hostedUniverse.lookup(getAnalysisType(svmImageLayerLoader, stream)); + } + } + + private static AnalysisType getAnalysisType(SVMImageLayerLoader imageLayerLoader, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return imageLayerLoader.getAnalysisTypeForBaseLayerId(id); + } + + public abstract static class AbstractHostedMethodBuiltIn extends ObjectCopier.Builtin { + protected final SVMImageLayerLoader svmImageLayerLoader; + + protected AbstractHostedMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { super(HostedMethod.class); this.svmImageLayerLoader = svmImageLayerLoader; } @@ -295,13 +339,34 @@ protected HostedMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { stream.writePackedUnsignedInt(((HostedMethod) obj).getWrapped().getId()); } + } + + public static class AnalysisMethodBuiltIn extends AbstractHostedMethodBuiltIn { + protected AnalysisMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + super(svmImageLayerLoader); + } @Override protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - AnalysisMethod method = svmImageLayerLoader.getAnalysisMethodForBaseLayerId(id); - return svmImageLayerLoader.getHostedUniverse().lookup(method); + return getAnalysisMethod(svmImageLayerLoader, stream); + } + } + + public static class HostedMethodBuiltIn extends AbstractHostedMethodBuiltIn { + protected HostedMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + super(svmImageLayerLoader); } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + HostedUniverse hostedUniverse = svmImageLayerLoader.getHostedUniverse(); + return hostedUniverse.lookup(getAnalysisMethod(svmImageLayerLoader, stream)); + } + } + + private static AnalysisMethod getAnalysisMethod(SVMImageLayerLoader imageLayerLoader, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return imageLayerLoader.getAnalysisMethodForBaseLayerId(id); } public static class HostedOptionValuesBuiltIn extends ObjectCopier.Builtin { 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 626782c8cfd9..66c1d07ba729 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 @@ -109,8 +109,8 @@ public class SVMImageLayerWriter extends ImageLayerWriter { private NativeImageHeap nativeImageHeap; private HostedUniverse hUniverse; - public SVMImageLayerWriter(boolean useSharedLayerGraphs) { - super(useSharedLayerGraphs); + public SVMImageLayerWriter(boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { + super(useSharedLayerGraphs, useSharedLayerStrengthenedGraphs); } public void setNativeImageHeap(NativeImageHeap nativeImageHeap) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index 61762f2f47ce..d66ad09a1058 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -384,7 +384,7 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil // which is also in the code cache (a.k.a. a section-local call). // This will change, and we will have to case-split here... but not yet. HostedMethod callTarget = (HostedMethod) call.target; - VMError.guarantee(!callTarget.wrapped.isInBaseLayer(), "Unexpected direct call to base layer method %s. These calls are currently lowered to indirect calls.", callTarget); + VMError.guarantee(!callTarget.isCompiledInPriorLayer(), "Unexpected direct call to base layer method %s. These calls are currently lowered to indirect calls.", callTarget); int callTargetStart = callTarget.getCodeAddressOffset(); if (trampolineOffsetMap != null && trampolineOffsetMap.containsKey(callTarget)) { callTargetStart = trampolineOffsetMap.get(callTarget); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java index d1185a1b09a7..def07cdba99d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java @@ -176,10 +176,11 @@ public static HostedImageLayerBuildingSupport initialize(HostedOptionValues valu SVMImageLayerWriter writer = null; ArchiveSupport archiveSupport = new ArchiveSupport(false); Boolean useSharedLayerGraphs = SubstrateOptions.UseSharedLayerGraphs.getValue(values); + Boolean useSharedLayerStrengthenedGraphs = SubstrateOptions.UseSharedLayerStrengthenedGraphs.getValue(values); if (buildingSharedLayer) { LayerOption layerOption = LayerOption.parse(SubstrateOptions.LayerCreate.getValue(values).lastValue().orElseThrow()); writeLayerArchiveSupport = new WriteLayerArchiveSupport(archiveSupport, layerOption.fileName()); - writer = new SVMImageLayerWriter(useSharedLayerGraphs); + writer = new SVMImageLayerWriter(useSharedLayerGraphs, useSharedLayerStrengthenedGraphs); } SVMImageLayerLoader loader = null; LoadLayerArchiveSupport loadLayerArchiveSupport = null; From 6f91603a8aaced3a8c294029d2897c4ad43efffa Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Thu, 19 Dec 2024 12:48:04 +0100 Subject: [PATCH 2/2] simplify parseInCurrentLayer criteria --- .../src/com/oracle/svm/hosted/code/CompileQueue.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 e133e7508f2d..01dea65fcaf7 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 @@ -985,11 +985,8 @@ public void scheduleDeoptTargets() { } private static boolean parseInCurrentLayer(HostedMethod method) { - if (method.wrapped.isInBaseLayer() && !method.wrapped.reachableInCurrentLayer()) { - return false; - } var hasAnalyzedGraph = method.wrapped.getAnalyzedGraph() != null; - if (!hasAnalyzedGraph && method.wrapped.reachableInCurrentLayer() && HostedImageLayerBuildingSupport.buildingExtensionLayer()) { + if (!hasAnalyzedGraph && method.wrapped.reachableInCurrentLayer()) { ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); hasAnalyzedGraph = imageLayerLoader.hasStrengthenedGraph(method.wrapped); }