Skip to content

Commit a5b55f9

Browse files
committed
add onTypeCreated analysis callback
1 parent 55bb550 commit a5b55f9

File tree

15 files changed

+244
-108
lines changed

15 files changed

+244
-108
lines changed

substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) {
214214
PointstoGraphBuilderPlugins.registerSystemPlugins(plugins.getInvocationPlugins());
215215
PointstoGraphBuilderPlugins.registerObjectPlugins(plugins.getInvocationPlugins());
216216
}
217+
bigbang.markInitializationFinished();
217218
}
218219

219220
private String getAnalysisName(String entryClass) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public abstract class AbstractAnalysisEngine implements BigBang {
103103
protected final ClassInclusionPolicy classInclusionPolicy;
104104
private static final ResolvedJavaMethod[] NO_METHODS = new ResolvedJavaMethod[]{};
105105
private static final ResolvedJavaField[] NO_FIELDS = new ResolvedJavaField[]{};
106+
private volatile boolean initialized = false;
106107

107108
@SuppressWarnings("this-escape")
108109
public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider,
@@ -226,6 +227,19 @@ private boolean analysisModified() {
226227
return analysisModified;
227228
}
228229

230+
@Override
231+
public void markInitializationFinished() {
232+
assert !initialized;
233+
234+
initialized = true;
235+
universe.notifyBigBangInitialized();
236+
}
237+
238+
@Override
239+
public boolean isInitialized() {
240+
return initialized;
241+
}
242+
229243
@Override
230244
public void cleanupAfterAnalysis() {
231245
universe.getTypes().forEach(AnalysisType::cleanupAfterAnalysis);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ default void onTypeReachable(AnalysisType type) {
128128

129129
void initializeMetaData(AnalysisType type);
130130

131+
void markInitializationFinished();
132+
133+
boolean isInitialized();
134+
131135
/**
132136
* Callback executed after the analysis finished. The cleanupAfterAnalysis is executed after the
133137
* universe builder, which can be too late for some tasks.

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ public TypeFlow<?> getTypeFlow() {
662662
@SuppressWarnings("try")
663663
@Override
664664
public boolean finish() throws InterruptedException {
665+
assert isInitialized();
665666
try (Indent indent = debug.logAndIndent("starting analysis in BigBang.finish")) {
666667
boolean didSomeWork = false;
667668
do {

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

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.util.Collection;
3131
import java.util.HashSet;
3232
import java.util.List;
33-
import java.util.Objects;
3433
import java.util.Set;
3534
import java.util.concurrent.ConcurrentHashMap;
3635
import java.util.concurrent.ConcurrentMap;
@@ -171,7 +170,6 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav
171170

172171
private final AnalysisType[] interfaces;
173172
private AnalysisMethod[] declaredMethods;
174-
private Set<AnalysisMethod> dispatchTableMethods;
175173

176174
/* isArray is an expensive operation so we eagerly compute it */
177175
private final boolean isArray;
@@ -1389,63 +1387,6 @@ public AnalysisMethod[] getDeclaredConstructors(boolean forceLink) {
13891387
return universe.lookup(wrapped.getDeclaredConstructors(forceLink));
13901388
}
13911389

1392-
public boolean isOpenTypeWorldDispatchTableMethodsCalculated() {
1393-
return dispatchTableMethods != null;
1394-
}
1395-
1396-
public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
1397-
Objects.requireNonNull(dispatchTableMethods);
1398-
return dispatchTableMethods;
1399-
}
1400-
1401-
/*
1402-
* Calculates all methods in this class which should be included in its dispatch table.
1403-
*/
1404-
public Set<AnalysisMethod> getOrCalculateOpenTypeWorldDispatchTableMethods() {
1405-
if (dispatchTableMethods != null) {
1406-
return dispatchTableMethods;
1407-
}
1408-
if (isPrimitive()) {
1409-
dispatchTableMethods = Set.of();
1410-
return dispatchTableMethods;
1411-
}
1412-
if (getWrapped() instanceof BaseLayerType) {
1413-
// GR-58587 implement proper support.
1414-
dispatchTableMethods = Set.of();
1415-
return dispatchTableMethods;
1416-
}
1417-
1418-
var resultSet = new HashSet<AnalysisMethod>();
1419-
for (ResolvedJavaMethod m : getWrapped().getDeclaredMethods(false)) {
1420-
assert !m.isConstructor() : Assertions.errorMessage("Unexpected constructor", m);
1421-
if (m.isStatic()) {
1422-
/* Only looking at member methods */
1423-
continue;
1424-
}
1425-
try {
1426-
AnalysisMethod aMethod = universe.lookup(m);
1427-
assert aMethod != null : m;
1428-
resultSet.add(aMethod);
1429-
} catch (UnsupportedFeatureException t) {
1430-
/*
1431-
* Methods which are deleted or not available on this platform will throw an error
1432-
* during lookup - ignore and continue execution
1433-
*
1434-
* Note it is not simple to create a check to determine whether calling
1435-
* universe#lookup will trigger an error by creating an analysis object for a type
1436-
* not supported on this platform, as creating a method requires, in addition to the
1437-
* types of its return type and parameters, all of the super types of its return and
1438-
* parameters to be created as well.
1439-
*/
1440-
}
1441-
}
1442-
1443-
// ensure result is fully visible across threads
1444-
VarHandle.storeStoreFence();
1445-
dispatchTableMethods = resultSet;
1446-
return dispatchTableMethods;
1447-
}
1448-
14491390
@Override
14501391
public AnalysisMethod findMethod(String name, Signature signature) {
14511392
for (AnalysisMethod method : getDeclaredMethods(false)) {

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.concurrent.ConcurrentHashMap;
3535
import java.util.concurrent.ConcurrentMap;
3636
import java.util.concurrent.atomic.AtomicInteger;
37+
import java.util.function.Consumer;
3738
import java.util.function.Function;
3839

3940
import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess;
@@ -106,6 +107,7 @@ public class AnalysisUniverse implements Universe {
106107

107108
private Function<Object, Object>[] objectReplacers;
108109
private Function<Object, ImageHeapConstant>[] objectToConstantReplacers;
110+
private Consumer<AnalysisType>[] onTypeCreatedCallbacks;
109111

110112
private SubstitutionProcessor[] featureSubstitutions;
111113
private SubstitutionProcessor[] featureNativeSubstitutions;
@@ -147,6 +149,7 @@ public AnalysisUniverse(HostVM hostVM, JavaKind wordKind, AnalysisPolicy analysi
147149
sealed = false;
148150
objectReplacers = (Function<Object, Object>[]) new Function<?, ?>[0];
149151
objectToConstantReplacers = (Function<Object, ImageHeapConstant>[]) new Function<?, ?>[0];
152+
onTypeCreatedCallbacks = (Consumer<AnalysisType>[]) new Consumer<?>[0];
150153
featureSubstitutions = new SubstitutionProcessor[0];
151154
featureNativeSubstitutions = new SubstitutionProcessor[0];
152155
unsafeAccessedStaticFields = analysisPolicy.useConservativeUnsafeAccess() ? null : new ConcurrentHashMap<>();
@@ -327,6 +330,12 @@ private AnalysisType createType(ResolvedJavaType type) {
327330
assert oldValue == claim : oldValue + " != " + claim;
328331
claim = null;
329332

333+
/*
334+
* Trigger type creation callbacks. Note this will run in parallel with other threads
335+
* being able to retrieve this AnalysisType from {@code types}.
336+
*/
337+
runOnTypeCreatedCallbacks(newValue);
338+
330339
return newValue;
331340

332341
} finally {
@@ -621,6 +630,13 @@ public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant>
621630
objectToConstantReplacers[objectToConstantReplacers.length - 1] = replacer;
622631
}
623632

633+
public void registerOnTypeCreatedCallback(Consumer<AnalysisType> consumer) {
634+
assert consumer != null;
635+
assert !bb.isInitialized() : "too late to add a callback";
636+
onTypeCreatedCallbacks = Arrays.copyOf(onTypeCreatedCallbacks, onTypeCreatedCallbacks.length + 1);
637+
onTypeCreatedCallbacks[onTypeCreatedCallbacks.length - 1] = consumer;
638+
}
639+
624640
public void registerFeatureSubstitution(SubstitutionProcessor substitution) {
625641
SubstitutionProcessor[] subs = featureSubstitutions;
626642
subs = Arrays.copyOf(subs, subs.length + 1);
@@ -699,6 +715,40 @@ private Object replaceObject0(Object source, boolean allowObjectToConstantReplac
699715
return ihc == null ? destination : ihc;
700716
}
701717

718+
public void notifyBigBangInitialized() {
719+
assert bb.isInitialized();
720+
721+
/*
722+
* It is possible for types to be created before all typeCreationCallbacks are installed.
723+
* Hence, we trigger the typeCreationCallbacks for all types created prior to the completion
724+
* of big bang initialization at this point.
725+
*/
726+
for (var obj : types.values().toArray()) {
727+
/*
728+
* Nominally the map values are of type object and can hold a thread object while an
729+
* AnalysisType is being created. However, this method is called when all values will be
730+
* of type AnalysisType.
731+
*/
732+
AnalysisType aType = (AnalysisType) obj;
733+
runOnTypeCreatedCallbacks(aType);
734+
}
735+
}
736+
737+
private void runOnTypeCreatedCallbacks(AnalysisType type) {
738+
if (bb == null || !bb.isInitialized()) {
739+
/*
740+
* Until the big bang is initialized, it is possible for more callbacks to be
741+
* registered. Hence, these hooks are run on all types created before big bang
742+
* initialization via {@code notifyBigBangInitialized}
743+
*/
744+
return;
745+
}
746+
747+
for (var callback : onTypeCreatedCallbacks) {
748+
bb.postTask((t) -> callback.accept(type));
749+
}
750+
}
751+
702752
public void registerOverrideReachabilityNotification(AnalysisMethod declaredMethod, MethodOverrideReachableNotification notification) {
703753
methodOverrideReachableNotifications.computeIfAbsent(declaredMethod, m -> ConcurrentHashMap.newKeySet()).add(notification);
704754
}

substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ public void markMethodInvoked(ReachabilityAnalysisMethod method, Object reason)
284284

285285
@Override
286286
public boolean finish() throws InterruptedException {
287+
assert isInitialized();
287288
do {
288289
runReachability();
289290
assert executor.getPostedOperations() == 0 : executor.getPostedOperations();

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,15 @@ public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant>
312312
getUniverse().registerObjectToConstantReplacer(replacer);
313313
}
314314

315+
/**
316+
* Register a callback which will execute once for each analysis type created. Note this
317+
* callback runs when the created AnalysisType is already visible within the analysis
318+
* universe.
319+
*/
320+
public void registerOnTypeCreatedCallback(Consumer<AnalysisType> callback) {
321+
getUniverse().registerOnTypeCreatedCallback(callback);
322+
}
323+
315324
/**
316325
* Register a callback that is executed when an object of the specified type or any of its
317326
* subtypes is marked as reachable. The callback is executed before the object is added to

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public int getInstalledLayerNum(ResolvedJavaField field) {
136136
} else {
137137
AnalysisField aField = (AnalysisField) field;
138138
return switch (LayeredStaticFieldSupport.singleton().getAssignmentStatus(aField)) {
139-
case UNDECIDED -> getCurrentLayerNumber();
139+
case UNSPECIFIED -> getCurrentLayerNumber();
140140
case PRIOR_LAYER -> LayeredStaticFieldSupport.singleton().getPriorInstalledLayerNum(aField);
141141
case APP_LAYER_REQUESTED, APP_LAYER_DEFERRED -> LayeredStaticFieldSupport.getAppLayerNumber();
142142
};

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,9 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De
817817
bb.getHostVM().getClassInitializationSupport().sealConfiguration();
818818
if (ImageLayerBuildingSupport.buildingImageLayer()) {
819819
ImageSingletons.lookup(LoadImageSingletonFeature.class).processRegisteredSingletons(aUniverse);
820-
}
821-
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
822-
HostedImageLayerBuildingSupport.singleton().getWriter().initializeExternalValues();
820+
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
821+
HostedImageLayerBuildingSupport.singleton().getWriter().initializeExternalValues();
822+
}
823823
}
824824
}
825825

@@ -1252,6 +1252,8 @@ public static void initializeBigBang(Inflation bb, OptionValues options, Feature
12521252

12531253
performSnippetGraphAnalysis(bb, aReplacements, options, Function.identity());
12541254
}
1255+
1256+
bb.markInitializationFinished();
12551257
}
12561258

12571259
/**

0 commit comments

Comments
 (0)