Skip to content

Commit a8ad963

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 0650510 commit a8ad963

File tree

3 files changed

+73
-44
lines changed

3 files changed

+73
-44
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import com.oracle.graal.pointsto.api.HostVM;
2828
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
29+
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
2930
import com.oracle.graal.pointsto.meta.HostedProviders;
3031
import com.oracle.graal.pointsto.util.Timer;
3132
import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -36,6 +37,7 @@
3637

3738
import java.io.PrintWriter;
3839
import java.util.List;
40+
import java.util.function.Function;
3941

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

9496
boolean extendedAsserts();
97+
98+
void runAnalysis(DebugContext debug, Function<AnalysisUniverse, Boolean> duringAnalysisAction) throws InterruptedException;
9599
}

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@
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.Function;
4647

4748
import com.oracle.graal.pointsto.flow.FieldTypeFlow;
4849
import com.oracle.graal.pointsto.reports.StatisticsPrinter;
50+
import com.oracle.graal.pointsto.util.AnalysisError;
4951
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
5052
import org.graalvm.compiler.core.common.SuppressFBWarnings;
5153
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
@@ -703,6 +705,61 @@ public HostVM getHostVM() {
703705
return hostVM;
704706
}
705707

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

61+
import com.oracle.graal.pointsto.util.AnalysisError;
6162
import org.graalvm.collections.EconomicSet;
6263
import org.graalvm.collections.Pair;
6364
import org.graalvm.compiler.api.replacements.Fold;
@@ -690,51 +691,16 @@ 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-
726-
bb.getHostVM().notifyClassReachabilityListener(aUniverse, config);
727-
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-
}
695+
try {
696+
bb.runAnalysis(debug,
697+
(aUniverse) -> {
698+
bb.getHostVM().notifyClassReachabilityListener(aUniverse, config);
699+
featureHandler.forEachFeature(feature -> feature.duringAnalysis(config));
700+
return !config.getAndResetRequireAnalysisIteration();
701+
});
702+
} catch (AnalysisError e) {
703+
throw UserError.abort(e, "Analysis step failed. Reason: %s.", e.getMessage());
738704
}
739705
assert verifyAssignableTypes(imageName);
740706

@@ -779,6 +745,8 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu
779745
return false;
780746
}
781747

748+
749+
782750
@SuppressWarnings("try")
783751
private boolean verifyAssignableTypes(String imageName) {
784752
/*

0 commit comments

Comments
 (0)