Skip to content

Commit 3e79a4e

Browse files
committed
ensure vtables are calculated for all types when using open world analysis.
1 parent c6ebfd2 commit 3e79a4e

File tree

3 files changed

+84
-16
lines changed

3 files changed

+84
-16
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,10 @@ public AnalysisMethod findConstructor(Signature signature) {
13691369
return null;
13701370
}
13711371

1372+
public boolean isOpenTypeWorldDispatchTableMethodsCalculated() {
1373+
return dispatchTableMethods != null;
1374+
}
1375+
13721376
public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
13731377
Objects.requireNonNull(dispatchTableMethods);
13741378
return dispatchTableMethods;
@@ -1403,6 +1407,7 @@ public Set<AnalysisMethod> getOrCalculateOpenTypeWorldDispatchTableMethods() {
14031407
}
14041408
try {
14051409
AnalysisMethod aMethod = universe.lookup(m);
1410+
assert aMethod != null : m;
14061411
resultSet.add(aMethod);
14071412
} catch (UnsupportedFeatureException t) {
14081413
/*

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public void registerWrittenDynamicHub(DynamicHub hub, AnalysisUniverse aUniverse
318318
assert hType.getWrapped().isReachable() : "All installed hubs should be reachable " + hType;
319319

320320
int vtableLength = Array.getLength(vTable);
321-
if (!VTableBuilder.needsDispatchTable(hType) && !hType.isArray()) {
321+
if (VTableBuilder.hasEmptyDispatchTable(hType)) {
322322
assert vtableLength == 0 : hType;
323323
return;
324324
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/VTableBuilder.java

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@
4747
public final class VTableBuilder {
4848
private final HostedUniverse hUniverse;
4949
private final HostedMetaAccess hMetaAccess;
50-
private final boolean closedTypeWorldHubLayout;
51-
private final boolean imageLayer = ImageLayerBuildingSupport.buildingImageLayer();
50+
51+
private final OpenTypeWorldHubLayoutUtils openHubUtils;
5252

5353
private VTableBuilder(HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) {
5454
this.hUniverse = hUniverse;
5555
this.hMetaAccess = hMetaAccess;
56-
closedTypeWorldHubLayout = SubstrateOptions.useClosedTypeWorldHubLayout();
56+
openHubUtils = SubstrateOptions.useClosedTypeWorldHubLayout() ? null : new OpenTypeWorldHubLayoutUtils(hUniverse);
5757
}
5858

5959
public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) {
@@ -66,8 +66,67 @@ public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaA
6666
}
6767
}
6868

69-
private static boolean shouldIncludeType(HostedType type) {
70-
return type.getWrapped().isReachable() || type.getWrapped().isTrackedAcrossLayers();
69+
private static class OpenTypeWorldHubLayoutUtils {
70+
private final boolean closedTypeWorld;
71+
private final boolean registerTrackedTypes;
72+
private final boolean registerAllTypes;
73+
private final boolean filterVTableMethods;
74+
75+
OpenTypeWorldHubLayoutUtils(HostedUniverse hUniverse) {
76+
closedTypeWorld = SubstrateOptions.useClosedTypeWorld();
77+
78+
/*
79+
* We only filter vtable methods when we are building a non-layered image under the
80+
* closed type world assumption. For layered builds, we must keep all vtable methods to
81+
* ensure consistency across layers.
82+
*
83+
* With the closed type world assumption we can filter out methods that we know will be
84+
* simplified to direct calls (i.e., when at most a single implementation exists for the
85+
* given target). See generateDispatchTable for the use of this filter.
86+
*/
87+
filterVTableMethods = closedTypeWorld && !ImageLayerBuildingSupport.buildingImageLayer();
88+
89+
registerTrackedTypes = hUniverse.hostVM().enableTrackAcrossLayers();
90+
registerAllTypes = ImageLayerBuildingSupport.buildingApplicationLayer();
91+
assert !(registerTrackedTypes && registerAllTypes) : "We expect these flags to be mutually exclusive";
92+
assert (registerTrackedTypes || registerAllTypes) == ImageLayerBuildingSupport.buildingImageLayer() : "Type information must be registered during layered image builds";
93+
}
94+
95+
private boolean shouldIncludeType(HostedType type) {
96+
if (closedTypeWorld) {
97+
if (type.getWrapped().isInBaseLayer()) {
98+
/*
99+
* This check will be later removed.
100+
*
101+
* GR-60010 - We are currently loading base analysis types too late.
102+
*/
103+
return type.getWrapped().isOpenTypeWorldDispatchTableMethodsCalculated();
104+
}
105+
106+
/*
107+
* When using the closed type world we know calls to unreachable types will be
108+
* removed via graph strengthening. It is also always possible to see base layer
109+
* types.
110+
*/
111+
return type.getWrapped().isReachable() || type.getWrapped().isInBaseLayer();
112+
} else {
113+
/*
114+
* When using the open type world we are conservative and calculate metadata for all
115+
* types seen during analysis.
116+
*/
117+
return type.getWrapped().isOpenTypeWorldDispatchTableMethodsCalculated();
118+
}
119+
}
120+
121+
private boolean shouldRegisterType(HostedType type) {
122+
if (registerAllTypes) {
123+
return true;
124+
}
125+
if (registerTrackedTypes && type.getWrapped().isTrackedAcrossLayers()) {
126+
return true;
127+
}
128+
return false;
129+
}
71130
}
72131

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

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

