Skip to content

Commit 3add7df

Browse files
committed
Refactor iterative analysis code to common method
Extract the iteratively analyzing code from NativeImageGenerator to PointsToAnalysis so it can be used by both native image generation and standalone pointsto analysis.
1 parent adfb1fe commit 3add7df

File tree

2 files changed

+68
-42
lines changed

2 files changed

+68
-42
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
import java.util.concurrent.ForkJoinWorkerThread;
4444
import java.util.concurrent.atomic.AtomicLong;
4545
import java.util.concurrent.atomic.AtomicLongArray;
46+
import java.util.function.BooleanSupplier;
47+
import java.util.function.Consumer;
48+
import java.util.function.Function;
49+
import java.util.function.Supplier;
4650

4751
import com.oracle.graal.pointsto.flow.FieldTypeFlow;
4852
import com.oracle.graal.pointsto.reports.StatisticsPrinter;
@@ -703,6 +707,61 @@ public HostVM getHostVM() {
703707
return hostVM;
704708
}
705709

710+
/**
711+
* Iterate until analysis reaches a fixpoint.
712+
*
713+
*
714+
* @param debug debug context
715+
* @param duringAnalysisAction The action handler taken during analysis, return true if no more iteration is required.
716+
* It could be the {@link org.graalvm.nativeimage.hosted.Feature#duringAnalysis}
717+
* for Native Image generation, but also can be other similar actions for standalone pointsto
718+
* analysis that does not dependent on {@link com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl}
719+
* and {@link com.oracle.svm.hosted.NativeImageGenerator.AnalysisFeatureHandler}.
720+
* @return The error message during the analysis. If the analysis ends successfully, an empty String is returned, otherwise
721+
* the actual error message is returned.
722+
* @throws InterruptedException
723+
*/
724+
@SuppressWarnings("try")
725+
public String iterativelyAnalyze(DebugContext debug, Function<AnalysisUniverse, Boolean> duringAnalysisAction) throws InterruptedException {
726+
int numIterations = 0;
727+
while (true) {
728+
try (Indent indent2 = debug.logAndIndent("new analysis iteration")) {
729+
/*
730+
* Do the analysis (which itself is done in a similar iterative process)
731+
*/
732+
boolean analysisChanged = finish();
733+
734+
numIterations++;
735+
if (numIterations > 1000) {
736+
/*
737+
* Usually there are < 10 iterations. If we have so many iterations, we
738+
* probably have an endless loop (but at least we have a performance
739+
* problem because we re-start the analysis so often).
740+
*/
741+
return String.format("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " +
742+
"The analysis itself %s find a change in type states in the last iteration.",
743+
numIterations, analysisChanged ? "DID" : "DID NOT");
744+
745+
}
746+
747+
/*
748+
* Allow features to change the universe.
749+
*/
750+
try (StopTimer t2 = getProcessFeaturesTimer().start()) {
751+
int numTypes = universe.getTypes().size();
752+
int numMethods = universe.getMethods().size();
753+
int numFields = universe.getFields().size();
754+
if (duringAnalysisAction.apply(universe)) {
755+
if (numTypes != universe.getTypes().size() || numMethods != universe.getMethods().size() || numFields != universe.getFields().size()) {
756+
return "When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()";
757+
}
758+
return "";
759+
}
760+
}
761+
}
762+
}
763+
}
764+
706765
@SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "ForkJoinPool does support null for the exception handler.")
707766
public static ForkJoinPool createExecutor(DebugContext debug, int numberOfThreads) {
708767
ForkJoinPool.ForkJoinWorkerThreadFactory factory = debugThreadFactory(debug.areScopesEnabled() || debug.areMetricsEnabled() ? debug : null);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import java.util.Set;
5656
import java.util.concurrent.ForkJoinPool;
5757
import java.util.concurrent.atomic.AtomicBoolean;
58+
import java.util.function.BooleanSupplier;
5859
import java.util.function.Consumer;
5960
import java.util.stream.Collectors;
6061

@@ -690,51 +691,15 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu
690691
}
691692

692693
try (StopTimer t = bb.getAnalysisTimer().start()) {
693-
694-
/*
695-
* Iterate until analysis reaches a fixpoint.
696-
*/
697694
DuringAnalysisAccessImpl config = new DuringAnalysisAccessImpl(featureHandler, loader, bb, nativeLibraries, debug);
698-
int numIterations = 0;
699-
while (true) {
700-
try (Indent indent2 = debug.logAndIndent("new analysis iteration")) {
701-
/*
702-
* Do the analysis (which itself is done in a similar iterative process)
703-
*/
704-
boolean analysisChanged = bb.finish();
705-
706-
numIterations++;
707-
if (numIterations > 1000) {
708-
/*
709-
* Usually there are < 10 iterations. If we have so many iterations, we
710-
* probably have an endless loop (but at least we have a performance
711-
* problem because we re-start the analysis so often).
712-
*/
713-
throw UserError.abort("Static analysis did not reach a fix point after %d iterations because a Feature keeps requesting new analysis iterations. " +
714-
"The analysis itself %s find a change in type states in the last iteration.",
715-
numIterations, analysisChanged ? "DID" : "DID NOT");
716-
}
717-
718-
/*
719-
* Allow features to change the universe.
720-
*/
721-
try (StopTimer t2 = bb.getProcessFeaturesTimer().start()) {
722-
int numTypes = aUniverse.getTypes().size();
723-
int numMethods = aUniverse.getMethods().size();
724-
int numFields = aUniverse.getFields().size();
725-
695+
String msg = ((NativeImagePointsToAnalysis) bb).iterativelyAnalyze(debug,
696+
(aUniverse) -> {
726697
bb.getHostVM().notifyClassReachabilityListener(aUniverse, config);
727698
featureHandler.forEachFeature(feature -> feature.duringAnalysis(config));
728-
729-
if (!config.getAndResetRequireAnalysisIteration()) {
730-
if (numTypes != aUniverse.getTypes().size() || numMethods != aUniverse.getMethods().size() || numFields != aUniverse.getFields().size()) {
731-
throw UserError.abort(
732-
"When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()");
733-
}
734-
break;
735-
}
736-
}
737-
}
699+
return !config.getAndResetRequireAnalysisIteration();
700+
});
701+
if (msg.length() > 0) {
702+
throw UserError.abort(msg);
738703
}
739704
assert verifyAssignableTypes(imageName);
740705

@@ -779,6 +744,8 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu
779744
return false;
780745
}
781746

747+
748+
782749
@SuppressWarnings("try")
783750
private boolean verifyAssignableTypes(String imageName) {
784751
/*

0 commit comments

Comments
 (0)