3737import org .graalvm .compiler .debug .GraalError ;
3838import org .graalvm .word .WordBase ;
3939
40+ import com .oracle .graal .pointsto .BigBang ;
4041import com .oracle .graal .pointsto .ObjectScanner ;
4142import com .oracle .graal .pointsto .ObjectScanner .ArrayScan ;
4243import com .oracle .graal .pointsto .ObjectScanner .EmbeddedRootScan ;
5354import com .oracle .graal .pointsto .meta .AnalysisUniverse ;
5455import com .oracle .graal .pointsto .util .AnalysisError ;
5556import com .oracle .graal .pointsto .util .AnalysisFuture ;
57+ import com .oracle .graal .pointsto .util .CompletionExecutor ;
5658import com .oracle .graal .pointsto .util .GraalAccess ;
5759import com .oracle .svm .util .ReflectionUtil ;
5860
@@ -75,6 +77,7 @@ public abstract class ImageHeapScanner {
7577
7678 private static final JavaConstant [] emptyConstantArray = new JavaConstant [0 ];
7779
80+ protected final BigBang bb ;
7881 protected final ImageHeap imageHeap ;
7982 protected final AnalysisMetaAccess metaAccess ;
8083 protected final AnalysisUniverse universe ;
@@ -90,8 +93,9 @@ public abstract class ImageHeapScanner {
9093 /** Marker object installed when encountering scanning issues like illegal objects. */
9194 private static final ImageHeapObject NULL_IMAGE_HEAP_OBJECT = new ImageHeapInstance (JavaConstant .NULL_POINTER , 0 );
9295
93- public ImageHeapScanner (ImageHeap heap , AnalysisMetaAccess aMetaAccess , SnippetReflectionProvider aSnippetReflection ,
96+ public ImageHeapScanner (BigBang bb , ImageHeap heap , AnalysisMetaAccess aMetaAccess , SnippetReflectionProvider aSnippetReflection ,
9497 ConstantReflectionProvider aConstantReflection , ObjectScanningObserver aScanningObserver ) {
98+ this .bb = bb ;
9599 imageHeap = heap ;
96100 metaAccess = aMetaAccess ;
97101 universe = aMetaAccess .getUniverse ();
@@ -467,51 +471,72 @@ protected boolean skipScanning() {
467471 return false ;
468472 }
469473
470- public Object rescanRoot (Field reflectionField ) {
474+ /**
475+ * When a re-scanning is triggered while the analysis is running in parallel, it is necessary to
476+ * do the re-scanning in a separate executor task to avoid deadlocks. For example,
477+ * lookupJavaField might need to wait for the reachability handler to be finished that actually
478+ * triggered the re-scanning.
479+ *
480+ * In the (legacy) Feature.duringAnalysis state, the executor is not running and we must not
481+ * schedule new tasks, because that would be treated as "the analysis has not finsihed yet". So
482+ * in that case we execute the task directly.
483+ */
484+ private void maybeRunInExecutor (CompletionExecutor .DebugContextRunnable task ) {
485+ if (bb .executorIsStarted ()) {
486+ bb .postTask (task );
487+ } else {
488+ task .run (null );
489+ }
490+ }
491+
492+ public void rescanRoot (Field reflectionField ) {
471493 if (skipScanning ()) {
472- return null ;
494+ return ;
473495 }
474- AnalysisType type = metaAccess .lookupJavaType (reflectionField .getDeclaringClass ());
475- if (type .isReachable ()) {
476- AnalysisField field = metaAccess .lookupJavaField (reflectionField );
477- JavaConstant fieldValue = readHostedFieldValue (field , null ).get ();
478- TypeData typeData = field .getDeclaringClass ().getOrComputeData ();
479- AnalysisFuture <JavaConstant > fieldTask = patchStaticField (typeData , field , fieldValue , OtherReason .RESCAN , null );
480- if (field .isRead () || field .isFolded ()) {
481- Object root = asObject (fieldTask .ensureDone ());
482- rescanCollectionElements (root );
483- return root ;
496+
497+ maybeRunInExecutor (unused -> {
498+ AnalysisType type = metaAccess .lookupJavaType (reflectionField .getDeclaringClass ());
499+ if (type .isReachable ()) {
500+ AnalysisField field = metaAccess .lookupJavaField (reflectionField );
501+ JavaConstant fieldValue = readHostedFieldValue (field , null ).get ();
502+ TypeData typeData = field .getDeclaringClass ().getOrComputeData ();
503+ AnalysisFuture <JavaConstant > fieldTask = patchStaticField (typeData , field , fieldValue , OtherReason .RESCAN , null );
504+ if (field .isRead () || field .isFolded ()) {
505+ Object root = asObject (fieldTask .ensureDone ());
506+ rescanCollectionElements (root );
507+ }
484508 }
485- }
486- return null ;
509+ });
487510 }
488511
489512 public void rescanField (Object receiver , Field reflectionField ) {
490513 if (skipScanning ()) {
491514 return ;
492515 }
493- AnalysisType type = metaAccess .lookupJavaType (reflectionField .getDeclaringClass ());
494- if (type .isReachable ()) {
495- AnalysisField field = metaAccess .lookupJavaField (reflectionField );
496- assert !field .isStatic ();
497- JavaConstant receiverConstant = asConstant (receiver );
498- Optional <JavaConstant > replaced = maybeReplace (receiverConstant , OtherReason .RESCAN );
499- if (replaced .isPresent ()) {
500- if (replaced .get ().isNull ()) {
501- /* There was some problem during replacement, bailout. */
502- return ;
516+ maybeRunInExecutor (unused -> {
517+ AnalysisType type = metaAccess .lookupJavaType (reflectionField .getDeclaringClass ());
518+ if (type .isReachable ()) {
519+ AnalysisField field = metaAccess .lookupJavaField (reflectionField );
520+ assert !field .isStatic ();
521+ JavaConstant receiverConstant = asConstant (receiver );
522+ Optional <JavaConstant > replaced = maybeReplace (receiverConstant , OtherReason .RESCAN );
523+ if (replaced .isPresent ()) {
524+ if (replaced .get ().isNull ()) {
525+ /* There was some problem during replacement, bailout. */
526+ return ;
527+ }
528+ receiverConstant = replaced .get ();
503529 }
504- receiverConstant = replaced .get ();
505- }
506- JavaConstant fieldValue = readHostedFieldValue (field , universe .toHosted (receiverConstant )).get ();
507- if (fieldValue != null ) {
508- ImageHeapInstance receiverObject = (ImageHeapInstance ) toImageHeapObject (receiverConstant );
509- AnalysisFuture <JavaConstant > fieldTask = patchInstanceField (receiverObject , field , fieldValue , OtherReason .RESCAN , null );
510- if (field .isRead () || field .isFolded ()) {
511- rescanCollectionElements (asObject (fieldTask .ensureDone ()));
530+ JavaConstant fieldValue = readHostedFieldValue (field , universe .toHosted (receiverConstant )).get ();
531+ if (fieldValue != null ) {
532+ ImageHeapInstance receiverObject = (ImageHeapInstance ) toImageHeapObject (receiverConstant );
533+ AnalysisFuture <JavaConstant > fieldTask = patchInstanceField (receiverObject , field , fieldValue , OtherReason .RESCAN , null );
534+ if (field .isRead () || field .isFolded ()) {
535+ rescanCollectionElements (asObject (fieldTask .ensureDone ()));
536+ }
512537 }
513538 }
514- }
539+ });
515540 }
516541
517542 protected AnalysisFuture <JavaConstant > patchStaticField (TypeData typeData , AnalysisField field , JavaConstant fieldValue , ScanReason reason , Consumer <ScanReason > onAnalysisModified ) {
@@ -540,7 +565,6 @@ protected AnalysisFuture<JavaConstant> patchInstanceField(ImageHeapInstance rece
540565 */
541566 public void rescanObject (Object object ) {
542567 rescanObject (object , OtherReason .RESCAN );
543- rescanCollectionElements (object );
544568 }
545569
546570 /**
@@ -553,7 +577,11 @@ public void rescanObject(Object object, ScanReason reason) {
553577 if (object == null ) {
554578 return ;
555579 }
556- doScan (asConstant (object ), reason );
580+
581+ maybeRunInExecutor (unused -> {
582+ doScan (asConstant (object ), reason );
583+ rescanCollectionElements (object );
584+ });
557585 }
558586
559587 private void rescanCollectionElements (Object object ) {
0 commit comments