5757import org .graalvm .compiler .printer .GraalDebugHandlersFactory ;
5858import org .graalvm .nativeimage .hosted .Feature ;
5959
60- import com .oracle .graal .pointsto .ObjectScanner .ReusableSet ;
6160import com .oracle .graal .pointsto .api .HostVM ;
6261import com .oracle .graal .pointsto .api .PointstoOptions ;
6362import com .oracle .graal .pointsto .constraints .UnsupportedFeatures ;
@@ -128,7 +127,7 @@ public abstract class PointsToAnalysis implements BigBang {
128127 private final CompletionExecutor .Timing timing ;
129128
130129 public final Timer typeFlowTimer ;
131- public final Timer checkObjectsTimer ;
130+ public final Timer verifyHeapTimer ;
132131 public final Timer processFeaturesTimer ;
133132 public final Timer analysisTimer ;
134133
@@ -142,7 +141,7 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostedP
142141 this .hostVM = hostVM ;
143142 String imageName = hostVM .getImageName ();
144143 this .typeFlowTimer = new Timer (imageName , "(typeflow)" , false );
145- this .checkObjectsTimer = new Timer (imageName , "(objects )" , false );
144+ this .verifyHeapTimer = new Timer (imageName , "(verify )" , false );
146145 this .processFeaturesTimer = new Timer (imageName , "(features)" , false );
147146 this .analysisTimer = new Timer (imageName , "analysis" , true );
148147
@@ -194,14 +193,14 @@ public Timer getProcessFeaturesTimer() {
194193 @ Override
195194 public void printTimers () {
196195 typeFlowTimer .print ();
197- checkObjectsTimer .print ();
196+ verifyHeapTimer .print ();
198197 processFeaturesTimer .print ();
199198 }
200199
201200 @ Override
202201 public void printTimerStatistics (PrintWriter out ) {
203202 StatisticsPrinter .print (out , "typeflow_time_ms" , typeFlowTimer .getTotalTime ());
204- StatisticsPrinter .print (out , "objects_time_ms " , checkObjectsTimer .getTotalTime ());
203+ StatisticsPrinter .print (out , "verify_time_ms " , verifyHeapTimer .getTotalTime ());
205204 StatisticsPrinter .print (out , "features_time_ms" , processFeaturesTimer .getTotalTime ());
206205 StatisticsPrinter .print (out , "total_analysis_time_ms" , analysisTimer .getTotalTime ());
207206
@@ -323,13 +322,15 @@ public void cleanupAfterAnalysis() {
323322 allSynchronizedTypeFlow = null ;
324323 unsafeLoads = null ;
325324 unsafeStores = null ;
326- scannedObjects = null ;
327325
328326 ConstantObjectsProfiler .constantTypes .clear ();
329327
330328 universe .getTypes ().forEach (AnalysisType ::cleanupAfterAnalysis );
331329 universe .getFields ().forEach (AnalysisField ::cleanupAfterAnalysis );
332330 universe .getMethods ().forEach (AnalysisMethod ::cleanupAfterAnalysis );
331+
332+ universe .getHeapScanner ().cleanupAfterAnalysis ();
333+ universe .getHeapVerifier ().cleanupAfterAnalysis ();
333334 }
334335
335336 @ Override
@@ -570,10 +571,6 @@ public ConstantFieldProvider getConstantFieldProvider() {
570571 return providers .getConstantFieldProvider ();
571572 }
572573
573- public CompletionExecutor getExecutor () {
574- return executor ;
575- }
576-
577574 @ Override
578575 public void checkUserLimitations () {
579576 }
@@ -630,26 +627,9 @@ public void postTask(final DebugContextRunnable task) {
630627 public boolean finish () throws InterruptedException {
631628 try (Indent indent = debug .logAndIndent ("starting analysis in BigBang.finish" )) {
632629 universe .setAnalysisDataValid (false );
633- boolean didSomeWork = false ;
634-
635- int numTypes ;
636- do {
637- didSomeWork |= doTypeflow ();
638-
639- /*
640- * Check if the object graph introduces any new types, which leads to new operations
641- * being posted.
642- */
643- assert executor .getPostedOperations () == 0 ;
644- numTypes = universe .getTypes ().size ();
645- try (StopTimer t = checkObjectsTimer .start ()) {
646- // track static fields
647- checkObjectGraph ();
648- }
649- } while (executor .getPostedOperations () != 0 || numTypes != universe .getTypes ().size ());
650-
630+ boolean didSomeWork = doTypeflow ();
631+ assert executor .getPostedOperations () == 0 ;
651632 universe .setAnalysisDataValid (true );
652-
653633 return didSomeWork ;
654634 }
655635 }
@@ -668,39 +648,11 @@ public boolean doTypeflow() throws InterruptedException {
668648 return didSomeWork ;
669649 }
670650
671- private ReusableSet scannedObjects = new ReusableSet ();
672-
673- @ SuppressWarnings ("try" )
674- private void checkObjectGraph () throws InterruptedException {
675- scannedObjects .reset ();
676- // scan constants
677- boolean isParallel = PointstoOptions .ScanObjectsParallel .getValue (options );
678- ObjectScanner objectScanner = new AnalysisObjectScanner (this , isParallel ? executor : null , scannedObjects );
679- checkObjectGraph (objectScanner );
680- if (isParallel ) {
681- executor .start ();
682- objectScanner .scanBootImageHeapRoots (null , null );
683- executor .complete ();
684- executor .shutdown ();
685- executor .init (timing );
686- } else {
687- objectScanner .scanBootImageHeapRoots (null , null );
688- }
689- }
690-
691651 @ Override
692652 public HeapScanningPolicy scanningPolicy () {
693653 return heapScanningPolicy ;
694654 }
695655
696- /**
697- * Traverses the object graph to discover references to new types.
698- *
699- * @param objectScanner
700- */
701- protected void checkObjectGraph (ObjectScanner objectScanner ) {
702- }
703-
704656 @ Override
705657 public HostVM getHostVM () {
706658 return hostVM ;
@@ -744,8 +696,9 @@ public void runAnalysis(DebugContext debugContext, Function<AnalysisUniverse, Bo
744696 "The analysis itself %s find a change in type states in the last iteration." ,
745697 numIterations , analysisChanged ? "DID" : "DID NOT" ));
746698 }
747-
748- /* Allow features to change the universe. */
699+ /*
700+ * Allow features to change the universe.
701+ */
749702 int numTypes = universe .getTypes ().size ();
750703 int numMethods = universe .getMethods ().size ();
751704 int numFields = universe .getFields ().size ();
@@ -754,12 +707,35 @@ public void runAnalysis(DebugContext debugContext, Function<AnalysisUniverse, Bo
754707 throw AnalysisError .shouldNotReachHere (
755708 "When a feature makes more types, methods, or fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()" );
756709 }
757- return ;
710+ /*
711+ * Manual rescanning doesn't explicitly require analysis iterations, but it can
712+ * insert some pending operations.
713+ */
714+ boolean pendingOperations = executor .getPostedOperations () > 0 ;
715+ if (pendingOperations ) {
716+ System .out .println ("Found pending operations, continuing analysis." );
717+ continue ;
718+ }
719+ /* Outer analysis loop is done. Check if heap verification modifies analysis. */
720+ if (!analysisModified ()) {
721+ return ;
722+ }
758723 }
759724 }
760725 }
761726 }
762727
728+ @ SuppressWarnings ("try" )
729+ private boolean analysisModified () throws InterruptedException {
730+ boolean analysisModified ;
731+ try (StopTimer ignored = verifyHeapTimer .start ()) {
732+ analysisModified = universe .getHeapVerifier ().requireAnalysisIteration (executor );
733+ }
734+ /* Initialize for the next iteration. */
735+ executor .init (timing );
736+ return analysisModified ;
737+ }
738+
763739 @ SuppressFBWarnings (value = "NP_NONNULL_PARAM_VIOLATION" , justification = "ForkJoinPool does support null for the exception handler." )
764740 public static ForkJoinPool createExecutor (DebugContext debug , int numberOfThreads ) {
765741 ForkJoinPool .ForkJoinWorkerThreadFactory factory = debugThreadFactory (debug .areScopesEnabled () || debug .areMetricsEnabled () ? debug : null );
0 commit comments