Skip to content
Merged
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 @@ -26,6 +26,7 @@

import com.oracle.graal.pointsto.api.HostVM;
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
import com.oracle.graal.pointsto.meta.HostedProviders;
import com.oracle.graal.pointsto.util.Timer;
import jdk.vm.ci.meta.ConstantReflectionProvider;
Expand All @@ -36,6 +37,7 @@

import java.io.PrintWriter;
import java.util.List;
import java.util.function.Function;

/**
* Central static analysis interface that groups together the functionality of reachability analysis
Expand Down Expand Up @@ -92,4 +94,6 @@ public interface BigBang extends ReachabilityAnalysis, HeapScanning {
Runnable getHeartbeatCallback();

boolean extendedAsserts();

void runAnalysis(DebugContext debug, Function<AnalysisUniverse, Boolean> duringAnalysisAction) throws InterruptedException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.function.Function;

import com.oracle.graal.pointsto.util.AnalysisError;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.core.common.SuppressFBWarnings;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
Expand Down Expand Up @@ -703,6 +705,62 @@ public HostVM getHostVM() {
return hostVM;
}

/**
* Iterate until analysis reaches a fixpoint.
*
*
* @param debugContext debug context
* @param duringAnalysisAction The action handler taken during analysis, return true if no more iteration is required.
* It could be the {@link org.graalvm.nativeimage.hosted.Feature#duringAnalysis}
* for Native Image generation, but also can be other similar actions for standalone pointsto
* analysis that does not dependent on {@link com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl}
* and {@link com.oracle.svm.hosted.NativeImageGenerator.AnalysisFeatureHandler}.
*
* @return The error message during the analysis. If the analysis ends successfully, an empty String is returned, otherwise
* the actual error message is returned.
* @throws InterruptedException
*/
@SuppressWarnings("try")
@Override
public void runAnalysis(DebugContext debugContext, Function<AnalysisUniverse, Boolean> duringAnalysisAction) throws InterruptedException {
int numIterations = 0;
while (true) {
try (Indent indent2 = debugContext.logAndIndent("new analysis iteration")) {
/*
* Do the analysis (which itself is done in a similar iterative process)
*/
boolean analysisChanged = finish();

numIterations++;
if (numIterations > 1000) {
/*
* Usually there are < 10 iterations. If we have so many iterations, we
* probably have an endless loop (but at least we have a performance
* problem because we re-start the analysis so often).
*/
AnalysisError.shouldNotReachHere(String.format("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " +
"The analysis itself %s find a change in type states in the last iteration.",
numIterations, analysisChanged ? "DID" : "DID NOT"));
}

/*
* Allow features to change the universe.
*/
try (StopTimer t2 = getProcessFeaturesTimer().start()) {
int numTypes = universe.getTypes().size();
int numMethods = universe.getMethods().size();
int numFields = universe.getFields().size();
if (duringAnalysisAction.apply(universe)) {
if (numTypes != universe.getTypes().size() || numMethods != universe.getMethods().size() || numFields != universe.getFields().size()) {
AnalysisError.shouldNotReachHere("When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()");
}
return;
}
}
}
}
}

@SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "ForkJoinPool does support null for the exception handler.")
public static ForkJoinPool createExecutor(DebugContext debug, int numberOfThreads) {
ForkJoinPool.ForkJoinWorkerThreadFactory factory = debugThreadFactory(debug.areScopesEnabled() || debug.areMetricsEnabled() ? debug : null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;

import com.oracle.graal.pointsto.util.AnalysisError;
import org.graalvm.collections.EconomicSet;
import org.graalvm.collections.Pair;
import org.graalvm.compiler.api.replacements.Fold;
Expand Down Expand Up @@ -693,51 +694,16 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu
}

try (StopTimer t = bb.getAnalysisTimer().start()) {

/*
* Iterate until analysis reaches a fixpoint.
*/
DuringAnalysisAccessImpl config = new DuringAnalysisAccessImpl(featureHandler, loader, bb, nativeLibraries, debug);
int numIterations = 0;
while (true) {
try (Indent indent2 = debug.logAndIndent("new analysis iteration")) {
/*
* Do the analysis (which itself is done in a similar iterative process)
*/
boolean analysisChanged = bb.finish();

numIterations++;
if (numIterations > 1000) {
/*
* Usually there are < 10 iterations. If we have so many iterations, we
* probably have an endless loop (but at least we have a performance
* problem because we re-start the analysis so often).
*/
throw UserError.abort("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " +
"The analysis itself %s find a change in type states in the last iteration.",
numIterations, analysisChanged ? "DID" : "DID NOT");
}

/*
* Allow features to change the universe.
*/
try (StopTimer t2 = bb.getProcessFeaturesTimer().start()) {
int numTypes = aUniverse.getTypes().size();
int numMethods = aUniverse.getMethods().size();
int numFields = aUniverse.getFields().size();

bb.getHostVM().notifyClassReachabilityListener(aUniverse, config);
featureHandler.forEachFeature(feature -> feature.duringAnalysis(config));

if (!config.getAndResetRequireAnalysisIteration()) {
if (numTypes != aUniverse.getTypes().size() || numMethods != aUniverse.getMethods().size() || numFields != aUniverse.getFields().size()) {
throw UserError.abort(
"When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()");
}
break;
}
}
}
try {
bb.runAnalysis(debug,
(aUniverse) -> {
bb.getHostVM().notifyClassReachabilityListener(aUniverse, config);
featureHandler.forEachFeature(feature -> feature.duringAnalysis(config));
return !config.getAndResetRequireAnalysisIteration();
});
} catch (AnalysisError e) {
throw UserError.abort(e, "Analysis step failed. Reason: %s.", e.getMessage());
}
assert verifyAssignableTypes(imageName);

Expand Down