Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,6 @@ public void cleanupAfterAnalysis() {

universe.getHeapScanner().cleanupAfterAnalysis();
universe.getHeapVerifier().cleanupAfterAnalysis();
if (universe.getImageLayerLoader() != null) {
universe.getImageLayerLoader().cleanupAfterAnalysis();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -179,7 +180,7 @@ public void loadLayerAnalysis() {
loadLayerAnalysis0();
}

public void cleanupAfterAnalysis() {
public void cleanupAfterCompilation() {
if (graphsChannel != null) {
try {
graphsChannel.close();
Expand Down Expand Up @@ -594,28 +595,33 @@ 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) {
PersistedAnalysisMethod.Reader methodData = getMethodData(analysisMethod);
return getEncodedGraph(analysisMethod, methodData.getStrengthenedGraphLocation());
}

private boolean hasGraph(AnalysisMethod analysisMethod, Function<PersistedAnalysisMethod.Reader, Boolean> 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);
Expand Down Expand Up @@ -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<ConstantReference.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]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,15 @@ public class ImageLayerSnapshotUtil {
/** This needs to be initialized after analysis, as some fields are not available before. */
protected Map<Object, Field> 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();
}
}

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -112,6 +113,9 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> allImplementationsUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Object.class, "allImplementations");

private static final AtomicReferenceFieldUpdater<AnalysisMethod, Boolean> reachableInCurrentLayerUpdater = AtomicReferenceFieldUpdater
.newUpdater(AnalysisMethod.class, Boolean.class, "reachableInCurrentLayer");

public record Signature(String name, AnalysisType[] parameterTypes) {
}

Expand Down Expand Up @@ -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<Object> parsedGraphCacheState = new AtomicReference<>(GRAPH_CACHE_UNPARSED);
private static final Object GRAPH_CACHE_UNPARSED = "unparsed";
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,27 @@ public class SubstrateOptions {
@Option(help = "Build shared library")//
public static final HostedOptionKey<Boolean> 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<Boolean> UseSharedLayerGraphs = new HostedOptionKey<>(true) {
@Override
protected void onValueUpdate(EconomicMap<OptionKey<?>, 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<Boolean> UseSharedLayerStrengthenedGraphs = new HostedOptionKey<>(false) {
@Override
protected void onValueUpdate(EconomicMap<OptionKey<?>, 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");
}
}
};

Expand Down
Loading
Loading