|
43 | 43 | import java.util.concurrent.ForkJoinWorkerThread; |
44 | 44 | import java.util.concurrent.atomic.AtomicLong; |
45 | 45 | 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; |
46 | 50 |
|
47 | 51 | import com.oracle.graal.pointsto.flow.FieldTypeFlow; |
48 | 52 | import com.oracle.graal.pointsto.reports.StatisticsPrinter; |
@@ -703,6 +707,61 @@ public HostVM getHostVM() { |
703 | 707 | return hostVM; |
704 | 708 | } |
705 | 709 |
|
| 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 | + |
706 | 765 | @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "ForkJoinPool does support null for the exception handler.") |
707 | 766 | public static ForkJoinPool createExecutor(DebugContext debug, int numberOfThreads) { |
708 | 767 | ForkJoinPool.ForkJoinWorkerThreadFactory factory = debugThreadFactory(debug.areScopesEnabled() || debug.areMetricsEnabled() ? debug : null); |
|
0 commit comments