Skip to content

Commit 1a8bb87

Browse files
committed
Delay reachability handlers callback execution until analysis is started.
1 parent 0c69fe5 commit 1a8bb87

File tree

6 files changed

+60
-27
lines changed

6 files changed

+60
-27
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -130,33 +130,36 @@ public void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) {
130130
public void onFieldRead(AnalysisField field) {
131131
assert field.isRead() : field;
132132
/* Check if the value is available before accessing it. */
133-
AnalysisType declaringClass = field.getDeclaringClass();
134133
if (field.isStatic()) {
135-
FieldScan reason = new FieldScan(field);
136-
if (!field.installableInLayer()) {
137-
/*
138-
* For non-installable static fields we do not scan the constant value, but instead
139-
* inject its type state in the field flow. This will be propagated to any
140-
* corresponding field loads.
141-
*
142-
* GR-52421: the field state needs to be serialized from the base layer analysis
143-
*/
144-
if (field.getStorageKind().isObject()) {
145-
bb.injectFieldTypes(field, List.of(field.getType()), true);
146-
} else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive()) {
147-
((PointsToAnalysisField) field).saturatePrimitiveField();
148-
}
149-
} else if (isValueAvailable(field)) {
150-
JavaConstant fieldValue = readStaticFieldValue(field);
151-
if (fieldValue instanceof ImageHeapConstant imageHeapConstant && field.isFinal()) {
152-
AnalysisError.guarantee(imageHeapConstant.getOrigin() != null, "The origin of the constant %s should have been registered before", imageHeapConstant);
153-
}
154-
markReachable(fieldValue, reason);
155-
notifyAnalysis(field, null, fieldValue, reason);
156-
}
134+
postTask(() -> onStaticFieldRead(field));
157135
} else {
158136
/* Trigger field scanning for the already processed objects. */
159-
postTask(() -> onInstanceFieldRead(field, declaringClass));
137+
postTask(() -> onInstanceFieldRead(field, field.getDeclaringClass()));
138+
}
139+
}
140+
141+
private void onStaticFieldRead(AnalysisField field) {
142+
FieldScan reason = new FieldScan(field);
143+
if (!field.installableInLayer()) {
144+
/*
145+
* For non-installable static fields we do not scan the constant value, but instead
146+
* inject its type state in the field flow. This will be propagated to any corresponding
147+
* field loads.
148+
*
149+
* GR-52421: the field state needs to be serialized from the base layer analysis
150+
*/
151+
if (field.getStorageKind().isObject()) {
152+
bb.injectFieldTypes(field, List.of(field.getType()), true);
153+
} else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive()) {
154+
((PointsToAnalysisField) field).saturatePrimitiveField();
155+
}
156+
} else if (isValueAvailable(field)) {
157+
JavaConstant fieldValue = readStaticFieldValue(field);
158+
if (fieldValue instanceof ImageHeapConstant imageHeapConstant && field.isFinal()) {
159+
AnalysisError.guarantee(imageHeapConstant.getOrigin() != null, "The origin of the constant %s should have been registered before", imageHeapConstant);
160+
}
161+
markReachable(fieldValue, reason);
162+
notifyAnalysis(field, null, fieldValue, reason);
160163
}
161164
}
162165

@@ -890,9 +893,10 @@ protected AnalysisField lookupJavaField(String className, String fieldName) {
890893
*
891894
* In the (legacy) Feature.duringAnalysis state, the executor is not running and we must not
892895
* schedule new tasks, because that would be treated as "the analysis has not finished yet". So
893-
* in that case we execute the task directly.
896+
* in that case we execute the task directly. A task that runs in the Feature.duringAnalysis
897+
* stage and modifies the analysis state should itself trigger an additional analysis iteration.
894898
*/
895-
private void maybeRunInExecutor(CompletionExecutor.DebugContextRunnable task) {
899+
protected void maybeRunInExecutor(CompletionExecutor.DebugContextRunnable task) {
896900
if (bb.executorIsStarted()) {
897901
bb.postTask(task);
898902
} else {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,9 @@ public void setConcurrentAnalysisAccess(DuringAnalysisAccess access) {
787787
}
788788

789789
public DuringAnalysisAccess getConcurrentAnalysisAccess() {
790+
AnalysisError.guarantee(concurrentAnalysisAccess != null, "The requested DuringAnalysisAccess object is not available. " +
791+
"This means that an analysis task is executed too eagerly, before analysis. " +
792+
"Make sure that all analysis tasks are posted to the analysis execution engine.");
790793
return concurrentAnalysisAccess;
791794
}
792795

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildPhaseProvider.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public final class BuildPhaseProvider {
3535

3636
private boolean featureRegistrationFinished;
3737
private boolean setupFinished;
38+
private boolean analysisStarted;
3839
private boolean analysisFinished;
3940
private boolean hostedUniverseBuilt;
4041
private boolean readyForCompilation;
@@ -69,6 +70,14 @@ public static boolean isSetupFinished() {
6970
return ImageSingletons.contains(BuildPhaseProvider.class) && singleton().setupFinished;
7071
}
7172

73+
public static void markAnalysisStarted() {
74+
singleton().analysisStarted = true;
75+
}
76+
77+
public static boolean isAnalysisStarted() {
78+
return ImageSingletons.contains(BuildPhaseProvider.class) && singleton().analysisStarted;
79+
}
80+
7281
public static void markAnalysisFinished() {
7382
singleton().analysisFinished = true;
7483
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,8 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De
838838
*/
839839
HostedImageLayerBuildingSupport.singleton().getLoader().relinkTransformedStaticFinalFieldValues();
840840
}
841+
/* All pre-analysis set-up is done and the fixed-point analysis can start. */
842+
BuildPhaseProvider.markAnalysisStarted();
841843
bb.runAnalysis(debug, (universe) -> {
842844
try (StopTimer t2 = TimerCollection.createTimerAndStart(TimerCollection.Registry.FEATURES)) {
843845
bb.getHostVM().notifyClassReachabilityListener(universe, config);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public AnnotationSubstitutionProcessor getAnnotationSubstitutionProcessor() {
128128

129129
@Override
130130
public void onFieldAccessed(AnalysisField field) {
131-
customTypeFieldHandler.handleField(field);
131+
postTask(() -> customTypeFieldHandler.handleField(field));
132132
}
133133

134134
@Override

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
4141
import com.oracle.graal.pointsto.meta.AnalysisField;
4242
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
43+
import com.oracle.graal.pointsto.util.CompletionExecutor;
44+
import com.oracle.svm.core.BuildPhaseProvider;
4345
import com.oracle.svm.core.hub.DynamicHub;
4446
import com.oracle.svm.hosted.ImageClassLoader;
4547
import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider;
@@ -132,4 +134,17 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason
132134
reflectionSupport.registerHeapDynamicHub(hub, reason);
133135
}
134136
}
137+
138+
@Override
139+
protected void maybeRunInExecutor(CompletionExecutor.DebugContextRunnable task) {
140+
if (BuildPhaseProvider.isAnalysisStarted()) {
141+
super.maybeRunInExecutor(task);
142+
} else {
143+
/*
144+
* Before the analysis is started post all scanning tasks to the executor. They will be
145+
* executed after the analysis starts.
146+
*/
147+
bb.postTask(task);
148+
}
149+
}
135150
}

0 commit comments

Comments
 (0)