Skip to content

Commit

Permalink
[GR-59782] Ensure vtables are calculated for all types when using ope…
Browse files Browse the repository at this point in the history
…n world analysis.

PullRequest: graal/19323
  • Loading branch information
teshull committed Nov 22, 2024
2 parents e301976 + 3e79a4e commit bcd53e5
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,10 @@ public AnalysisMethod findConstructor(Signature signature) {
return null;
}

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

public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
Objects.requireNonNull(dispatchTableMethods);
return dispatchTableMethods;
Expand Down Expand Up @@ -1403,6 +1407,7 @@ public Set<AnalysisMethod> getOrCalculateOpenTypeWorldDispatchTableMethods() {
}
try {
AnalysisMethod aMethod = universe.lookup(m);
assert aMethod != null : m;
resultSet.add(aMethod);
} catch (UnsupportedFeatureException t) {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ public void registerWrittenDynamicHub(DynamicHub hub, AnalysisUniverse aUniverse
assert hType.getWrapped().isReachable() : "All installed hubs should be reachable " + hType;

int vtableLength = Array.getLength(vTable);
if (!VTableBuilder.needsDispatchTable(hType) && !hType.isArray()) {
if (VTableBuilder.hasEmptyDispatchTable(hType)) {
assert vtableLength == 0 : hType;
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@
public final class VTableBuilder {
private final HostedUniverse hUniverse;
private final HostedMetaAccess hMetaAccess;
private final boolean closedTypeWorldHubLayout;
private final boolean imageLayer = ImageLayerBuildingSupport.buildingImageLayer();

private final OpenTypeWorldHubLayoutUtils openHubUtils;

private VTableBuilder(HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) {
this.hUniverse = hUniverse;
this.hMetaAccess = hMetaAccess;
closedTypeWorldHubLayout = SubstrateOptions.useClosedTypeWorldHubLayout();
openHubUtils = SubstrateOptions.useClosedTypeWorldHubLayout() ? null : new OpenTypeWorldHubLayoutUtils(hUniverse);
}

public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) {
Expand All @@ -66,8 +66,67 @@ public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaA
}
}

private static boolean shouldIncludeType(HostedType type) {
return type.getWrapped().isReachable() || type.getWrapped().isTrackedAcrossLayers();
private static class OpenTypeWorldHubLayoutUtils {
private final boolean closedTypeWorld;
private final boolean registerTrackedTypes;
private final boolean registerAllTypes;
private final boolean filterVTableMethods;

OpenTypeWorldHubLayoutUtils(HostedUniverse hUniverse) {
closedTypeWorld = SubstrateOptions.useClosedTypeWorld();

/*
* We only filter vtable methods when we are building a non-layered image under the
* closed type world assumption. For layered builds, we must keep all vtable methods to
* ensure consistency across layers.
*
* With the closed type world assumption we can filter out methods that we know will be
* simplified to direct calls (i.e., when at most a single implementation exists for the
* given target). See generateDispatchTable for the use of this filter.
*/
filterVTableMethods = closedTypeWorld && !ImageLayerBuildingSupport.buildingImageLayer();

registerTrackedTypes = hUniverse.hostVM().enableTrackAcrossLayers();
registerAllTypes = ImageLayerBuildingSupport.buildingApplicationLayer();
assert !(registerTrackedTypes && registerAllTypes) : "We expect these flags to be mutually exclusive";
assert (registerTrackedTypes || registerAllTypes) == ImageLayerBuildingSupport.buildingImageLayer() : "Type information must be registered during layered image builds";
}

private boolean shouldIncludeType(HostedType type) {
if (closedTypeWorld) {
if (type.getWrapped().isInBaseLayer()) {
/*
* This check will be later removed.
*
* GR-60010 - We are currently loading base analysis types too late.
*/
return type.getWrapped().isOpenTypeWorldDispatchTableMethodsCalculated();
}

/*
* When using the closed type world we know calls to unreachable types will be
* removed via graph strengthening. It is also always possible to see base layer
* types.
*/
return type.getWrapped().isReachable() || type.getWrapped().isInBaseLayer();
} else {
/*
* When using the open type world we are conservative and calculate metadata for all
* types seen during analysis.
*/
return type.getWrapped().isOpenTypeWorldDispatchTableMethodsCalculated();
}
}

private boolean shouldRegisterType(HostedType type) {
if (registerAllTypes) {
return true;
}
if (registerTrackedTypes && type.getWrapped().isTrackedAcrossLayers()) {
return true;
}
return false;
}
}

private boolean verifyOpenTypeWorldDispatchTables() {
Expand Down Expand Up @@ -124,7 +183,7 @@ private List<HostedMethod> generateITable(HostedType type) {

private List<HostedMethod> generateDispatchTable(HostedType type, int startingIndex) {
Predicate<HostedMethod> includeMethod;
if (closedTypeWorldHubLayout) {
if (openHubUtils.filterVTableMethods) {
// include only methods which will be indirect calls
includeMethod = m -> m.implementations.length > 1 || m.wrapped.isVirtualRootMethod();
} else {
Expand All @@ -141,7 +200,7 @@ private List<HostedMethod> generateDispatchTable(HostedType type, int startingIn
index++;
}

if (imageLayer) {
if (openHubUtils.shouldRegisterType(type)) {
LayeredDispatchTableSupport.singleton().registerDeclaredDispatchInfo(type, table);
}

Expand Down Expand Up @@ -209,13 +268,13 @@ private void generateOpenTypeWorldDispatchTable(HostedInstanceClass type, Map<Ho
type.openTypeWorldDispatchTables[i] = targetMethod;
}

if (imageLayer) {
if (openHubUtils.shouldRegisterType(type)) {
LayeredDispatchTableSupport.singleton().registerNonArrayDispatchTable(type, validTarget);
}
}

for (HostedType subType : type.subTypes) {
if (subType instanceof HostedInstanceClass instanceClass && shouldIncludeType(subType)) {
if (subType instanceof HostedInstanceClass instanceClass && openHubUtils.shouldIncludeType(subType)) {
generateOpenTypeWorldDispatchTable(instanceClass, dispatchTablesMap, invalidDispatchTableEntryHandler);
}
}
Expand All @@ -229,7 +288,7 @@ private void buildOpenTypeWorldDispatchTables() {
* Each interface has its own dispatch table. These can be directly determined via
* looking at their declared methods.
*/
if (type.isInterface() && shouldIncludeType(type)) {
if (type.isInterface() && openHubUtils.shouldIncludeType(type)) {
dispatchTablesMap.put(type, generateITable(type));
}
}
Expand All @@ -240,25 +299,29 @@ private void buildOpenTypeWorldDispatchTables() {
int[] emptyITableOffsets = new int[0];
var objectType = hUniverse.getObjectClass();
for (HostedType type : hUniverse.getTypes()) {
if (type.isArray() && shouldIncludeType(type)) {
if (type.isArray() && openHubUtils.shouldIncludeType(type)) {
type.openTypeWorldDispatchTables = objectType.openTypeWorldDispatchTables;
type.openTypeWorldDispatchTableSlotTargets = objectType.openTypeWorldDispatchTableSlotTargets;
type.itableStartingOffsets = objectType.itableStartingOffsets;
if (imageLayer) {
if (openHubUtils.shouldRegisterType(type)) {
LayeredDispatchTableSupport.singleton().registerArrayDispatchTable(type, objectType);
}
}
if (type.openTypeWorldDispatchTables == null) {
assert !needsDispatchTable(type) : type;
assert !openHubUtils.shouldIncludeType(type) || hasEmptyDispatchTable(type) : type;
type.openTypeWorldDispatchTables = HostedMethod.EMPTY_ARRAY;
type.openTypeWorldDispatchTableSlotTargets = HostedMethod.EMPTY_ARRAY;
type.itableStartingOffsets = emptyITableOffsets;
}
}
}

public static boolean needsDispatchTable(HostedType type) {
return shouldIncludeType(type) && !(type.isInterface() || type.isPrimitive() || type.isAbstract());
public static boolean hasEmptyDispatchTable(HostedType type) {
/*
* Note that array types are by definition abstract, i.e., if type.isArray() is true then
* type.isAbstract() is true.
*/
return (type.isInterface() || type.isPrimitive() || type.isAbstract()) && !type.isArray();
}

private void buildClosedTypeWorldVTables() {
Expand Down

0 comments on commit bcd53e5

Please sign in to comment.