Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) {
PointstoGraphBuilderPlugins.registerSystemPlugins(plugins.getInvocationPlugins());
PointstoGraphBuilderPlugins.registerObjectPlugins(plugins.getInvocationPlugins());
}
bigbang.markInitializationFinished();
}

private String getAnalysisName(String entryClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public abstract class AbstractAnalysisEngine implements BigBang {
protected final ClassInclusionPolicy classInclusionPolicy;
private static final ResolvedJavaMethod[] NO_METHODS = new ResolvedJavaMethod[]{};
private static final ResolvedJavaField[] NO_FIELDS = new ResolvedJavaField[]{};
private volatile boolean initialized = false;

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

@Override
public void markInitializationFinished() {
assert !initialized;

initialized = true;
universe.notifyBigBangInitialized();
}

@Override
public boolean isInitialized() {
return initialized;
}

@Override
public void cleanupAfterAnalysis() {
universe.getTypes().forEach(AnalysisType::cleanupAfterAnalysis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ default void onTypeReachable(AnalysisType type) {

void initializeMetaData(AnalysisType type);

void markInitializationFinished();

boolean isInitialized();

/**
* Callback executed after the analysis finished. The cleanupAfterAnalysis is executed after the
* universe builder, which can be too late for some tasks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ public TypeFlow<?> getTypeFlow() {
@SuppressWarnings("try")
@Override
public boolean finish() throws InterruptedException {
assert isInitialized();
try (Indent indent = debug.logAndIndent("starting analysis in BigBang.finish")) {
boolean didSomeWork = false;
do {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -171,7 +170,6 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav

private final AnalysisType[] interfaces;
private AnalysisMethod[] declaredMethods;
private Set<AnalysisMethod> dispatchTableMethods;

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

public boolean isOpenTypeWorldDispatchTableMethodsCalculated() {
return dispatchTableMethods != null;
}

public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
Objects.requireNonNull(dispatchTableMethods);
return dispatchTableMethods;
}

/*
* Calculates all methods in this class which should be included in its dispatch table.
*/
public Set<AnalysisMethod> getOrCalculateOpenTypeWorldDispatchTableMethods() {
if (dispatchTableMethods != null) {
return dispatchTableMethods;
}
if (isPrimitive()) {
dispatchTableMethods = Set.of();
return dispatchTableMethods;
}
if (getWrapped() instanceof BaseLayerType) {
// GR-58587 implement proper support.
dispatchTableMethods = Set.of();
return dispatchTableMethods;
}

var resultSet = new HashSet<AnalysisMethod>();
for (ResolvedJavaMethod m : getWrapped().getDeclaredMethods(false)) {
assert !m.isConstructor() : Assertions.errorMessage("Unexpected constructor", m);
if (m.isStatic()) {
/* Only looking at member methods */
continue;
}
try {
AnalysisMethod aMethod = universe.lookup(m);
assert aMethod != null : m;
resultSet.add(aMethod);
} catch (UnsupportedFeatureException t) {
/*
* Methods which are deleted or not available on this platform will throw an error
* during lookup - ignore and continue execution
*
* Note it is not simple to create a check to determine whether calling
* universe#lookup will trigger an error by creating an analysis object for a type
* not supported on this platform, as creating a method requires, in addition to the
* types of its return type and parameters, all of the super types of its return and
* parameters to be created as well.
*/
}
}

// ensure result is fully visible across threads
VarHandle.storeStoreFence();
dispatchTableMethods = resultSet;
return dispatchTableMethods;
}

@Override
public AnalysisMethod findMethod(String name, Signature signature) {
for (AnalysisMethod method : getDeclaredMethods(false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;

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

private Function<Object, Object>[] objectReplacers;
private Function<Object, ImageHeapConstant>[] objectToConstantReplacers;
private Consumer<AnalysisType>[] onTypeCreatedCallbacks;

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

/*
* Trigger type creation callbacks. Note this will run in parallel with other threads
* being able to retrieve this AnalysisType from {@code types}.
*/
runOnTypeCreatedCallbacks(newValue);

return newValue;

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

public void registerOnTypeCreatedCallback(Consumer<AnalysisType> consumer) {
assert consumer != null;
assert !bb.isInitialized() : "too late to add a callback";
onTypeCreatedCallbacks = Arrays.copyOf(onTypeCreatedCallbacks, onTypeCreatedCallbacks.length + 1);
onTypeCreatedCallbacks[onTypeCreatedCallbacks.length - 1] = consumer;
}

public void registerFeatureSubstitution(SubstitutionProcessor substitution) {
SubstitutionProcessor[] subs = featureSubstitutions;
subs = Arrays.copyOf(subs, subs.length + 1);
Expand Down Expand Up @@ -699,6 +715,40 @@ private Object replaceObject0(Object source, boolean allowObjectToConstantReplac
return ihc == null ? destination : ihc;
}

public void notifyBigBangInitialized() {
assert bb.isInitialized();

/*
* It is possible for types to be created before all typeCreationCallbacks are installed.
* Hence, we trigger the typeCreationCallbacks for all types created prior to the completion
* of big bang initialization at this point.
*/
for (var obj : types.values().toArray()) {
/*
* Nominally the map values are of type object and can hold a thread object while an
* AnalysisType is being created. However, this method is called when all values will be
* of type AnalysisType.
*/
AnalysisType aType = (AnalysisType) obj;
runOnTypeCreatedCallbacks(aType);
}
}

private void runOnTypeCreatedCallbacks(AnalysisType type) {
if (bb == null || !bb.isInitialized()) {
/*
* Until the big bang is initialized, it is possible for more callbacks to be
* registered. Hence, these hooks are run on all types created before big bang
* initialization via {@code notifyBigBangInitialized}
*/
return;
}

for (var callback : onTypeCreatedCallbacks) {
bb.postTask((t) -> callback.accept(type));
}
}

public void registerOverrideReachabilityNotification(AnalysisMethod declaredMethod, MethodOverrideReachableNotification notification) {
methodOverrideReachableNotifications.computeIfAbsent(declaredMethod, m -> ConcurrentHashMap.newKeySet()).add(notification);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ public void markMethodInvoked(ReachabilityAnalysisMethod method, Object reason)

@Override
public boolean finish() throws InterruptedException {
assert isInitialized();
do {
runReachability();
assert executor.getPostedOperations() == 0 : executor.getPostedOperations();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,15 @@ public void registerObjectToConstantReplacer(Function<Object, ImageHeapConstant>
getUniverse().registerObjectToConstantReplacer(replacer);
}

/**
* Register a callback which will execute once for each analysis type created. Note this
* callback runs when the created AnalysisType is already visible within the analysis
* universe.
*/
public void registerOnTypeCreatedCallback(Consumer<AnalysisType> callback) {
getUniverse().registerOnTypeCreatedCallback(callback);
}

/**
* Register a callback that is executed when an object of the specified type or any of its
* subtypes is marked as reachable. The callback is executed before the object is added to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public int getInstalledLayerNum(ResolvedJavaField field) {
} else {
AnalysisField aField = (AnalysisField) field;
return switch (LayeredStaticFieldSupport.singleton().getAssignmentStatus(aField)) {
case UNDECIDED -> getCurrentLayerNumber();
case UNSPECIFIED -> getCurrentLayerNumber();
case PRIOR_LAYER -> LayeredStaticFieldSupport.singleton().getPriorInstalledLayerNum(aField);
case APP_LAYER_REQUESTED, APP_LAYER_DEFERRED -> LayeredStaticFieldSupport.getAppLayerNumber();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,9 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De
bb.getHostVM().getClassInitializationSupport().sealConfiguration();
if (ImageLayerBuildingSupport.buildingImageLayer()) {
ImageSingletons.lookup(LoadImageSingletonFeature.class).processRegisteredSingletons(aUniverse);
}
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
HostedImageLayerBuildingSupport.singleton().getWriter().initializeExternalValues();
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
HostedImageLayerBuildingSupport.singleton().getWriter().initializeExternalValues();
}
}
}

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

performSnippetGraphAnalysis(bb, aReplacements, options, Function.identity());
}

bb.markInitializationFinished();
}

/**
Expand Down
Loading