47
47
public final class VTableBuilder {
48
48
private final HostedUniverse hUniverse ;
49
49
private final HostedMetaAccess hMetaAccess ;
50
- private final boolean closedTypeWorldHubLayout ;
51
- private final boolean imageLayer = ImageLayerBuildingSupport . buildingImageLayer () ;
50
+
51
+ private final OpenTypeWorldHubLayoutUtils openHubUtils ;
52
52
53
53
private VTableBuilder (HostedUniverse hUniverse , HostedMetaAccess hMetaAccess ) {
54
54
this .hUniverse = hUniverse ;
55
55
this .hMetaAccess = hMetaAccess ;
56
- closedTypeWorldHubLayout = SubstrateOptions .useClosedTypeWorldHubLayout ();
56
+ openHubUtils = SubstrateOptions .useClosedTypeWorldHubLayout () ? null : new OpenTypeWorldHubLayoutUtils ( hUniverse );
57
57
}
58
58
59
59
public static void buildTables (HostedUniverse hUniverse , HostedMetaAccess hMetaAccess ) {
@@ -66,8 +66,67 @@ public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaA
66
66
}
67
67
}
68
68
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
+ }
71
130
}
72
131
73
132
private boolean verifyOpenTypeWorldDispatchTables () {
@@ -124,7 +183,7 @@ private List<HostedMethod> generateITable(HostedType type) {
124
183
125
184
private List <HostedMethod > generateDispatchTable (HostedType type , int startingIndex ) {
126
185
Predicate <HostedMethod > includeMethod ;
127
- if (closedTypeWorldHubLayout ) {
186
+ if (openHubUtils . filterVTableMethods ) {
128
187
// include only methods which will be indirect calls
129
188
includeMethod = m -> m .implementations .length > 1 || m .wrapped .isVirtualRootMethod ();
130
189
} else {
@@ -141,7 +200,7 @@ private List<HostedMethod> generateDispatchTable(HostedType type, int startingIn
141
200
index ++;
142
201
}
143
202
144
- if (imageLayer ) {
203
+ if (openHubUtils . shouldRegisterType ( type ) ) {
145
204
LayeredDispatchTableSupport .singleton ().registerDeclaredDispatchInfo (type , table );
146
205
}
147
206
@@ -209,13 +268,13 @@ private void generateOpenTypeWorldDispatchTable(HostedInstanceClass type, Map<Ho
209
268
type .openTypeWorldDispatchTables [i ] = targetMethod ;
210
269
}
211
270
212
- if (imageLayer ) {
271
+ if (openHubUtils . shouldRegisterType ( type ) ) {
213
272
LayeredDispatchTableSupport .singleton ().registerNonArrayDispatchTable (type , validTarget );
214
273
}
215
274
}
216
275
217
276
for (HostedType subType : type .subTypes ) {
218
- if (subType instanceof HostedInstanceClass instanceClass && shouldIncludeType (subType )) {
277
+ if (subType instanceof HostedInstanceClass instanceClass && openHubUtils . shouldIncludeType (subType )) {
219
278
generateOpenTypeWorldDispatchTable (instanceClass , dispatchTablesMap , invalidDispatchTableEntryHandler );
220
279
}
221
280
}
@@ -229,7 +288,7 @@ private void buildOpenTypeWorldDispatchTables() {
229
288
* Each interface has its own dispatch table. These can be directly determined via
230
289
* looking at their declared methods.
231
290
*/
232
- if (type .isInterface () && shouldIncludeType (type )) {
291
+ if (type .isInterface () && openHubUtils . shouldIncludeType (type )) {
233
292
dispatchTablesMap .put (type , generateITable (type ));
234
293
}
235
294
}
@@ -240,25 +299,29 @@ private void buildOpenTypeWorldDispatchTables() {
240
299
int [] emptyITableOffsets = new int [0 ];
241
300
var objectType = hUniverse .getObjectClass ();
242
301
for (HostedType type : hUniverse .getTypes ()) {
243
- if (type .isArray () && shouldIncludeType (type )) {
302
+ if (type .isArray () && openHubUtils . shouldIncludeType (type )) {
244
303
type .openTypeWorldDispatchTables = objectType .openTypeWorldDispatchTables ;
245
304
type .openTypeWorldDispatchTableSlotTargets = objectType .openTypeWorldDispatchTableSlotTargets ;
246
305
type .itableStartingOffsets = objectType .itableStartingOffsets ;
247
- if (imageLayer ) {
306
+ if (openHubUtils . shouldRegisterType ( type ) ) {
248
307
LayeredDispatchTableSupport .singleton ().registerArrayDispatchTable (type , objectType );
249
308
}
250
309
}
251
310
if (type .openTypeWorldDispatchTables == null ) {
252
- assert !needsDispatchTable (type ) : type ;
311
+ assert !openHubUtils . shouldIncludeType ( type ) || hasEmptyDispatchTable (type ) : type ;
253
312
type .openTypeWorldDispatchTables = HostedMethod .EMPTY_ARRAY ;
254
313
type .openTypeWorldDispatchTableSlotTargets = HostedMethod .EMPTY_ARRAY ;
255
314
type .itableStartingOffsets = emptyITableOffsets ;
256
315
}
257
316
}
258
317
}
259
318
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 ();
262
325
}
263
326
264
327
private void buildClosedTypeWorldVTables () {
0 commit comments