From 01f82d345f1bf42b77b212533cea40502276ff04 Mon Sep 17 00:00:00 2001 From: "cengfeng.lzy" Date: Fri, 10 Sep 2021 10:32:28 +0800 Subject: [PATCH] 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. --- .../com/oracle/graal/pointsto/BigBang.java | 4 ++ .../graal/pointsto/PointsToAnalysis.java | 58 +++++++++++++++++++ .../svm/hosted/NativeImageGenerator.java | 54 ++++------------- 3 files changed, 72 insertions(+), 44 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index 4d34825d0c7e..b17b5d7707ea 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -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; @@ -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 @@ -92,4 +94,6 @@ public interface BigBang extends ReachabilityAnalysis, HeapScanning { Runnable getHeartbeatCallback(); boolean extendedAsserts(); + + void runAnalysis(DebugContext debug, Function duringAnalysisAction) throws InterruptedException; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index d73228a53fc1..78c3cc170897 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -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; @@ -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 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); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index b01843f59fa6..130b39dc9b34 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -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; @@ -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);