144-
if (imageLayer) {
203+
if (openHubUtils.shouldRegisterType(type)) {
145204
LayeredDispatchTableSupport.singleton().registerDeclaredDispatchInfo(type, table);
146205
}
147206

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

212-
if (imageLayer) {
271+
if (openHubUtils.shouldRegisterType(type)) {
213272
LayeredDispatchTableSupport.singleton().registerNonArrayDispatchTable(type, validTarget);
214273
}
215274
}
216275

217276
for (HostedType subType : type.subTypes) {
218-
if (subType instanceof HostedInstanceClass instanceClass && shouldIncludeType(subType)) {
277+
if (subType instanceof HostedInstanceClass instanceClass && openHubUtils.shouldIncludeType(subType)) {
219278
generateOpenTypeWorldDispatchTable(instanceClass, dispatchTablesMap, invalidDispatchTableEntryHandler);
220279
}
221280
}
@@ -229,7 +288,7 @@ private void buildOpenTypeWorldDispatchTables() {
229288
* Each interface has its own dispatch table. These can be directly determined via
230289
* looking at their declared methods.
231290
*/
232-
if (type.isInterface() && shouldIncludeType(type)) {
291+
if (type.isInterface() && openHubUtils.shouldIncludeType(type)) {
233292
dispatchTablesMap.put(type, generateITable(type));
234293
}
235294
}
@@ -240,25 +299,29 @@ private void buildOpenTypeWorldDispatchTables() {
240299
int[] emptyITableOffsets = new int[0];
241300
var objectType = hUniverse.getObjectClass();
242301
for (HostedType type : hUniverse.getTypes()) {
243-
if (type.isArray() && shouldIncludeType(type)) {
302+
if (type.isArray() && openHubUtils.shouldIncludeType(type)) {
244303
type.openTypeWorldDispatchTables = objectType.openTypeWorldDispatchTables;
245304
type.openTypeWorldDispatchTableSlotTargets = objectType.openTypeWorldDispatchTableSlotTargets;
246305
type.itableStartingOffsets = objectType.itableStartingOffsets;
247-
if (imageLayer) {
306+
if (openHubUtils.shouldRegisterType(type)) {
248307
LayeredDispatchTableSupport.singleton().registerArrayDispatchTable(type, objectType);
249308
}
250309
}
251310
if (type.openTypeWorldDispatchTables == null) {
252-
assert !needsDispatchTable(type) : type;
311+
assert !openHubUtils.shouldIncludeType(type) || hasEmptyDispatchTable(type) : type;
253312
type.openTypeWorldDispatchTables = HostedMethod.EMPTY_ARRAY;
254313
type.openTypeWorldDispatchTableSlotTargets = HostedMethod.EMPTY_ARRAY;
255314
type.itableStartingOffsets = emptyITableOffsets;
256315
}
257316
}
258317
}
259318

260-
public static boolean needsDispatchTable(HostedType type) {
261-
return shouldIncludeType(type) && !(type.isInterface() || type.isPrimitive() || type.isAbstract());
319+
public static boolean hasEmptyDispatchTable(HostedType type) {
320+
/*
321+
* Note that array types are by definition abstract, i.e., if type.isArray() is true then
322+
* type.isAbstract() is true.
323+
*/
324+
return (type.isInterface() || type.isPrimitive() || type.isAbstract()) && !type.isArray();
262325
}
263326

264327
private void buildClosedTypeWorldVTables() {

0 commit comments

Comments
 (0)